Wywoływanie funkcji agentów sztucznej inteligencji platformy Azure
Artykuł
Agenci usługi Azure AI obsługują wywoływanie funkcji, co pozwala opisać strukturę funkcji asystenta, a następnie zwrócić funkcje, które muszą być wywoływane wraz z ich argumentami.
Uwaga
Przebiegi wygasają dziesięć minut po utworzeniu. Pamiętaj, aby przesłać dane wyjściowe narzędzia przed wygaśnięciem.
Definiowanie funkcji, która ma być wywoływana przez agenta
Zacznij od zdefiniowania funkcji, która ma być wywoływana przez agenta. Podczas tworzenia funkcji, która ma zostać wywołana przez agenta, należy opisać jego strukturę z dowolnymi wymaganymi parametrami w spisie treści. Uwzględnij wszystkie definicje funkcji w jednym pliku, user_functions.py który można następnie zaimportować do głównego skryptu.
import json
import datetime
from typing import Any, Callable, Set, Dict, List, Optional
def fetch_weather(location: str) -> str:
"""
Fetches the weather information for the specified location.
:param location (str): The location to fetch weather for.
:return: Weather information as a JSON string.
:rtype: str
"""
# In a real-world scenario, you'd integrate with a weather API.
# Here, we'll mock the response.
mock_weather_data = {"New York": "Sunny, 25°C", "London": "Cloudy, 18°C", "Tokyo": "Rainy, 22°C"}
weather = mock_weather_data.get(location, "Weather data not available for this location.")
weather_json = json.dumps({"weather": weather})
return weather_json
# Statically defined user functions for fast reference
user_functions: Set[Callable[..., Any]] = {
fetch_weather,
}
Zobacz plik python w witrynie GitHub , aby zapoznać się z przykładem pełnej serii definicji funkcji. Ten plik jest określany jako user_functions.py w poniższym przykładzie.
// Example of a function that defines no parameters
string GetUserFavoriteCity() => "Seattle, WA";
FunctionToolDefinition getUserFavoriteCityTool = new("getUserFavoriteCity", "Gets the user's favorite city.");
// Example of a function with a single required parameter
string GetCityNickname(string location) => location switch
{
"Seattle, WA" => "The Emerald City",
_ => throw new NotImplementedException(),
};
FunctionToolDefinition getCityNicknameTool = new(
name: "getCityNickname",
description: "Gets the nickname of a city, e.g. 'LA' for 'Los Angeles, CA'.",
parameters: BinaryData.FromObjectAsJson(
new
{
Type = "object",
Properties = new
{
Location = new
{
Type = "string",
Description = "The city and state, e.g. San Francisco, CA",
},
},
Required = new[] { "location" },
},
new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }));
W poniższym przykładzie utworzymy funkcję pomocnika, aby pobrać i przeanalizować dane wyjściowe rozpoznanych narzędzi i zwrócić je.
ToolOutput GetResolvedToolOutput(RequiredToolCall toolCall)
{
if (toolCall is RequiredFunctionToolCall functionToolCall)
{
if (functionToolCall.Name == getUserFavoriteCityTool.Name)
{
return new ToolOutput(toolCall, GetUserFavoriteCity());
}
using JsonDocument argumentsJson = JsonDocument.Parse(functionToolCall.Arguments);
if (functionToolCall.Name == getCityNicknameTool.Name)
{
string locationArgument = argumentsJson.RootElement.GetProperty("location").GetString();
return new ToolOutput(toolCall, GetCityNickname(locationArgument));
}
}
return null;
}
W poniższym przykładzie utworzymy klienta i zdefiniujmy element toolset , który będzie używany do przetwarzania funkcji zdefiniowanych w programie user_functions.
toolset: W przypadku korzystania z parametru zestawu narzędzi udostępniasz nie tylko definicje funkcji i opisy, ale także ich implementacje. Zestaw SDK wykona te funkcje w ramach create_and_run_process lub przesyłania strumieniowego. Te funkcje będą wywoływane na podstawie ich definicji.
import os
from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential
from azure.ai.projects.models import FunctionTool, ToolSet
from user_functions import user_functions # user functions which can be found in a user_functions.py file.
# Create an Azure AI Client from a connection string, copied from your Azure AI Foundry project.
# It should be in the format "<HostName>;<AzureSubscriptionId>;<ResourceGroup>;<HubName>"
# Customers need to login to Azure subscription via Azure CLI and set the environment variables
project_client = AIProjectClient.from_connection_string(
credential=DefaultAzureCredential(),
conn_str=os.environ["PROJECT_CONNECTION_STRING"],
)
# Initialize agent toolset with user functions
functions = FunctionTool(user_functions)
toolset = ToolSet()
toolset.add(functions)
// note: parallel function calling is only supported with newer models like gpt-4-1106-preview
Response<Agent> agentResponse = await client.CreateAgentAsync(
model: "gpt-4-1106-preview",
name: "SDK Test Agent - Functions",
instructions: "You are a weather bot. Use the provided functions to help answer questions. "
+ "Customize your responses to the user's preferences as much as possible and use friendly "
+ "nicknames for cities whenever possible.",
tools: new List<ToolDefinition> { getUserFavoriteCityTool, getCityNicknameTool, getCurrentWeatherAtLocationTool }
);
Agent agent = agentResponse.Value;
# Create agent with toolset and process a run
agent = project_client.agents.create_agent(
model="gpt-4o-mini", name="my-agent", instructions="You are a helpful agent", toolset=toolset
)
print(f"Created agent, ID: {agent.id}")
// note: parallel function calling is only supported with newer models like gpt-4-1106-preview
Response<Agent> agentResponse = await client.CreateAgentAsync(
model: "gpt-4o-mini",
name: "SDK Test Agent - Functions",
instructions: "You are a weather bot. Use the provided functions to help answer questions. "
+ "Customize your responses to the user's preferences as much as possible and use friendly "
+ "nicknames for cities whenever possible.",
tools: new List<ToolDefinition> { getUserFavoriteCityTool, getCityNicknameTool, getCurrentWeatherAtLocationTool }
);
Agent agent = agentResponse.Value;
# Create thread for communication
thread = project_client.agents.create_thread()
print(f"Created thread, ID: {thread.id}")
# Create message to thread
message = project_client.agents.create_message(
thread_id=thread.id,
role="user",
content="Hello, send an email with the datetime and weather information in New York?",
)
print(f"Created message, ID: {message.id}")
Response<AgentThread> threadResponse = await client.CreateThreadAsync();
AgentThread thread = threadResponse.Value;
Response<ThreadMessage> messageResponse = await client.CreateMessageAsync(
thread.Id,
MessageRole.User,
"What's the weather like in my favorite city?");
ThreadMessage message = messageResponse.Value;
Tworzenie przebiegu i sprawdzanie danych wyjściowych
# Create and process agent run in thread with tools
run = project_client.agents.create_and_process_run(thread_id=thread.id, assistant_id=agent.id)
print(f"Run finished with status: {run.status}")
if run.status == "failed":
print(f"Run failed: {run.last_error}")
# Delete the agent when done
project_client.agents.delete_agent(agent.id)
print("Deleted agent")
# Fetch and log all messages
messages = project_client.agents.list_messages(thread_id=thread.id)
print(f"Messages: {messages}")
Response<ThreadRun> runResponse = await client.CreateRunAsync(thread, agent);
#region Snippet:FunctionsHandlePollingWithRequiredAction
do
{
await Task.Delay(TimeSpan.FromMilliseconds(500));
runResponse = await client.GetRunAsync(thread.Id, runResponse.Value.Id);
if (runResponse.Value.Status == RunStatus.RequiresAction
&& runResponse.Value.RequiredAction is SubmitToolOutputsAction submitToolOutputsAction)
{
List<ToolOutput> toolOutputs = new();
foreach (RequiredToolCall toolCall in submitToolOutputsAction.ToolCalls)
{
toolOutputs.Add(GetResolvedToolOutput(toolCall));
}
runResponse = await client.SubmitToolOutputsToRunAsync(runResponse.Value, toolOutputs);
}
}
while (runResponse.Value.Status == RunStatus.Queued
|| runResponse.Value.Status == RunStatus.InProgress);
#endregion
Response<PageableList<ThreadMessage>> afterRunMessagesResponse
= await client.GetMessagesAsync(thread.Id);
IReadOnlyList<ThreadMessage> messages = afterRunMessagesResponse.Value.Data;
// Note: messages iterate from newest to oldest, with the messages[0] being the most recent
foreach (ThreadMessage threadMessage in messages)
{
Console.Write($"{threadMessage.CreatedAt:yyyy-MM-dd HH:mm:ss} - {threadMessage.Role,10}: ");
foreach (MessageContent contentItem in threadMessage.ContentItems)
{
if (contentItem is MessageTextContent textItem)
{
Console.Write(textItem.Text);
}
else if (contentItem is MessageImageFileContent imageFileItem)
{
Console.Write($"<image from ID: {imageFileItem.FileId}");
}
Console.WriteLine();
}
}