التحكم في توفر الأدوات

Note

واجهة برمجة تطبيقات التعرض للأداة التقدمية (FunctionInvocationContext.add_tools / remove_tools) حاليا Python فقط.

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

  • التعرض التدريجي للأداة — إضافة أو إزالة الأدوات في وقت التشغيل من داخل أداة أو برنامج وسيط وظيفي، لذلك لا يرى النموذج سوى الأدوات التي يكون جاهزا للاستخدام.
  • Middleware gating — استخدم الوسيطة الوظيفية للتحقق من صحة وسيطات المكالمة وإرجاع الملاحظات التصحيحية دون تنفيذ الدالة الأساسية.
  • المكالمة الأولى القسرية — استخدم tool_choice لطلب النموذج لاستدعاء أداة معينة قبل أي أداة أخرى.

Note

لا تتطلب قيود الترتيب المزدوج مثل "استدعاء get_record دائما قبل update_record" سير عمل. تتعامل التقنيات الموجودة في هذه الصفحة مع هذا النمط داخل تشغيل واحد. مهام سير العمل مخصصة للتنسيق الأصلي متعدد الخطوات عبر عمليات التشغيل أو الفروع المتوازية.

التعرض التدريجي للأداة

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

واجهة برمجة التطبيقات تجريبية وتعيش على FunctionInvocationContext:

العضو Description
ctx.tools مباشرة، قابلة list للتغيير من الأدوات للتشغيل الحالي. None عند استدعاء الدالة خارج حلقة استدعاء الدالة.
ctx.add_tools(tools) إضافة واحدة أو أكثر من الأدوات. يتم التفاف المكالمات ك FunctionTool. إعادة إضافة نفس الكائن هي no-op؛ كائن مختلف باسم مكرر يرفع ValueError. الكل أو لا شيء: إذا تم رفع أي أداة في الدفعة، فلن تتم إضافة أي أداة.
ctx.remove_tools(tools) قم بالإزالة حسب الاسم أو كائن الأداة أو القابل للاستدعاء. يتم تجاهل الأسماء غير الموجودة في القائمة بصمت.

يصدر كلا المساعدين ExperimentalWarning في المرة الأولى التي يتم استدعاؤها في عملية (معرف PROGRESSIVE_TOOLSالميزة ). استدعاء أي من المساعدين خارج حلقة استدعاء الوظيفة يثير RuntimeError.

Important

يتم إعادة تعيين قائمة الأدوات إلى المجموعة الأصلية في كل مكالمة جديدة agent.run() ، لذا يتم إعادة تسليح جميع البوابات تلقائيا لكل دور.

Note

ينطبق التعرض التدريجي للأداة على حلقة استدعاء الوظائف القياسية فقط. وهو غير متوفر لموفري CodeAct (agent-framework-monty، agent-framework-hyperlight)، حيث يرى النموذج سطح تنفيذ التعليمات البرمجية واحد بدلا من مخططات الأدوات الفردية. يؤدي استدعاء add_tools أو remove_tools من داخل بيئة الاختبار المعزولة CodeAct إلى RuntimeErrorرفع . لتغيير مجموعة الأدوات لعامل CodeAct، استخدم أساليب الموفر الخاصة add_tools / / remove_toolclear_tools بين عمليات التشغيل.

نمط أداة Loader

تسجيل مجموعة صغيرة من أدوات "loader" مقدما والسماح للنموذج بسحب أدوات إضافية عند الطلب. هذا يحافظ على المخطط الأولي صغيرا، ما يحسن دقة تحديد الأدوات ويقلل من التكلفة.

import asyncio
import warnings
from typing import Annotated

from agent_framework import Agent, FunctionInvocationContext, tool
from agent_framework.openai import OpenAIChatClient
from pydantic import Field

warnings.filterwarnings("ignore", category=FutureWarning)  # suppress ExperimentalWarning for brevity


@tool(approval_mode="never_require")
def factorial(n: Annotated[int, Field(description="A non-negative integer.")]) -> str:
    """Compute the factorial of n."""
    if n < 0:
        return "Error: n must be a non-negative integer."
    result = 1
    for value in range(2, n + 1):
        result *= value
    return f"{n}! = {result}"


@tool(approval_mode="never_require")
def fibonacci(n: Annotated[int, Field(description="The 0-based index in the Fibonacci sequence.")]) -> str:
    """Compute the n-th Fibonacci number."""
    if n < 0:
        return "Error: n must be a non-negative integer."
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    return f"fib({n}) = {a}"


# The ctx parameter is injected by the framework and is NOT visible to the model.
@tool(approval_mode="never_require")
def load_math_tools(ctx: FunctionInvocationContext) -> str:
    """Load additional math tools (factorial, fibonacci) so they can be used."""
    ctx.add_tools([factorial, fibonacci])
    return "Loaded math tools: factorial, fibonacci. You can now call them."


async def main() -> None:
    agent = Agent(
        client=OpenAIChatClient(),
        name="MathAgent",
        instructions=(
            "You are a math assistant. "
            "If you need math capabilities that are not yet available, call load_math_tools first."
        ),
        tools=[load_math_tools],  # agent starts with only the loader
    )
    print(await agent.run("What is 5 factorial?"))


asyncio.run(main())

العينة الكاملة القابلة للتشغيل في python/samples/02-agents/tools/dynamic_tool_exposure.py.

نمط Gating

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

from agent_framework import Agent, FunctionInvocationContext, tool
from agent_framework.openai import OpenAIChatClient

_last_fetched_id: str | None = None


@tool(approval_mode="never_require")
def get_record(record_id: str, ctx: FunctionInvocationContext) -> str:
    """Fetch a record. Unlocks update_record for the same record."""
    global _last_fetched_id
    _last_fetched_id = record_id
    ctx.add_tools(update_record)  # gate: expose the write tool now
    return f"Record {record_id}: title='Example record', status='open'"


@tool(approval_mode="never_require")
def update_record(record_id: str, status: str) -> str:
    """Update the status of a record."""
    return f"Updated record {record_id} to status '{status}'."


agent = Agent(
    client=OpenAIChatClient(),
    name="RecordAgent",
    instructions="You help manage records. Fetch a record before updating it.",
    tools=[get_record],  # update_record is hidden until get_record runs
)

نظرا ctx.tools لإعادة التعيين إلى [get_record] في بداية كل تشغيل، تعيد البوابة شحنها تلقائيا لكل منعطف المحادثة.

وسيطة gating

يمكن للبرنامج الوسيط للدالة فحص وسيطات استدعاء أداة معلقة ورفضها قبل تنفيذ الدالة الأساسية عن طريق الإعداد context.result دون استدعاء call_next(). يتم إرجاع السلسلة المعينة إلى context.result النموذج كنتيجة للدالة، مما يعطيها ملاحظات تصحيحية.

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

from collections.abc import Awaitable, Callable

from agent_framework import FunctionInvocationContext

_last_fetched_id: str | None = None


async def enforce_read_before_write(
    context: FunctionInvocationContext,
    call_next: Callable[[], Awaitable[None]],
) -> None:
    """Reject update_record calls that target a different record than the one fetched."""
    if context.function.name == "update_record":
        requested_id = context.arguments.get("record_id") if hasattr(context.arguments, "get") else None
        if requested_id != _last_fetched_id:
            # Set result without calling call_next — the function never executes.
            context.result = (
                f"Error: you must fetch record '{requested_id}' before updating it. "
                f"Last fetched record was '{_last_fetched_id}'."
            )
            return
    await call_next()

أضف البرنامج الوسيط إلى العامل:

agent = Agent(
    client=OpenAIChatClient(),
    name="RecordAgent",
    instructions="Fetch a record before updating it.",
    tools=[get_record, update_record],
    middleware=[enforce_read_before_write],
)

لمزيد من الاطلاع على البرامج الوسيطة للدالة، راجع تعريف البرامج الوسيطةوتجاوزات النتائج.

فرض استدعاء أداة باستخدام tool_choice

لمطالبة النموذج باستدعاء أداة معينة كإجراء أول لها، مرر tool_choice مع الوضع "required" و required_function_name. يتم إعادة تعيين tool_choice إطار العمل تلقائيا إلى None بعد التكرار الأول بحيث يكون النموذج مجانيا في التكرارات اللاحقة.

result = await agent.run(
    "Update record REC-42 to status 'in-progress'.",
    options={"tool_choice": {"mode": "required", "required_function_name": "get_record"}},
)

tool_choice يقبل ToolMode الحقل الإملاء أو السلاسل "auto"المختصرة أو "required"أو "none":

from agent_framework import ToolMode

tool_choice: ToolMode = {"mode": "required", "required_function_name": "get_record"}

دلالات ومحاذير

السلوك التفاصيل
تأثير التكرار التالي add_tools / remove_tools تكون الطفرات مرئية للنموذج في تكرار التكرار الحلقي التالي. اكتملت استدعاءات الأداة المرسلة بالفعل في الدفعة الحالية بغض النظر.
دفعة أثناء الطيران إذا طلب النموذج العديد من الأدوات في دفعة واحدة، يتم تنفيذ جميعها قبل إرسال قائمة الأدوات المحدثة مرة أخرى.
الأسماء المكررة إعادة إضافة نفس الكائن بالضبط هو no-op. تؤدي إضافة كائن مختلف يتطابق اسمه مع أداة موجودة إلى ValueErrorرفع . يتم التحقق من صحة الدفعة بأكملها قبل أي إضافة، لذلك يترك التكرار في منتصف القائمة القائمة المباشرة دون تغيير.
خطأ في التكرار الحلقي الخارجي استدعاء add_tools أو remove_tools عند ctx.tools is None رفع RuntimeError. يحدث هذا عند استدعاء الدالة مباشرة (على سبيل المثال عبر FunctionTool.invoke) بدلا من حلقة العامل.
الحالة التجريبية يصدر كلا المساعدين ExperimentalWarning عند أول مكالمة لكل عملية. منع مع warnings.filterwarnings("ignore", category=FutureWarning) إذا رغبت في ذلك.
نطاق لكل تشغيل قائمة الأدوات المباشرة هي نسخة جديدة تم إنشاؤها من normalize_tools في بداية كل agent.run() مكالمة. لا يتم تغيير الحاوية الأصلية tools للمتصل مطلقا.
استبعاد CodeAct غير متوفر لموفري agent-framework-monty CodeAct أو agent-framework-hyperlight .

Note

واجهات برمجة تطبيقات توفر أداة وقت التشغيل المغطاة في هذه الصفحة Python فقط حاليا. للحصول على أنماط أدوات Go، راجع أدوات الدالةواستخدام أدوات الدالة مع الإنسان في موافقات التكرار الحلقي.

الخطوات التالية