Függvényeszközök használata ügynök mellett

Ez az oktatóanyag lépés bemutatja, hogyan használhat függvényeszközöket egy ügynökkel, ahol az ügynök az Azure OpenAI Csevegés befejezése szolgáltatásra épül.

Fontos

Nem minden ügynöktípus támogatja a funkció eszközöket. Egyesek csak egyéni beépített eszközöket támogathatnak, és nem teszik lehetővé, hogy a hívó saját függvényeket adjon meg. Ez a lépés egy ChatClientAgent, amely támogatja a függvényeszközöket.

Előfeltételek

Az előfeltételekről és a NuGet-csomagok telepítéséről lásd az egyszerű ügynök létrehozása és futtatása lépést ebben az oktatóanyagban.

Az ügynök létrehozása funkcióeszközökkel

A funkcióeszközök olyan egyéni kódok, amelyeket az ügynök szükség esetén meghívhat. Bármely C#-metódust függvényeszközsé alakíthat, ha a AIFunctionFactory.Create metódus használatával létrehoz egy példányt AIFunction a metódusból.

Ha további leírásokat kell adnia a függvényről vagy annak paramétereiről az ügynöknek, hogy pontosabban tudjon választani a különböző függvények között, használhatja az System.ComponentModel.DescriptionAttribute attribútumot a metóduson és annak paraméterein.

Íme egy példa egy egyszerű függvényeszközre, amely meghamisít egy adott hely időjárását. Leírási attribútumokkal van díszítve, hogy további leírásokat adjon magáról és helyparaméteréről az ügynöknek.

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.";

Az ügynök létrehozásakor mostantól a függvényeszközt is átadhatja az ügynöknek, ha átadja az eszközök listáját a AsAIAgent metódusnak.

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)]);

Figyelmeztetés

DefaultAzureCredential a fejlesztéshez kényelmes, de a termelési környezetben gondos megfontolást igényel. Éles környezetben fontolja meg egy adott hitelesítő adat (pl. ManagedIdentityCredential) használatát a késési problémák elkerülése, a hitelesítő adatok nem szándékos próbálgatásának és a tartalék mechanizmusokból eredő esetleges biztonsági kockázatok elkerülése érdekében.

Most már csak a szokásos módon futtathatja az ügynököt, és szükség esetén az ügynök meghívhatja a GetWeather függvényeszközt.

Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?"));

Jótanács

A teljes futtatható példákért tekintse meg a .NET-mintákat .

Fontos

Nem minden ügynöktípus támogatja a funkció eszközöket. Egyesek csak egyéni beépített eszközöket támogathatnak, és nem teszik lehetővé, hogy a hívó saját függvényeket adjon meg. Ez a lépés a chat ügyfeleken keresztül létrehozott ügynököket használja, amelyek támogatják a funkcióeszközöket.

Előfeltételek

Az előfeltételekről és a Python-csomagok telepítéséről lásd a Hozzon létre és futtasson egy egyszerű ügynököt lépést ebben az oktatóanyagban.

Az ügynök létrehozása funkcióeszközökkel

A funkcióeszközök olyan egyéni kódok, amelyeket az ügynök szükség esetén meghívhat. Bármely Python-függvényt függvényeszközzé alakíthat, ha az ügynök tools paraméterének adja meg az ügynök létrehozásakor.

Ha további leírásokat kell adnia a függvényről vagy annak paramétereiről az ügynöknek, hogy pontosabban tudjon választani a különböző függvények között, a Python típusjegyzeteivel Annotated és Pydantic-jával Field leírásokat adhat meg.

Íme egy példa egy egyszerű függvényeszközre, amely meghamisít egy adott hely időjárását. Típusjegyzetekkel további leírásokat ad meg a függvényről és a helyparaméterről az ügynök számára.

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."

A @tool dekorátor segítségével egyértelműen megadhatja a függvény nevét és leírását.

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."

Ha nem adja meg a name és description paramétereket a @tool dekorátorban, a keretrendszer automatikusan a függvény nevét és a doksorját használja tartalékként.

Kifejezett sémák használata @tool

Amikor teljes mértékben kézben akarja tartani a modell számára megadott sémát, adja át a schema paramétert a @tool számára. Pydantic-modellt vagy nyers JSON-sémaszótárat is megadhat.

# 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",
)
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 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.",
    schema=get_current_time_schema,
    approval_mode="never_require",
)
def get_current_time(timezone: str = "UTC") -> str:
    """Get the current time."""

Csak futásidejű környezet átadása egy eszköznek

Használjon normál függvényparamétereket a modell által megadott értékekhez. Csak futásidejű értékekhez használható FunctionInvocationContext , például function_invocation_kwargs az aktuális munkamenethez. Az injektált környezeti paraméter el van rejtve a modell számára közzétett séma elől.

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}")

A ctx.kwargsctx.session és a függvény köztes szoftverről további információt a Futtatókörnyezet című témakörben talál.

Csak deklarációs eszközök létrehozása

Ha egy eszköz a keretrendszeren kívül van megvalósítva (például ügyféloldali a felhasználói felületen), deklarálhatja implementáció nélkül a FunctionTool(..., func=None) segítségével. A modell továbbra is tud érvelni és meghívni az eszközt, és az alkalmazás később is meg tudja adni az eredményt.

# 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"],
    },
)

Az ügynök létrehozásakor most már megadhatja a függvényeszközt az ügynöknek, ha átadja azt a tools paraméternek.

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
)

Most már csak a szokásos módon futtathatja az ügynököt, és szükség esetén az ügynök meghívhatja a get_weather függvényeszközt.

async def main():
    result = await agent.run("What is the weather like in Amsterdam?")
    print(result.text)

asyncio.run(main())

Osztály létrehozása több függvényeszközzel

Ha több eszköz osztozik függőségeken vagy megváltoztatható állapoton, csomagolja őket egy osztályba, és adja át a kapcsolt metódusokat az ügynök számára. Használjon osztályattribútumokat olyan értékekhez, amelyeket a modell nem adhat meg, például szolgáltatásügyfeleket, funkciójelölőket vagy gyorsítótárazott állapotot.

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

Ez a minta jól illeszkedik a hosszú élettartamú eszközállapothoz. Használja FunctionInvocationContext inkább, ha az érték hívásonként változik.

Függvénykezelő eszközök

A függvényeszközök lehetővé teszik, hogy az ügynökök egyéni Go-függvényeket hívjanak. A functool csomag egyszerű módot kínál a típusbiztos eszközök automatikus sémagenerálással történő definiálására.

Függvényeszköz definiálása

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
})

A függvény aláírása határozza meg az eszköz bemeneti sémáját. A context.Context paramétert a keretrendszer injektálja, és nincs kitéve a modellnek.

Strukturált bemeneti típusok

Több paraméterrel rendelkező eszközök esetén adjon meg egy szerkezetet:

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
})

Ügynök létrehozása eszközökkel

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()

Ügynök használata függvényeszközként

Bármely ügynök becsomagolható függvényeszközként egy másik ügynök számára:

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{})},
    },
})

Használja a helyi parancsértelmező eszközt

A Go SDK tartalmazza a(z) tool/shelltool elemet a helyi parancsértelmezőben való végrehajtáshoz. Az eszköz alapértelmezés szerint jóváhagyást igényel, és párosítható egy környezeti környezetszolgáltatóval, így a modell ismeri az aktuális rendszerhéjcsaládot, a munkakönyvtárat és a gyakori eszközverziókat.

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},
    },
})

Akkor használható shelltool.ModeStateless , ha minden hívásnak egy friss rendszerhéjban kell futnia. Csak akkor használható shelltool.ModePersistent , ha egyetlen ügynök munkamenetének rendszerhéjállapotra van szüksége, például módosított könyvtárakra vagy exportált környezeti változókra, hogy a hívások között megmaradjanak. Csak akkor állítsa be AcknowledgeUnsafe: true , ha független elkülönítési határt ad meg, és nincs szüksége a beépített jóváhagyási kapura.

Következő lépések

Eszköz rendelkezésre állásának szabályozása futásidőben

Eszközöket adhat hozzá vagy távolíthat el az ügynök futása közben a FunctionInvocationContext.add_tools() / remove_tools() használatával, vezérelheti a hívásokat függvényköztes rétegen keresztül, vagy kikényszeríthet egy adott első hívást a tool_choice használatával. A teljes mintákhoz tekintse meg az eszközök rendelkezésre állásának szabályozását .