استخدام أدوات الدالة مع عامل

توضح لك خطوة البرنامج التعليمي هذه كيفية استخدام أدوات الدالة مع عامل، حيث يتم بناء العامل على خدمة إكمال دردشة OpenAI Azure.

Important

لا تدعم كافة أنواع الوكلاء أدوات الدالة. قد يدعم البعض الأدوات المضمنة المخصصة فقط، دون السماح للمتصل بتوفير وظائفه الخاصة. تستخدم ChatClientAgentهذه الخطوة ، والتي تدعم أدوات الدالة.

المتطلبات الأساسية

للحصول على المتطلبات الأساسية وتثبيت حزم NuGet، راجع خطوة إنشاء وتشغيل عامل بسيط في هذا البرنامج التعليمي.

إنشاء العامل باستخدام أدوات الدالة

أدوات الدالة هي مجرد تعليمة برمجية مخصصة تريد أن يتمكن العامل من الاتصال بها عند الحاجة. يمكنك تحويل أي أسلوب C# إلى أداة دالة، باستخدام AIFunctionFactory.Create الأسلوب لإنشاء AIFunction مثيل من الأسلوب .

إذا كنت بحاجة إلى توفير أوصاف إضافية حول الدالة أو معلماتها للعامل، بحيث يمكن الاختيار بشكل أكثر دقة بين الدالات المختلفة، يمكنك استخدام السمة 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)]);

تحذير

DefaultAzureCredential مناسب للتنمية ولكنه يتطلب دراسة متأنية في الإنتاج. في الإنتاج، ضع في اعتبارك استخدام بيانات اعتماد محددة (على سبيل المثال، ManagedIdentityCredential) لتجنب مشكلات زمن الانتقال، وبحث بيانات الاعتماد غير المقصودة، والمخاطر الأمنية المحتملة من الآليات الاحتياطية.

الآن يمكنك فقط تشغيل العامل كالمعتاد، وسيكون العامل قادرا على استدعاء أداة الدالة GetWeather عند الحاجة.

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

Tip

راجع نماذج .NET للحصول على أمثلة كاملة قابلة للتشغيل.

Important

لا تدعم كافة أنواع الوكلاء أدوات الدالة. قد يدعم البعض الأدوات المضمنة المخصصة فقط، دون السماح للمتصل بتوفير وظائفه الخاصة. تستخدم هذه الخطوة العوامل التي تم إنشاؤها عبر عملاء الدردشة، والتي تدعم أدوات الوظائف.

المتطلبات الأساسية

للحصول على المتطلبات الأساسية وتثبيت حزم 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 المصمم، فسيستخدم إطار العمل تلقائيا اسم الدالة و docstring كعمليات احتياطية.

استخدام المخططات الصريحة مع @tool

عندما تحتاج إلى التحكم الكامل في المخطط المكشوف للنموذج، قم بتمرير المعلمة schema إلى @tool. يمكنك توفير إما نموذج Pydantic أو قاموس مخطط JSON الخام.

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

تمرير سياق وقت التشغيل فقط إلى أداة

استخدم معلمات الدالة العادية للقيم التي يجب أن يوفرها النموذج. استخدم 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و ودالة الوسيطة، راجع سياق وقت التشغيل.

إنشاء أدوات الإعلان فقط

إذا تم تنفيذ أداة خارج إطار العمل (على سبيل المثال، من جانب العميل في واجهة المستخدم)، يمكنك الإعلان عنها دون تنفيذ باستخدام 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"],
    },
)

عند إنشاء العامل، يمكنك الآن توفير أداة الوظيفة للعامل، عن طريق تمريرها إلى المعلمة 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())

إنشاء فئة باستخدام أدوات وظائف متعددة

عندما تشترك العديد من الأدوات في تبعيات أو حالة قابلة للتغيير، قم بتضمينها في فئة وتمرير الأساليب المرتبطة إلى العامل. استخدم سمات الفئة للقيم التي يجب ألا يوفرها النموذج، مثل عملاء الخدمة أو علامات الميزات أو الحالة المخزنة مؤقتا.

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

استخدام أداة shell المحلية

يتضمن tool/shelltool Go SDK لتنفيذ shell المحلي. تتطلب الأداة الموافقة بشكل افتراضي ويمكن إقرانها بموفر سياق البيئة حتى يعرف النموذج عائلة shell الحالية ودليل العمل وإصدارات الأدوات الشائعة.

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 عندما يجب تشغيل كل مكالمة في shell جديدة. استخدم shelltool.ModePersistent فقط عندما تحتاج جلسة عامل واحد إلى حالة shell مثل الدلائل المتغيرة أو متغيرات البيئة المصدرة للاستمرار عبر المكالمات. اضبط AcknowledgeUnsafe: true فقط عند توفير حدود عزل مستقلة ولا تحتاج إلى بوابة الموافقة المضمنة.

استخدام أدوات الدالة مع Harness Agent

يستخدم الوكيل العادي الأدوات التي تمر بها أثناء إنشاء الوكيل، وتؤلف أي موفرين إضافيين أو برامج وسيطة بنفسك. يستخدم عامل Harness نفس أدوات الدالة، ولكنه يعمل مسبقا على تكوين البنية الأساسية لبرنامج ربط العمليات التجارية لاستدعاء الوظيفة، واستمرارية كل استدعاء لكل خدمة، ودعم الموافقة على الأدوات، وقدرات تسخير أخرى.

قم بتمرير أدوات الدالة من خلال HarnessAgentOptions.ChatOptions.Tools عند إنشاء HarnessAgent باستخدام AsHarnessAgent:

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 لتجاوز حد استدعاء الدالة الخاص به؛ يستخدم FunctionInvokingChatClient الافتراضي null الافتراضي. يضيف HostedWebSearchTool التسخير أيضا بشكل افتراضي، لذا قم بتعيين DisableWebSearch = true ما إذا كان يجب أن يعرض العامل الأدوات فقط في ChatOptions.Tools.

قم بتمرير أداة واحدة أو سلسلة من الأدوات إلى معلمة toolscreate_harness_agent:

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)

يقوم المصنع بتكوين استدعاء الدالة التلقائي واستمرار محفوظات استدعاء لكل خدمة. دالات مزينة باستخدام @toolapproval_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. راجع التحكم في توفر الأداة للأنماط الكاملة.