백 엔드 도구는 일반 MAF 도구 파이프라인을 사용합니다. AG-UI 클라이언트가 호출 및 결과를 관찰할 수 있도록 전송 이벤트를 추가합니다. 별도의 도구 추상화는 도입되지 않습니다.
백 엔드 도구 추가
MAF 에이전트와 마찬가지로 도구를 정의하고 등록합니다.
using System.ComponentModel;
using Microsoft.Extensions.AI;
[Description("Get the weather for a location.")]
static string GetWeather(
[Description("The city to look up.")] string location) =>
$"The weather in {location} is sunny.";
AITool getWeather = AIFunctionFactory.Create(GetWeather, name: "get_weather");
AIAgent agent = chatClient.AsAIAgent(tools: [getWeather]);
app.MapAGUIServer("/", agent);
복잡한 요청 또는 응답 유형의 경우 ASP.NET Core 및 JsonSerializerOptions에 대해 동일한 AIFunctionFactory.Create를 구성합니다.
Tip
전체 구현은 .NET 백 엔드 도구 샘플을 참조하세요.
도구 스키마, 종속성 주입, 오류 처리 및 일반 도구 디자인은 에이전트와 함께 함수 도구 사용을 참조하세요.
AG-UI 이벤트 매핑
에이전트가 도구를 호출하는 경우:
-
FunctionCallContent은 AG-UITOOL_CALL_STARTTOOL_CALL_ARGS및TOOL_CALL_END이벤트로 내보내집니다. -
FunctionResultContent는TOOL_CALL_RESULT이벤트로 발생합니다. - 텍스트 및 기타 에이전트 콘텐츠는 정상적으로 계속 스트리밍됩니다.
.NET 클라이언트는 번역된 콘텐츠를 다음과 같이 FunctionCallContentFunctionResultContent받습니다.
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(messages, session))
{
foreach (AIContent content in update.Contents)
{
if (content is FunctionCallContent call)
{
Console.WriteLine($"Calling {call.Name}");
}
else if (content is FunctionResultContent result)
{
Console.WriteLine($"Result: {result.Result}");
}
}
}
도구 결과는 AG-UI 클라이언트에도 노출되는 모델 관련 값입니다. 도구 결과 외에도 공유 UI 상태를 내보내려면 상태 관리에 설명된 명시적 매핑을 사용합니다.
다음 단계
이 자습서에서는 AG-UI 에이전트에 함수 도구를 추가하는 방법을 보여 줍니다. 함수 도구는 에이전트가 데이터 검색, 계산 수행 또는 외부 시스템과의 상호 작용과 같은 특정 작업을 수행하기 위해 호출할 수 있는 사용자 지정 Python 함수입니다. AG-UI를 사용하면 이러한 도구가 백 엔드에서 실행되고 결과가 클라이언트로 자동으로 스트리밍됩니다.
사전 요구 사항
시작하기 전에 시작 자습서를 완료하고 다음을 수행했는지 확인합니다.
- Python 3.10 이상
-
agent-framework-ag-ui설치 - 구성된 Azure OpenAI 서비스
- AG-UI 서버 및 클라이언트 설정에 대한 기본 이해
비고
이러한 샘플은 인증에 사용합니다 DefaultAzureCredential . Azure(예: 통해 az login)로 인증되었는지 확인합니다. 자세한 내용은 Azure ID 설명서를 참조하세요.
백 엔드 도구 렌더링이란?
백 엔드 도구 렌더링은 다음을 의미합니다.
- 함수 도구는 서버에 정의됩니다.
- AI 에이전트는 이러한 도구를 호출할 시기를 결정합니다.
- 백 엔드에서 실행되는 도구(서버 쪽)
- 도구 호출 이벤트 및 결과가 실시간으로 클라이언트로 스트리밍됩니다.
- 클라이언트가 도구 실행 진행률에 대한 업데이트를 받습니다.
이 방법은 다음을 제공합니다.
- 보안: 중요한 작업이 서버에 유지됩니다.
- 일관성: 모든 클라이언트는 동일한 도구 구현을 사용합니다.
- 투명도: 클라이언트에서 도구 실행 진행률을 표시할 수 있습니다.
- 유연성: 클라이언트 코드를 변경하지 않고 도구 업데이트
함수 도구 만들기
기본 함수 도구
데코레이터를 사용하여 Python 함수를 도구로 전환할 @tool 수 있습니다.
from typing import Annotated
from pydantic import Field
from agent_framework import tool
@tool
def get_weather(
location: Annotated[str, Field(description="The city")],
) -> str:
"""Get the current weather for a location."""
# In a real application, you would call a weather API
return f"The weather in {location} is sunny with a temperature of 22°C."
주요 개념
-
@tool데코레이터: 에이전트에서 사용할 수 있는 함수를 표시합니다. - 형식 주석: 매개 변수에 대한 형식 정보 제공
-
Annotated및Field: 에이전트가 매개 변수를 이해하는 데 도움이 되는 설명 추가 - Docstring: 함수가 수행하는 작업을 설명합니다(에이전트가 함수를 사용할 시기를 결정하는 데 도움이 됨).
- 반환 값: 에이전트에 반환된 결과(및 클라이언트로 스트리밍됨)
다중 함수 도구
여러 도구를 제공하여 에이전트에 더 많은 기능을 제공할 수 있습니다.
from typing import Any
from agent_framework import tool
@tool
def get_weather(
location: Annotated[str, Field(description="The city.")],
) -> str:
"""Get the current weather for a location."""
return f"The weather in {location} is sunny with a temperature of 22°C."
@tool
def get_forecast(
location: Annotated[str, Field(description="The city.")],
days: Annotated[int, Field(description="Number of days to forecast")] = 3,
) -> dict[str, Any]:
"""Get the weather forecast for a location."""
return {
"location": location,
"days": days,
"forecast": [
{"day": 1, "weather": "Sunny", "high": 24, "low": 18},
{"day": 2, "weather": "Partly cloudy", "high": 22, "low": 17},
{"day": 3, "weather": "Rainy", "high": 19, "low": 15},
],
}
함수 도구를 사용하여 AG-UI 서버 만들기
함수 도구를 사용하는 전체 서버 구현은 다음과 같습니다.
"""AG-UI server with backend tool rendering."""
import os
from typing import Annotated, Any
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatCompletionClient
from agent_framework_ag_ui import add_agent_framework_fastapi_endpoint
from azure.identity import AzureCliCredential
from fastapi import FastAPI
from pydantic import Field
# Define function tools
@tool
def get_weather(
location: Annotated[str, Field(description="The city")],
) -> str:
"""Get the current weather for a location."""
# Simulated weather data
return f"The weather in {location} is sunny with a temperature of 22°C."
@tool
def search_restaurants(
location: Annotated[str, Field(description="The city to search in")],
cuisine: Annotated[str, Field(description="Type of cuisine")] = "any",
) -> dict[str, Any]:
"""Search for restaurants in a location."""
# Simulated restaurant data
return {
"location": location,
"cuisine": cuisine,
"results": [
{"name": "The Golden Fork", "rating": 4.5, "price": "$$"},
{"name": "Bella Italia", "rating": 4.2, "price": "$$$"},
{"name": "Spice Garden", "rating": 4.7, "price": "$$"},
],
}
# Read required configuration
endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT")
deployment_name = os.environ.get("AZURE_OPENAI_CHAT_COMPLETION_MODEL")
if not endpoint:
raise ValueError("AZURE_OPENAI_ENDPOINT environment variable is required")
if not deployment_name:
raise ValueError("AZURE_OPENAI_CHAT_COMPLETION_MODEL environment variable is required")
chat_client = OpenAIChatCompletionClient(
model=deployment_name,
azure_endpoint=endpoint,
api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
credential=AzureCliCredential(),
)
# Create agent with tools
agent = Agent(
name="TravelAssistant",
instructions="You are a helpful travel assistant. Use the available tools to help users plan their trips.",
client=chat_client,
tools=[get_weather, search_restaurants],
)
# Create FastAPI app
app = FastAPI(title="AG-UI Travel Assistant")
add_agent_framework_fastapi_endpoint(app, agent, "/")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8888)
도구 이벤트 이해
에이전트가 도구를 호출하면 클라이언트는 다음과 같은 여러 이벤트를 받습니다.
도구 호출 이벤트
# 1. TOOL_CALL_START - Tool execution begins
{
"type": "TOOL_CALL_START",
"toolCallId": "call_abc123",
"toolCallName": "get_weather"
}
# 2. TOOL_CALL_ARGS - Tool arguments (may stream in chunks)
{
"type": "TOOL_CALL_ARGS",
"toolCallId": "call_abc123",
"delta": "{\"location\": \"Paris, France\"}"
}
# 3. TOOL_CALL_END - Arguments complete
{
"type": "TOOL_CALL_END",
"toolCallId": "call_abc123"
}
# 4. TOOL_CALL_RESULT - Tool execution result
{
"type": "TOOL_CALL_RESULT",
"toolCallId": "call_abc123",
"content": "The weather in Paris, France is sunny with a temperature of 22°C."
}
향상된 도구 이벤트용 클라이언트
도구 실행을 표시하는 향상된 클라이언트 AGUIChatClient 는 다음과 같습니다.
"""AG-UI client with tool event handling."""
import asyncio
import os
from agent_framework import Agent
from agent_framework_ag_ui import AGUIChatClient
async def main():
"""Main client loop with tool event display."""
server_url = os.environ.get("AGUI_SERVER_URL", "http://127.0.0.1:8888/")
print(f"Connecting to AG-UI server at: {server_url}\n")
# Create AG-UI chat client
chat_client = AGUIChatClient(endpoint=server_url)
# Create agent with the chat client
agent = Agent(
name="ClientAgent",
client=chat_client,
instructions="You are a helpful assistant.",
)
# Get a thread for conversation continuity
thread = agent.create_session()
try:
while True:
message = input("\nUser (:q or quit to exit): ")
if not message.strip():
continue
if message.lower() in (":q", "quit"):
break
print("\nAssistant: ", end="", flush=True)
async for update in agent.run(message, session=thread, stream=True):
# Display text content
if update.text:
print(f"\033[96m{update.text}\033[0m", end="", flush=True)
# Display tool calls and results
for content in update.contents:
if content.type == "function_call":
print(f"\n\033[95m[Calling tool: {content.name}]\033[0m")
elif content.type == "function_result":
result_text = content.result if isinstance(content.result, str) else str(content.result)
print(f"\033[94m[Tool result: {result_text}]\033[0m")
print("\n")
except KeyboardInterrupt:
print("\n\nExiting...")
except Exception as e:
print(f"\n\033[91mError: {e}\033[0m")
if __name__ == "__main__":
asyncio.run(main())
상호 작용 예제
향상된 서버 및 클라이언트가 실행 중인 경우:
User (:q or quit to exit): What's the weather like in Paris and suggest some Italian restaurants?
[Run Started]
[Tool Call: get_weather]
[Tool Result: The weather in Paris, France is sunny with a temperature of 22°C.]
[Tool Call: search_restaurants]
[Tool Result: {"location": "Paris", "cuisine": "Italian", "results": [...]}]
Based on the current weather in Paris (sunny, 22°C) and your interest in Italian cuisine,
I'd recommend visiting Bella Italia, which has a 4.2 rating. The weather is perfect for
outdoor dining!
[Run Finished]
도구 구현 모범 사례
오류 처리
도구에서 오류를 원활하게 대처합니다.
@tool
def get_weather(
location: Annotated[str, Field(description="The city.")],
) -> str:
"""Get the current weather for a location."""
try:
# Call weather API
result = call_weather_api(location)
return f"The weather in {location} is {result['condition']} with temperature {result['temp']}°C."
except Exception as e:
return f"Unable to retrieve weather for {location}. Error: {str(e)}"
풍부한 반환 유형
적절한 경우 구조화된 데이터를 반환합니다.
@tool
def analyze_sentiment(
text: Annotated[str, Field(description="The text to analyze")],
) -> dict[str, Any]:
"""Analyze the sentiment of text."""
# Perform sentiment analysis
return {
"text": text,
"sentiment": "positive",
"confidence": 0.87,
"scores": {
"positive": 0.87,
"neutral": 0.10,
"negative": 0.03,
},
}
기술 문서
에이전트가 도구를 사용하는 시기를 이해하는 데 도움이 되는 명확한 설명을 제공합니다.
@tool
def book_flight(
origin: Annotated[str, Field(description="Departure city and airport code, e.g., 'New York, JFK'")],
destination: Annotated[str, Field(description="Arrival city and airport code, e.g., 'London, LHR'")],
date: Annotated[str, Field(description="Departure date in YYYY-MM-DD format")],
passengers: Annotated[int, Field(description="Number of passengers")] = 1,
) -> dict[str, Any]:
"""
Book a flight for specified passengers from origin to destination.
This tool should be used when the user wants to book or reserve airline tickets.
Do not use this for searching flights - use search_flights instead.
"""
# Implementation
pass
클래스가 있는 도구 조직
관련 도구의 경우 클래스에서 구성합니다.
from agent_framework import tool
class WeatherTools:
"""Collection of weather-related tools."""
def __init__(self, api_key: str):
self.api_key = api_key
@tool
def get_current_weather(
self,
location: Annotated[str, Field(description="The city.")],
) -> str:
"""Get current weather for a location."""
# Use self.api_key to call API
return f"Current weather in {location}: Sunny, 22°C"
@tool
def get_forecast(
self,
location: Annotated[str, Field(description="The city.")],
days: Annotated[int, Field(description="Number of days")] = 3,
) -> dict[str, Any]:
"""Get weather forecast for a location."""
# Use self.api_key to call API
return {"location": location, "forecast": [...]}
# Create tools instance
weather_tools = WeatherTools(api_key="your-api-key")
# Create agent with class-based tools
agent = Agent(
name="WeatherAgent",
instructions="You are a weather assistant.",
client=OpenAIChatCompletionClient(...),
tools=[
weather_tools.get_current_weather,
weather_tools.get_forecast,
],
)
다음 단계
이제 백 엔드 도구 렌더링을 이해했으므로 다음을 수행할 수 있습니다.
- 고급 도구 만들기: 에이전트 프레임워크를 사용하여 함수 도구를 만드는 방법에 대해 자세히 알아보기
추가 리소스
go AG-UI 서버는 일반 Agent Framework 함수 도구를 노출할 수 있습니다. 를 사용하여 tool/functool도구를 만들고, 호스트된 에이전트에 연결하고, 에이전트 aguiprovider.NewJSONHTTPHandler에 서비스를 제공합니다.
searchRestaurants := functool.MustNew(functool.Config{
Name: "search_restaurants",
Description: "Search for restaurants in a location.",
}, func(ctx context.Context, in restaurantSearchRequest) (restaurantSearchResponse, error) {
return restaurantSearchResponse{
Location: in.Location,
Cuisine: in.Cuisine,
Results: []restaurantInfo{{Name: "The Golden Fork", Cuisine: in.Cuisine}},
}, nil
})
a := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
Config: agent.Config{
Tools: []tool.Tool{searchRestaurants},
},
})
Tip
전체 실행 가능한 예제는 AG-UI 백 엔드 도구 샘플을 참조하세요.