Azure AI 에이전트는 함수 호출을 지원하므로 함수의 구조를 에이전트에 설명한 다음 해당 인수와 함께 호출해야 하는 함수를 반환할 수 있습니다.
비고
실행은 만든 후 10분 후에 만료됩니다. 만료되기 전에 도구 출력을 제출해야 합니다.
사용량 지원
Azure AI 파운드리 지원 | Python SDK | C# SDK | JavaScript SDK | REST API (REST 애플리케이션 프로그래밍 인터페이스) | 기본 에이전트 설정 | 표준 에이전트 설정 |
---|---|---|---|---|---|---|
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
에이전트가 호출할 함수 정의
먼저 에이전트가 호출할 함수를 정의합니다. 에이전트가 호출할 함수를 만들 때 문서 문자열에 필요한 매개 변수를 사용하여 해당 구조를 설명합니다.
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: The ___location to fetch weather for.
:return: Weather information as a JSON string.
"""
# Mock weather data for demonstration purposes
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.")
return json.dumps({"weather": weather})
# Define user functions
user_functions = {fetch_weather}
클라이언트 및 에이전트 만들기
비고
GitHub에서 스트리밍 예제를 찾을 수 있습니다.
import os, time
from azure.identity import DefaultAzureCredential
from azure.ai.projects import AIProjectClient
from azure.ai.agents.models import FunctionTool
# Retrieve the project endpoint from environment variables
project_endpoint = os.environ["PROJECT_ENDPOINT"]
# Initialize the AIProjectClient
project_client = AIProjectClient(
endpoint=project_endpoint,
credential=DefaultAzureCredential(),
api_version="latest",
)
# Initialize the FunctionTool with user-defined functions
functions = FunctionTool(functions=user_functions)
with project_client:
# Create an agent with custom functions
agent = project_client.agents.create_agent(
model=os.environ["MODEL_DEPLOYMENT_NAME"],
name="my-agent",
instructions="You are a helpful agent",
tools=functions.definitions,
)
print(f"Created agent, ID: {agent.id}")
스레드 만들기
# Create a thread for communication
thread = project_client.agents.threads.create()
print(f"Created thread, ID: {thread.id}")
# Send a message to the thread
message = project_client.agents.messages.create(
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']}")
실행을 만들고 출력을 확인합니다.
# Create and process a run for the agent to handle the message
run = project_client.agents.runs.create(thread_id=thread.id, agent_id=agent.id)
print(f"Created run, ID: {run.id}")
# Poll the run status until it is completed or requires action
while run.status in ["queued", "in_progress", "requires_action"]:
time.sleep(1)
run = project_client.agents.runs.get(thread_id=thread.id, run_id=run.id)
if run.status == "requires_action":
tool_calls = run.required_action.submit_tool_outputs.tool_calls
tool_outputs = []
for tool_call in tool_calls:
if tool_call.name == "fetch_weather":
output = fetch_weather("New York")
tool_outputs.append({"tool_call_id": tool_call.id, "output": output})
project_client.agents.runs.submit_tool_outputs(thread_id=thread.id, run_id=run.id, tool_outputs=tool_outputs)
print(f"Run completed with status: {run.status}")
# Fetch and log all messages from the thread
messages = project_client.agents.messages.list(thread_id=thread.id)
for message in messages:
print(f"Role: {message['role']}, Content: {message['content']}")
# Delete the agent after use
project_client.agents.delete_agent(agent.id)
print("Deleted agent")
비고
GitHub에서 스트리밍 예제를 찾을 수 있습니다.
클라이언트 구성 및 함수 정의
먼저 appsettings.json
를 사용하여 구성을 설정하고 PersistentAgentsClient
을(를) 만듭니다.
using Azure;
using Azure.AI.Agents.Persistent;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using System.Text.Json;
// Load configuration from appsettings.json file
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();
// Read necessary configuration values (Project Endpoint and Model Deployment Name)
var projectEndpoint = configuration["ProjectEndpoint"];
var modelDeploymentName = configuration["ModelDeploymentName"];
// Initialize the client to interact with the Azure AI Agents Persistent Client using default credentials
PersistentAgentsClient client = new(projectEndpoint, new DefaultAzureCredential());
함수 정의
에이전트가 호출할 수 있는 로컬 C# 함수와 FunctionToolDefinition
해당 용도 및 에이전트에 대한 매개 변수를 설명하는 함수를 정의합니다.
// Function to get the user's favorite city (hardcoded for example)
string GetUserFavoriteCity() => "Seattle, WA";
// Definition for the GetUserFavoriteCity function, describing its purpose to the agent
FunctionToolDefinition getUserFavoriteCityTool = new("getUserFavoriteCity", "Gets the user's favorite city.");
// Function to get a city's nickname based on its ___location
string GetCityNickname(string ___location) => ___location switch
{
"Seattle, WA" => "The Emerald City",
// Handle cases where the nickname is not known
_ => throw new NotImplementedException(),
};
// Definition for the GetCityNickname function, including parameter description
FunctionToolDefinition getCityNicknameTool = new(
name: "getCityNickname",
description: "Gets the nickname of a city, e.g. 'LA' for 'Los Angeles, CA'.",
// Define the expected parameters (___location string)
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 }));
// Function to get weather at a specific ___location, with an optional temperature unit
string GetWeatherAtLocation(string ___location, string temperatureUnit = "f") => ___location switch
{
"Seattle, WA" => temperatureUnit == "f" ? "70f" : "21c",
// Handle cases where weather data is not available
_ => throw new NotImplementedException()
};
// Definition for the GetWeatherAtLocation function, specifying parameters and enum for unit
FunctionToolDefinition getCurrentWeatherAtLocationTool = new(
name: "getCurrentWeatherAtLocation",
description: "Gets the current weather at a provided ___location.",
// Define expected parameters (___location string, optional unit enum)
parameters: BinaryData.FromObjectAsJson(
new
{
Type = "object",
Properties = new
{
Location = new
{
Type = "string",
Description = "The city and state, e.g. San Francisco, CA",
},
Unit = new
{
Type = "string",
Enum = new[] { "c", "f" },
},
},
Required = new[] { "___location" },
},
new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }));
함수 실행 논리 구현
도우미 함수 GetResolvedToolOutput
을(를) 만들어 에이전트에서 RequiredToolCall
개체를 처리합니다. 이 함수는 적절한 C# 로컬 함수를 호출하고 해당 출력을 에이전트에 반환합니다.
// Helper function to execute the correct local C# function based on the tool call request from the agent
ToolOutput GetResolvedToolOutput(RequiredToolCall toolCall)
{
// Check if the required call is a function call
if (toolCall is RequiredFunctionToolCall functionToolCall)
{
// Execute GetUserFavoriteCity if its name matches
if (functionToolCall.Name == getUserFavoriteCityTool.Name)
{
return new ToolOutput(toolCall, GetUserFavoriteCity());
}
// Parse the arguments provided by the agent for other functions
using JsonDocument argumentsJson = JsonDocument.Parse(functionToolCall.Arguments);
// Execute GetCityNickname if its name matches
if (functionToolCall.Name == getCityNicknameTool.Name)
{
// Extract the '___location' argument
string locationArgument = argumentsJson.RootElement.GetProperty("___location").GetString();
return new ToolOutput(toolCall, GetCityNickname(locationArgument));
}
// Execute GetWeatherAtLocation if its name matches
if (functionToolCall.Name == getCurrentWeatherAtLocationTool.Name)
{
// Extract the '___location' argument
string locationArgument = argumentsJson.RootElement.GetProperty("___location").GetString();
// Check if the optional 'unit' argument was provided
if (argumentsJson.RootElement.TryGetProperty("unit", out JsonElement unitElement))
{
string unitArgument = unitElement.GetString();
return new ToolOutput(toolCall, GetWeatherAtLocation(locationArgument, unitArgument));
}
// Call without the unit if it wasn't provided
return new ToolOutput(toolCall, GetWeatherAtLocation(locationArgument));
}
}
// Return null if the tool call type isn't handled
return null;
}
에이전트 및 대화 스레드 만들기
이제 PersistentAgent
을/를 생성하여, 모델 배포 이름, 설명이 포함된 이름, 동작에 대한 지침, 그리고 사용할 수 있는 FunctionToolDefinitions
목록을 제공합니다. 그런 다음, PersistentAgentThread
을(를) 생성하고 초기 사용자 메시지를 추가하여 대화를 시작합니다.
// Create the agent instance
PersistentAgent agent = client.Administration.CreateAgent(
model: modelDeploymentName,
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: [getUserFavoriteCityTool, getCityNicknameTool, getCurrentWeatherAtLocationTool]);
// Create a new conversation thread for the agent
PersistentAgentThread thread = client.Threads.CreateThread();
// Add the initial user message to the thread
client.Messages.CreateMessage(
thread.Id,
MessageRole.User,
"What's the weather like in my favorite city?");
프로세스 실행 및 함수 호출 처리
스레드에서 에이전트를 위한 ThreadRun
를 만듭니다. 실행의 완료 상태를 폴링합니다. 실행 상태가 RequiresAction
이면, 이것은 에이전트가 귀하의 로컬 함수 중 하나를 호출해야 함을 의미합니다. 함수 도우미 GetResolvedToolOutput
를 사용하여 결과를 얻고 다시 실행 흐름에 전달합니다.
// Start a run for the agent to process the messages in the thread
ThreadRun run = client.Runs.CreateRun(thread.Id, agent.Id);
// Loop to check the run status and handle required actions
do
{
// Wait briefly before checking the status again
Thread.Sleep(TimeSpan.FromMilliseconds(500));
// Get the latest status of the run
run = client.Runs.GetRun(thread.Id, run.Id);
// Check if the agent requires a function call to proceed
if (run.Status == RunStatus.RequiresAction
&& run.RequiredAction is SubmitToolOutputsAction submitToolOutputsAction)
{
// Prepare a list to hold the outputs of the tool calls
List<ToolOutput> toolOutputs = [];
// Iterate through each required tool call
foreach (RequiredToolCall toolCall in submitToolOutputsAction.ToolCalls)
{
// Execute the function and get the output using the helper method
toolOutputs.Add(GetResolvedToolOutput(toolCall));
}
// Submit the collected tool outputs back to the run
run = client.Runs.SubmitToolOutputsToRun(run, toolOutputs);
}
}
// Continue looping while the run is in progress or requires action
while (run.Status == RunStatus.Queued
|| run.Status == RunStatus.InProgress
|| run.Status == RunStatus.RequiresAction);
결과 검색 및 표시
실행이 완료되면 스레드에서 모든 메시지를 검색하여 에이전트의 최종 응답을 포함하여 전체 대화를 확인합니다.
// Retrieve all messages from the completed thread, oldest first
Pageable<PersistentThreadMessage> messages = client.Messages.GetMessages(
threadId: thread.Id,
order: ListSortOrder.Ascending
);
// Iterate through each message in the thread
foreach (PersistentThreadMessage threadMessage in messages)
{
// Iterate through content items in the message (usually just one text item)
foreach (MessageContent content in threadMessage.ContentItems)
{
// Process based on content type
switch (content)
{
// If it's a text message
case MessageTextContent textItem:
// Print the role (user/agent) and the text content
Console.WriteLine($"[{threadMessage.Role}]: {textItem.Text}");
break;
// Add handling for other content types if necessary (e.g., images)
}
}
}
자원을 정리하세요
마지막으로 스레드와 에이전트를 삭제하여 만든 리소스를 정리합니다.
// Delete the conversation thread
client.Threads.DeleteThread(threadId: thread.Id);
// Delete the agent definition
client.Administration.DeleteAgent(agentId: agent.Id);
에이전트가 호출할 함수 정의
먼저 에이전트가 호출할 함수를 정의합니다. 에이전트가 호출할 함수를 만들 때 docstring에 필요한 매개 변수를 사용하여 해당 함수의 구조를 설명합니다.
class FunctionToolExecutor {
functionTools;
constructor() {
this.functionTools = [
{
func: this.getUserFavoriteCity,
...ToolUtility.createFunctionTool({
name: "getUserFavoriteCity",
description: "Gets the user's favorite city.",
parameters: {},
}),
},
{
func: this.getCityNickname,
...ToolUtility.createFunctionTool({
name: "getCityNickname",
description: "Gets the nickname of a city, e.g. 'LA' for 'Los Angeles, CA'.",
parameters: {
type: "object",
properties: {
___location: { type: "string", description: "The city and state, e.g. Seattle, Wa" },
},
},
}),
},
{
func: this.getWeather,
...ToolUtility.createFunctionTool({
name: "getWeather",
description: "Gets the weather for a ___location.",
parameters: {
type: "object",
properties: {
___location: { type: "string", description: "The city and state, e.g. Seattle, Wa" },
unit: { type: "string", enum: ["c", "f"] },
},
},
}),
},
];
}
getUserFavoriteCity() {
return { ___location: "Seattle, WA" };
}
getCityNickname(_location) {
return { nickname: "The Emerald City" };
}
getWeather(_location, unit) {
return { weather: unit === "f" ? "72f" : "22c" };
}
invokeTool(toolCall) {
console.log(`Function tool call - ${toolCall.function.name}`);
const args = [];
if (toolCall.function.parameters) {
try {
const params = JSON.parse(toolCall.function.parameters);
for (const key in params) {
if (Object.prototype.hasOwnProperty.call(params, key)) {
args.push(params[key]);
}
}
} catch (error) {
console.error(`Failed to parse parameters: ${toolCall.function.parameters}`, error);
return undefined;
}
}
const result = this.functionTools
.find((tool) => tool.definition.function.name === toolCall.function.name)
?.func(...args);
return result
? {
toolCallId: toolCall.id,
output: JSON.stringify(result),
}
: undefined;
}
getFunctionDefinitions() {
return this.functionTools.map((tool) => {
return tool.definition;
});
}
}
클라이언트 및 에이전트 만들기
const { AgentsClient, ToolUtility, isOutputOfType } = require("@azure/ai-agents");
const { delay } = require("@azure/core-util");
const { DefaultAzureCredential } = require("@azure/identity");
require("dotenv/config");
const projectEndpoint = process.env["PROJECT_ENDPOINT"];
const client = new AgentsClient(projectEndpoint, new DefaultAzureCredential());
const functionToolExecutor = new FunctionToolExecutor();
const functionTools = functionToolExecutor.getFunctionDefinitions();
const agent = await client.createAgent("gpt-4o", {
name: "my-agent",
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: functionTools,
});
console.log(`Created agent, agent ID: ${agent.id}`);
스레드 만들기
// Create thread
const thread = await client.threads.create();
console.log(`Created Thread, thread ID: ${thread.id}`);
// Create message
const message = await client.messages.create(
thread.id,
"user",
"What's the weather like in my favorite city?",
);
console.log(`Created message, message ID ${message.id}`);
실행을 만들고 출력을 확인합니다.
// Create run
let run = await client.runs.create(thread.id, agent.id);
console.log(`Created Run, Run ID: ${run.id}`);
while (["queued", "in_progress", "requires_action"].includes(run.status)) {
await delay(1000);
run = await client.runs.get(thread.id, run.id);
console.log(`Current Run status - ${run.status}, run ID: ${run.id}`);
if (run.status === "requires_action" && run.requiredAction) {
console.log(`Run requires action - ${run.requiredAction}`);
if (isOutputOfType(run.requiredAction, "submit_tool_outputs")) {
const submitToolOutputsActionOutput = run.requiredAction;
const toolCalls = submitToolOutputsActionOutput.submitToolOutputs.toolCalls;
const toolResponses = [];
for (const toolCall of toolCalls) {
if (isOutputOfType(toolCall, "function")) {
const toolResponse = functionToolExecutor.invokeTool(toolCall);
if (toolResponse) {
toolResponses.push(toolResponse);
}
}
}
if (toolResponses.length > 0) {
run = await client.runs.submitToolOutputs(thread.id, run.id, toolResponses);
console.log(`Submitted tool response - ${run.status}`);
}
}
}
}
console.log(`Run status - ${run.status}, run ID: ${run.id}`);
const messages = client.messages.list(thread.id);
for await (const threadMessage of messages) {
console.log(
`Thread Message Created at - ${threadMessage.createdAt} - Role - ${threadMessage.role}`,
);
threadMessage.content.forEach((content) => {
if (isOutputOfType(content, "text")) {
const textContent = content;
console.log(`Text Message Content - ${textContent.text.value}`);
} else if (isOutputOfType(content, "image_file")) {
const imageContent = content;
console.log(`Image Message Content - ${imageContent.imageFile.fileId}`);
}
});
}
// Delete agent
await client.deleteAgent(agent.id);
console.log(`Deleted agent, agent ID: ${agent.id}`);
에이전트가 호출할 함수 정의
먼저 에이전트가 호출할 함수를 정의합니다. 에이전트가 호출할 함수를 만들 때 docstring에 필요한 매개 변수를 사용하여 해당 함수의 구조를 설명합니다. 예제 함수는 다른 SDK 언어를 참조하세요.
에이전트 만들기
REST API 빠른 시작을 따라 환경 변수 AGENT_TOKEN
, AZURE_AI_FOUNDRY_PROJECT_ENDPOINT
, API_VERSION
에 올바른 값을 설정하십시오.
curl --request POST \
--url $AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/assistants?api-version=$API_VERSION \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"instructions": "You are a weather bot. Use the provided functions to answer questions.",
"model": "gpt-4o-mini",
tools=[{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the weather in ___location",
"parameters": {
"type": "object",
"properties": {
"___location": {"type": "string", "description": "The city name, for example San Francisco"}
},
"required": ["___location"]
}
}
}]
}'
스레드 만들기
curl --request POST \
--url $AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/threads?api-version=$API_VERSION \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d ''
스레드에 사용자 질문 추가
curl --request POST \
--url $AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/threads/thread_abc123/messages?api-version=$API_VERSION \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"role": "user",
"content": "What is the weather in Seattle?"
}'
스레드 실행
curl --request POST \
--url $AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/threads/thread_abc123/runs?api-version=$API_VERSION \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"assistant_id": "asst_abc123",
}'
실행 상태 검색
curl --request GET \
--url $AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/threads/thread_abc123/runs/run_abc123?api-version=$API_VERSION \
-H "Authorization: Bearer $AGENT_TOKEN"
에이전트 응답 검색
curl --request GET \
--url $AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/threads/thread_abc123/messages?api-version=$API_VERSION \
-H "Authorization: Bearer $AGENT_TOKEN"