Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este paso del tutorial se muestra cómo usar herramientas funcionales con un agente, el cual se basa en el servicio de finalización de chat de Azure OpenAI.
Importante
No todos los tipos de agente admiten herramientas funcionales. Algunos solo pueden admitir herramientas integradas personalizadas, sin permitir que el autor de la llamada proporcione sus propias funciones. En este paso se usa un ChatClientAgent, que admite herramientas funcionales.
Prerrequisitos
Para conocer los requisitos previos e instalar paquetes NuGet, consulte el paso Creación y ejecución de un agente sencillo en este tutorial.
Crea el agente con herramientas funcionales
Las herramientas de funciones son solo código personalizado al que desea que el agente pueda llamar cuando sea necesario.
Puede convertir cualquier método de C# en una herramienta de función mediante el AIFunctionFactory.Create método para crear una AIFunction instancia del método .
Si necesita proporcionar descripciones adicionales sobre la función o sus parámetros para el agente, de modo que pueda elegir con mayor precisión entre distintas funciones, puede usar el System.ComponentModel.DescriptionAttribute atributo en el método y sus parámetros.
Este es un ejemplo de una herramienta de función simple que falsifica la obtención del tiempo para una ubicación determinada. Está decorado con atributos de descripción para proporcionar descripciones adicionales sobre sí mismo y su parámetro de ubicación al agente.
using System.ComponentModel;
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
Al crear el agente, ahora puede proporcionar una herramienta de función al agente pasando una lista de herramientas al método AsAIAgent.
using System;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
AIAgent agent = new AIProjectClient(
new Uri("<your-foundry-project-endpoint>"),
new DefaultAzureCredential())
.AsAIAgent(
model: "gpt-4o-mini",
instructions: "You are a helpful assistant",
tools: [AIFunctionFactory.Create(GetWeather)]);
Advertencia
DefaultAzureCredential es conveniente para el desarrollo, pero requiere una consideración cuidadosa en producción. En producción, considere usar una credencial específica (por ejemplo, ManagedIdentityCredential) para evitar problemas de latencia, sondeos de credenciales no deseados y posibles riesgos de seguridad de los mecanismos de respaldo.
Ahora solo puede ejecutar el agente como es normal y el agente podrá llamar a la GetWeather herramienta de función cuando sea necesario.
Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?"));
Sugerencia
Consulte los ejemplos de .NET para obtener ejemplos completos de ejecución.
Importante
No todos los tipos de agente admiten herramientas funcionales. Algunos solo pueden admitir herramientas integradas personalizadas, sin permitir que el autor de la llamada proporcione sus propias funciones. En este paso se usan agentes creados a través de clientes de chat, que admiten herramientas de funciones.
Prerrequisitos
Para conocer los requisitos previos e instalar paquetes de Python, consulte el paso Creación y ejecución de un agente sencillo en este tutorial.
Crea el agente con herramientas funcionales
Las herramientas de funciones son solo código personalizado al que desea que el agente pueda llamar cuando sea necesario.
Puede convertir cualquier función de Python en una herramienta de función pasándola al parámetro del tools agente al crear el agente.
Si necesita proporcionar descripciones adicionales sobre la función o sus parámetros para el agente, de modo que pueda elegir con mayor precisión entre distintas funciones, puede usar las anotaciones de tipo de Python con Annotated y Pydantic Field para proporcionar descripciones.
Este es un ejemplo de una herramienta de función simple que falsifica la obtención del tiempo para una ubicación determinada. Usa anotaciones de tipo para proporcionar descripciones adicionales sobre la función y su parámetro de ubicación para el agente.
from typing import Annotated
from pydantic import Field
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
return f"The weather in {location} is cloudy with a high of 15°C."
También puede usar el @tool decorador para especificar explícitamente el nombre y la descripción de la función:
from typing import Annotated
from pydantic import Field
from agent_framework import tool
@tool(name="weather_tool", description="Retrieves weather information for any location")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
return f"The weather in {location} is cloudy with a high of 15°C."
Si no especifica los name parámetros y description en el @tool decorador, el marco usará automáticamente el nombre de la función y docstring como reserva.
Uso de esquemas explícitos con @tool
Cuando necesite control total sobre el esquema expuesto al modelo, pase el schema parámetro a @tool.
Puede proporcionar un modelo de Pydantic o un diccionario de esquema JSON.
# Load environment variables from .env file
load_dotenv()
# Approach 1: Pydantic model as explicit schema
class WeatherInput(BaseModel):
"""Input schema for the weather tool."""
location: Annotated[str, Field(description="The city name to get weather for")]
unit: Annotated[str, Field(description="Temperature unit: celsius or fahrenheit")] = "celsius"
@tool(
name="get_weather",
description="Get the current weather for a given location.",
schema=WeatherInput,
approval_mode="never_require",
"""Get the current weather for a location."""
return f"The weather in {location} is 22 degrees {unit}."
# Approach 2: JSON schema dictionary as explicit schema
get_current_time_schema = {
"type": "object",
"properties": {
"timezone": {"type": "string", "description": "The timezone to get the current time for", "default": "UTC"},
},
}
@tool(
name="get_current_time",
description="Get the current time in a given timezone.",
Pasar el contexto exclusivo de tiempo de ejecución a una herramienta
Use parámetros de función normales para los valores que debe proporcionar el modelo. Use FunctionInvocationContext para valores de solo tiempo de ejecución, como function_invocation_kwargs o la sesión actual. El parámetro de contexto insertado está oculto del esquema expuesto al modelo.
import asyncio
from typing import Annotated
from agent_framework import Agent, FunctionInvocationContext, tool
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
from pydantic import Field
# Define the function tool with explicit invocation context.
# The context parameter can also be declared as an untyped ``ctx`` parameter.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
ctx: FunctionInvocationContext,
) -> str:
"""Get the weather for a given location."""
# Extract the injected argument from the explicit context
user_id = ctx.kwargs.get("user_id", "unknown")
# Simulate using the user_id for logging or personalization
print(f"Getting weather for user: {user_id}")
return f"The weather in {location} is cloudy with a high of 15°C."
async def main() -> None:
agent = Agent(
client=OpenAIChatClient(),
name="WeatherAgent",
instructions="You are a helpful weather assistant.",
tools=[get_weather],
)
# Pass the runtime context explicitly when running the agent.
response = await agent.run(
"What is the weather like in Amsterdam?",
function_invocation_kwargs={"user_id": "user_123"},
Para obtener más información sobre ctx.kwargs, ctx.session y el middleware de funciones, consulte Contexto en tiempo de ejecución.
Creación de herramientas de solo declaración
Si una herramienta se implementa fuera del marco (por ejemplo, el lado cliente en una interfaz de usuario), puede declararla sin una implementación mediante FunctionTool(..., func=None).
El modelo todavía puede razonar y llamar a la herramienta, y la aplicación puede proporcionar el resultado más adelante.
# Load environment variables from .env file
load_dotenv()
# A declaration-only tool: the schema is sent to the LLM, but the framework
# has no implementation to execute. The caller must supply the result.
get_user_location = FunctionTool(
name="get_user_location",
func=None,
description="Get the user's current city. Only the client application can resolve this.",
input_model={
"type": "object",
"properties": {
"reason": {"type": "string", "description": "Why the location is needed"},
Al crear el agente, ahora puede proporcionar la herramienta de función al agente, pasándolo al parámetro tools.
import asyncio
import os
from agent_framework.openai import OpenAIChatCompletionClient
from azure.identity import AzureCliCredential
agent = OpenAIChatCompletionClient(
model=os.environ["AZURE_OPENAI_CHAT_COMPLETION_MODEL"],
azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
credential=AzureCliCredential(),
).as_agent(
instructions="You are a helpful assistant",
tools=get_weather
)
Ahora solo puede ejecutar el agente como es normal y el agente podrá llamar a la get_weather herramienta de función cuando sea necesario.
async def main():
result = await agent.run("What is the weather like in Amsterdam?")
print(result.text)
asyncio.run(main())
Creación de una clase con varias herramientas de función
Cuando varias herramientas comparten dependencias o estado mutable, encapsularlas en una clase y pasar métodos enlazados al agente. Use atributos de clase para los valores que el modelo no debe proporcionar, como clientes de servicio, marcas de características o estado almacenado en caché.
import asyncio
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv
class MyFunctionClass:
def __init__(self, safe: bool = False) -> None:
"""Simple class with two tools: divide and add.
The safe parameter controls whether divide raises on division by zero or returns `infinity` for divide by zero.
"""
self.safe = safe
def divide(
self,
a: Annotated[int, "Numerator"],
b: Annotated[int, "Denominator"],
) -> str:
"""Divide two numbers, safe to use also with 0 as denominator."""
result = "∞" if b == 0 and self.safe else a / b
return f"{a} / {b} = {result}"
def add(
self,
x: Annotated[int, "First number"],
y: Annotated[int, "Second number"],
) -> str:
return f"{x} + {y} = {x + y}"
async def main():
# Creating my function class with safe division enabled
tools = MyFunctionClass(safe=True)
# Applying the tool decorator to one of the methods of the class
add_function = tool(description="Add two numbers.")(tools.add)
agent = Agent(
client=OpenAIChatClient(),
name="ToolAgent",
instructions="Use the provided tools.",
)
print("=" * 60)
print("Step 1: Call divide(10, 0) - tool returns infinity")
query = "Divide 10 by 0"
response = await agent.run(
query,
tools=[add_function, tools.divide],
)
print(f"Response: {response.text}")
print("=" * 60)
print("Step 2: Call set safe to False and call again")
# Disabling safe mode to allow exceptions
tools.safe = False
Este patrón es una buena opción para el estado de las herramientas de larga duración. Use FunctionInvocationContext en su lugar cuando cambie el valor por invocación.