Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo passaggio dell'esercitazione illustra come usare gli strumenti delle funzioni con un agente, in cui l'agente è costruito su il servizio Completamento chat OpenAI di Azure.
Importante
Non tutti i tipi di agente supportano gli strumenti delle funzioni. Alcuni potrebbero supportare solo strumenti predefiniti personalizzati, senza consentire al chiamante di fornire le proprie funzioni. Questo passaggio usa un ChatClientAgent, che supporta gli strumenti funzionali.
Prerequisiti
Per i prerequisiti e l'installazione dei pacchetti NuGet, vedere il passaggio Creare ed eseguire un agente semplice in questa esercitazione.
Creare l'agente con gli strumenti per le funzioni
Gli strumenti delle funzioni sono solo codice personalizzato che si desidera che l'agente possa invocare quando necessario.
È possibile trasformare qualsiasi metodo C# in uno strumento funzione usando il AIFunctionFactory.Create metodo per creare un'istanza AIFunction dal metodo .
Se è necessario fornire descrizioni aggiuntive sulla funzione o sui relativi parametri per l'agente, in modo che possa scegliere in modo più accurato tra funzioni diverse, è possibile usare l'attributo System.ComponentModel.DescriptionAttribute nel metodo e i relativi parametri.
Ecco un esempio di uno strumento di funzione semplice che fa finta di ottenere il meteo per una determinata posizione. Viene decorato con attributi di descrizione per fornire descrizioni aggiuntive su se stesso e il relativo parametro di posizione per l'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.";
Quando crei l'agente, puoi ora fornire lo strumento di funzione passando un elenco di strumenti al metodo AsAIAgent.
using System;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI;
AIAgent agent = new AzureOpenAIClient(
new Uri("https://<myresource>.openai.azure.com"),
new DefaultAzureCredential())
.GetChatClient("gpt-4o-mini")
.AsAIAgent(instructions: "You are a helpful assistant", tools: [AIFunctionFactory.Create(GetWeather)]);
Avviso
DefaultAzureCredential è utile per lo sviluppo, ma richiede un'attenta considerazione nell'ambiente di produzione. Nell'ambiente di produzione prendere in considerazione l'uso di credenziali specifiche ,ad esempio ManagedIdentityCredential, per evitare problemi di latenza, probe di credenziali indesiderate e potenziali rischi per la sicurezza dai meccanismi di fallback.
Ora è possibile eseguire l'agente come di consueto e l'agente sarà in grado di chiamare la funzione dello strumento GetWeather quando necessario.
Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?"));
Suggerimento
Importante
Non tutti i tipi di agente supportano gli strumenti delle funzioni. Alcuni potrebbero supportare solo strumenti predefiniti personalizzati, senza consentire al chiamante di fornire le proprie funzioni. Questo passaggio usa gli agenti creati tramite client di chat, che supportano gli strumenti per le funzioni.
Prerequisiti
Per i prerequisiti e l'installazione dei pacchetti Python, vedere il passaggio Creare ed eseguire un agente semplice in questa esercitazione.
Creare l'agente con gli strumenti per le funzioni
Gli strumenti delle funzioni sono solo codice personalizzato che si desidera che l'agente possa invocare quando necessario.
È possibile trasformare qualsiasi funzione Python in uno strumento di funzione passandola al parametro dell'agente tools durante la creazione dell'agente.
Se è necessario fornire descrizioni aggiuntive sulla funzione o sui relativi parametri per l'agente, in modo che possa scegliere in modo più accurato tra funzioni diverse, è possibile usare le annotazioni dei tipi di Annotated Python con Field e Pydantic per fornire descrizioni.
Ecco un esempio di uno strumento di funzione semplice che fa finta di ottenere il meteo per una determinata posizione. Usa annotazioni di tipo per fornire descrizioni aggiuntive sulla funzione e il relativo parametro location all'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."
È anche possibile usare l'elemento @tool Decorator per specificare in modo esplicito il nome e la descrizione della funzione:
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."
Se non si specificano i parametri name e description nel decoratore @tool, il framework userà automaticamente il nome della funzione e la sua docstring come fallback.
Usare schemi espliciti con @tool
Quando è necessario il controllo completo sullo schema esposto al modello, passare il schema parametro a @tool.
È possibile fornire un modello Pydantic o un dizionario dello schema JSON non elaborato.
# 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.",
Passare il contesto di runtime a uno strumento
Usare i parametri di funzione normali per i valori che il modello deve fornire. Usare FunctionInvocationContext per valori di sola esecuzione, function_invocation_kwargs ad esempio o la sessione corrente. Il parametro di contesto inserito è nascosto dallo schema esposto al modello.
import asyncio
from typing import Annotated
from agent_framework import FunctionInvocationContext, tool
from agent_framework.openai import OpenAIResponsesClient
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 = OpenAIResponsesClient().as_agent(
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"},
)
Per ulteriori dettagli su ctx.kwargs, ctx.session e il middleware delle funzioni, vedere Runtime Context.
Creare strumenti solo dichiarativi
Se uno strumento viene implementato all'esterno del framework (ad esempio, lato client in un'interfaccia utente), è possibile dichiararlo senza un'implementazione usando FunctionTool(..., func=None).
Il modello può comunque ragionare e chiamare lo strumento e l'applicazione può fornire il risultato in un secondo momento.
# 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"},
Quando si crea l'agente, è ora possibile fornire lo strumento funzione all'agente passandolo al parametro tools.
import asyncio
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential
agent = AzureOpenAIChatClient(credential=AzureCliCredential()).as_agent(
instructions="You are a helpful assistant",
tools=get_weather
)
Ora è possibile eseguire l'agente come di consueto e l'agente sarà in grado di chiamare la funzione dello strumento get_weather quando necessario.
async def main():
result = await agent.run("What is the weather like in Amsterdam?")
print(result.text)
asyncio.run(main())
Creare una classe con più strumenti per le funzioni
Quando diversi strumenti condividono dipendenze o stato modificabile, incapsularli in una classe e passare i metodi legati all'agente. Usare gli attributi della classe per i valori che il modello non deve fornire, ad esempio client del servizio, flag di funzionalità o stato memorizzato nella cache.
import asyncio
from typing import Annotated
from agent_framework import tool
from agent_framework.openai import OpenAIResponsesClient
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 = OpenAIResponsesClient().as_agent(
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
response = await agent.run(query, tools=[add_function, tools.divide])
Questo modello è ideale per lo stato degli strumenti di lunga durata. Usare FunctionInvocationContext invece quando il valore cambia per ogni chiamata.