이 자습서 단계에서는 에이전트와 함께 함수 도구를 사용하는 방법을 보여 줍니다. 여기서 에이전트는 Azure OpenAI 채팅 완료 서비스를 기반으로 합니다.
중요합니다
모든 에이전트 형식이 함수 도구를 지원하는 것은 아닙니다. 일부는 호출자가 자체 함수를 제공하도록 허용하지 않고 사용자 지정 기본 제공 도구만 지원할 수 있습니다. 이 단계에서는 함수를 지원하는 ChatClientAgent를 사용합니다.
필수 조건
필수 구성 요소 및 NuGet 패키지 설치는 이 자습서의 간단한 에이전트 만들기 및 실행 단계를 참조하세요.
함수 도구를 사용하여 에이전트 만들기
함수 도구는 필요할 때 에이전트가 호출할 수 있도록 하는 사용자 지정 코드일 뿐입니다.
메서드에서 AIFunction 인스턴스를 생성하는 AIFunctionFactory.Create 메서드를 사용하면 모든 C# 메서드를 함수 도구로 변환할 수 있습니다.
다른 함수 중에서 더 정확하게 선택할 수 있도록 함수 또는 해당 매개 변수에 대한 추가 설명을 에이전트에 제공해야 하는 경우 메서드와 해당 매개 변수에 특성을 사용할 System.ComponentModel.DescriptionAttribute 수 있습니다.
다음은 지정된 위치에 대한 날씨를 가짜로 만드는 간단한 함수 도구의 예입니다. 자체 및 해당 위치 매개 변수에 대한 추가 설명을 에이전트에 제공하기 위해 설명 특성으로 데코레이팅됩니다.
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.";
이제 에이전트를 만들 때, 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)]);
Warning
DefaultAzureCredential 은 개발에 편리하지만 프로덕션 환경에서 신중하게 고려해야 합니다. 프로덕션 환경에서는 특정 자격 증명(예: ManagedIdentityCredential)을 사용하여 대기 시간 문제, 의도하지 않은 자격 증명 검색 및 대체 메커니즘의 잠재적인 보안 위험을 방지하는 것이 좋습니다.
이제 에이전트를 정상적으로 실행할 수 있으며 필요한 경우 에이전트가 GetWeather 함수 도구를 호출할 수 있습니다.
Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?"));
Tip
실행 가능한 전체 예제는 .NET 샘플 참조하세요.
중요합니다
모든 에이전트 형식이 함수 도구를 지원하는 것은 아닙니다. 일부는 호출자가 자체 함수를 제공하도록 허용하지 않고 사용자 지정 기본 제공 도구만 지원할 수 있습니다. 이 단계에서는 함수 도구를 지원하는 채팅 클라이언트를 통해 만든 에이전트를 사용합니다.
필수 조건
필수 구성 요소 및 Python 패키지 설치는 이 자습서의 간단한 에이전트 만들기 및 실행 단계를 참조하세요.
함수 도구를 사용하여 에이전트 만들기
함수 도구는 필요할 때 에이전트가 호출할 수 있도록 하는 사용자 지정 코드일 뿐입니다.
에이전트를 만들 때 Python 함수를 에이전트의 tools 매개 변수에 전달하여 함수 도구로 전환할 수 있습니다.
다른 함수 중에서 더 정확하게 선택할 수 있도록 함수 또는 해당 매개 변수에 대한 추가 설명을 에이전트에 제공해야 하는 경우 Python의 형식 주석과 Annotated Pydantic을 Field 사용하여 설명을 제공할 수 있습니다.
다음은 지정된 위치에 대한 날씨를 가짜로 만드는 간단한 함수 도구의 예입니다. 형식 주석을 사용하여 함수 및 해당 위치 매개 변수에 대한 추가 설명을 에이전트에 제공합니다.
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."
데코레이터를 @tool 사용하여 함수의 이름과 설명을 명시적으로 지정할 수도 있습니다.
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."
데코레이터에서 name 매개 변수 및 description 매개 변수를 @tool 지정하지 않으면 프레임워크는 자동으로 함수의 이름과 문서 문자열을 대체로 사용합니다.
@tool를 사용하여 명시적 스키마 사용
모델에 노출된 스키마를 완전히 제어해야 하는 경우, 매개 변수를 schema에 전달합니다 @tool.
Pydantic 모델 또는 원시 JSON 스키마 사전을 제공할 수 있습니다.
from pydantic import BaseModel, Field
# 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.",
)
def get_weather(location: str, unit: str = "celsius") -> str:
"""Get the current weather for a location."""
return f"The weather in {location} is 22 degrees {unit}."
# Approach 2: JSON schema dictionary for a trusted, non-sensitive tool.
# This receives lightweight top-level checks only; use Pydantic for runtime enforcement.
get_current_time_schema = {
"type": "object",
"properties": {
"timezone": {"type": "string", "description": "The timezone to get the current time for", "default": "UTC"},
},
}
@tool(
도구에 런타임 전용 컨텍스트 전달
모델에서 제공해야 하는 값에 대해 일반 함수 매개 변수를 사용합니다. 런타임 전용 값으로는 FunctionInvocationContext, function_invocation_kwargs 또는 현재 세션이 있습니다. 삽입된 컨텍스트 매개 변수는 모델에 노출된 스키마에서 숨겨집니다.
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"},
)
print(f"Agent: {response.text}")
ctx.kwargs, ctx.session, 및 함수 미들웨어에 대한 자세한 내용은 런타임 컨텍스트를 참조하세요.
선언 전용 도구 만들기
도구가 프레임워크 외부에서 구현되는 경우(예: UI의 클라이언트 쪽) 다음을 사용하여 FunctionTool(..., func=None)구현 없이 선언할 수 있습니다.
모델은 도구를 추론하고 호출할 수 있으며 애플리케이션은 나중에 결과를 제공할 수 있습니다.
# 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"},
},
"required": ["reason"],
},
)
사용자 지정 도구 결과 구문 분석
원시 반환 값을 문자열 또는 @tool 항목 목록으로 변환해야 하는 경우 result_parser 또는 FunctionTool에 Content을 설정합니다. 사용자 지정 파서가 예외를 발생시키면 직접 호출에서는 예외가 그대로 전파되고, 자동 함수 호출에서는 일반적인 도구 오류 결과를 반환하며 include_detailed_errors를 준수합니다. 원시 반환 값은 대체(fallback)로 사용되지 않으므로 사용자 지정 파서 내에서 복구 가능한 변환 오류를 처리합니다.
에이전트를 만들 때 이제 함수 도구를 매개 변수에 전달하여 에이전트에 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
)
이제 에이전트를 정상적으로 실행할 수 있으며 필요한 경우 에이전트가 get_weather 함수 도구를 호출할 수 있습니다.
async def main():
result = await agent.run("What is the weather like in Amsterdam?")
print(result.text)
asyncio.run(main())
자동 도구 호출 제한
모델 왕복, 총 함수 호출 및 경과된 벽시계 시간으로 자동 도구 호출을 제어하도록 채팅 클라이언트에 대한 제한을 설정합니다.
max_function_calls 및 max_duration_seconds 기본값으로 None, 무제한을 의미합니다. 양수 값으로 설정합니다. 클라이언트가 제한에 도달하면 도구 호출을 중지하고 최종 텍스트 응답을 모델에 요청합니다.
이러한 제한은 최상의 작업이며 모델에서 요청한 각 도구 호출 일괄 처리 후에 확인되므로 일괄 처리가 호출 수 또는 기간 제한을 초과할 수 있습니다. 도구 승인을 기다리는 데 걸린 시간은 max_duration_seconds에 포함됩니다.
from agent_framework.openai import OpenAIChatCompletionClient
client = OpenAIChatCompletionClient()
client.function_invocation_configuration.update(
{
"max_iterations": 5,
"max_function_calls": 20,
"max_duration_seconds": 30.0,
}
)
동시 도구 호출 제어
한 도우미 메시지에서 반환된 함수 호출은 기본적으로 동시에 실행됩니다. 도구가 변경 가능한 상태를 공유하거나 모델 순서대로 실행되어야 하는 경우 False을(를) allow_concurrent_invocation(으)로 설정합니다:
client.function_invocation_configuration["allow_concurrent_invocation"] = False
이 설정은 클라이언트 쪽 도구 실행을 공급자 쪽 옵션(예: allow_multiple_tool_calls)과 독립적으로 제어합니다. 세션 지원 승인 일괄 처리의 경우 결정은 별도로 도착할 수 있지만 도구가 실행되지 않으며 원래 일괄 처리의 모든 승인이 결정될 때까지 모델이 다시 시작되지 않습니다. 승인된 도구는 모델의 원래 순서대로 실행됩니다.
컨트롤 도구 오류 세부 정보
기본적으로 include_detailed_errors는 False입니다. 함수 실행 및 인수 유효성 검사 실패는 제네릭 결과를 모델 및 기타 직렬화된 채널에 반환합니다. 원래의 진단 결과는 Content.exception에서 신뢰할 수 있는 호스트 코드에 계속 제공됩니다.
Content.to_dict() 는 해당 필드를 고정된 민감하지 않은 오류 표식으로 바꾸고 프로토콜 변환은 진단을 노출하지 않습니다.
결과가 신뢰할 수 있는 채널에 유지되는 경우에만 설정합니다 client.function_invocation_configuration["include_detailed_errors"] = True . 예외 텍스트는 중요한 데이터를 포함할 수 있으며, 이 설정은 채널 표시 결과에 해당 텍스트를 추가합니다.
여러 함수 도구를 사용하여 클래스 만들기
여러 도구가 종속성 또는 변경 가능한 상태를 공유하는 경우 클래스에 래핑하고 바인딩된 메서드를 에이전트에 전달합니다. 모델에서 제공하지 않아야 하는 값(예: 서비스 클라이언트, 기능 플래그 또는 캐시된 상태)에 클래스 특성을 사용합니다.
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
이 패턴은 수명이 긴 도구 상태에 적합합니다. 호출당 값이 변경될 때 대신 사용합니다 FunctionInvocationContext .
함수 도구
함수 도구를 사용하면 에이전트가 사용자 지정 Go 함수를 호출할 수 있습니다. 이 패키지는 functool 자동 스키마 생성을 사용하여 형식 안전 도구를 정의하는 간단한 방법을 제공합니다.
함수 도구 정의
import (
"context"
"github.com/microsoft/agent-framework-go/tool"
"github.com/microsoft/agent-framework-go/tool/functool"
)
var weatherTool = functool.MustNew(functool.Config{
Name: "weather",
Description: "Get the current weather for a given location",
}, func(_ context.Context, location string) (string, error) {
return fmt.Sprintf("The weather in %s is cloudy with a high of 15°C.", location), nil
})
함수 서명은 도구의 입력 스키마를 결정합니다.
context.Context 매개 변수는 프레임워크에 의해 삽입되며 모델에 노출되지 않습니다.
구조적 입력 형식
여러 매개 변수가 있는 도구의 경우 구조체를 정의합니다.
type WeatherInput struct {
Location string `json:"location" jsonschema:"description=The city to check weather for"`
Unit string `json:"unit" jsonschema:"description=Temperature unit (celsius or fahrenheit),enum=celsius,enum=fahrenheit"`
}
var weatherTool = functool.MustNew(functool.Config{
Name: "weather",
Description: "Get weather for a location",
}, func(_ context.Context, input WeatherInput) (string, error) {
return fmt.Sprintf("Weather in %s: 15°%s", input.Location, input.Unit), nil
})
도구를 사용하여 에이전트 만들기
a := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
Instructions: "You are a helpful assistant.",
Config: agent.Config{
Tools: []tool.Tool{weatherTool},
},
})
resp, err := a.RunText(ctx, "What is the weather like in Amsterdam?").Collect()
에이전트를 함수 도구로 사용
모든 에이전트는 다른 에이전트에서 사용할 수 있는 함수 도구로 래핑할 수 있습니다.
import "github.com/microsoft/agent-framework-go/tool/agenttool"
weatherAgent := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
Instructions: "You answer questions about the weather.",
Config: agent.Config{
Name: "WeatherAgent",
Description: "An agent that answers weather questions.",
Tools: []tool.Tool{weatherTool},
},
})
mainAgent := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
Instructions: "You are a helpful assistant who responds in French.",
Config: agent.Config{
Tools: []tool.Tool{agenttool.New(weatherAgent, agenttool.Config{})},
},
})
로컬 셸 도구 사용
Go SDK는 로컬 셸 실행을 포함합니다 tool/shelltool . 이 도구는 기본적으로 승인이 필요하며, 모델이 현재 셸 패밀리, 작업 디렉터리 및 일반 도구 버전을 알 수 있도록 환경 컨텍스트 공급자와 페어링할 수 있습니다.
import "github.com/microsoft/agent-framework-go/tool/shelltool"
shell, err := shelltool.NewLocal(shelltool.LocalConfig{
Mode: shelltool.ModeStateless,
})
if err != nil {
return err
}
defer shell.Close()
envProvider := shelltool.NewEnvironmentProvider(shell, shelltool.EnvironmentProviderConfig{})
a := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
Instructions: "Run shell commands only when needed and summarize the result.",
Config: agent.Config{
Tools: []tool.Tool{shell},
ContextProviders: []agent.ContextProvider{envProvider},
},
})
각 호출이 새 셸에서 실행되어야 하는 경우에 사용합니다 shelltool.ModeStateless . 단일 에이전트 세션에 변경된 디렉터리 또는 내보낸 환경 변수와 같은 셸 상태가 호출 간에 유지되어야 하는 경우에만 사용합니다 shelltool.ModePersistent . 독립적인 격리 경계를 제공하고 기본 제공 승인 게이트가 필요하지 않은 경우에만 설정합니다 AcknowledgeUnsafe: true .
Tip
전체 예제는 함수 도구 샘플, 에이전트를 도구 샘플로, 환경 샘플이 포함된 셸 을 참조하세요.
Harness 에이전트와 함께 함수 도구 사용
일반 에이전트는 에이전트 생성 중에 전달하는 도구를 사용하며 추가 공급자 또는 미들웨어를 직접 작성합니다. Harness 에이전트는 동일한 함수 도구를 사용하지만 함수 호출 파이프라인, 서비스별 호출 기록 지속성, 도구 승인 지원 및 기타 하네스 기능을 미리 구성합니다.
AsHarnessAgent로 HarnessAgent를 생성할 때 HarnessAgentOptions.ChatOptions.Tools를 통해 함수 도구를 전달하세요:
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
AIAgent agent = chatClient.AsHarnessAgent(new HarnessAgentOptions
{
ChatOptions = new ChatOptions
{
Instructions = "You are a helpful assistant.",
Tools = [AIFunctionFactory.Create(GetWeather)],
},
});
AgentSession session = await agent.CreateSessionAsync();
AgentResponse response = await agent.RunAsync(
"What is the weather like in Amsterdam?",
session);
HarnessAgent가 FunctionInvokingChatClient을 자동으로 구성합니다.
HarnessAgentOptions.MaximumIterationsPerRequest을 설정하여 해당 함수 호출 제한을 재정의합니다. 기본 null은 FunctionInvokingChatClient의 기본값을 사용합니다. 하네스는 기본적으로 HostedWebSearchTool도 추가하므로, 에이전트가 ChatOptions.Tools의 도구만 노출해야 하는 경우 DisableWebSearch = true를 설정하세요.
create_harness_agent의 tools 매개변수에 단일 도구 또는 도구 시퀀스를 전달합니다.
from agent_framework import create_harness_agent
agent = create_harness_agent(
client=client,
agent_instructions="You are a helpful assistant.",
tools=get_weather,
)
session = agent.create_session()
response = await agent.run(
"What is the weather like in Amsterdam?",
session=session,
)
print(response.text)
팩터리는 자동 함수 호출 및 서비스별 호출 기록 지속성을 구성합니다.
@tool로 데코레이팅된 함수는 기본적으로 approval_mode="never_require"를 사용합니다.
disable_web_search=False 또한 클라이언트가 지원하는 경우 클라이언트의 웹 검색 도구를 추가합니다. 을 생략하도록 설정합니다 disable_web_search=True .
하네스는 기본적으로 ToolApprovalMiddleware를 설치하며(disable_tool_auto_approval=False), 해당 미들웨어는 각 실행마다 AgentSession를 필요로 합니다.
session=agent.create_session()를 표시된 대로 전달하거나, 하네스 승인 미들웨어가 필요하지 않은 경우 disable_tool_auto_approval=True를 명시적으로 설정하세요.
패키지된 Go 하네스는 현재 사용할 수 없습니다. 함수 도구를 agent.Config.Tools 추가하여 필요한 미들웨어 및 컨텍스트 공급자를 직접 작성합니다.
다음 단계
런타임 시 도구 가용성 제어
에이전트를 실행하는 동안 함수 미들웨어를 통한 게이트 호출 또는 특정 첫 번째 호출을 강제로 사용하여 FunctionInvocationContext.add_tools() / remove_tools()도구를 추가하거나 제거할 수 있습니다.tool_choice 전체 패턴은 도구 가용성 제어를 참조하세요.