پرش به محتوا

فراخوانی ابزار (Function Calling)

به مدل ابزار بدهید تا تابع‌های برنامهٔ شما را صدا بزند: تعریف ابزار با JSON Schema، چرخهٔ کامل درخواست و پاسخ، چند فراخوانی همزمان و نکته‌های Gemini و Claude.

بازبینی: ۸ مهر ۱۴۰۵ ۷ دقیقه مطالعه

فراخوانی ابزار (Function Calling) یعنی مدل به‌جای جواب دادن از حافظهٔ خودش، از برنامهٔ شما بخواهد تابعی را اجرا کند: وضعیت سفارش را از پایگاه دادهٔ شما بخواند، قیمت روز را بگیرد، نوبت ثبت کند. مدل فقط نام تابع و آرگومان‌ها را پیشنهاد می‌دهد؛ اجرای تابع کار برنامهٔ شماست و نتیجه را به مدل برمی‌گردانید تا پاسخ نهایی را بنویسد. ایجنت‌ها (Agent) روی همین چرخه ساخته می‌شوند.

چرخهٔ کامل#

  1. ابزارها را تعریف کنید

    نام، توضیح و ورودی هر تابع را با JSON Schema در فیلد tools بفرستید. توضیح خوب مهم‌ترین بخش است؛ مدل از روی آن تصمیم می‌گیرد.

  2. مدل تصمیم می‌گیرد

    اگر ابزاری لازم باشد، پاسخ finish_reason: "tool_calls" و فهرست tool_calls دارد.

  3. تابع را اجرا کنید

    آرگومان‌ها رشتهٔ JSON هستند؛ parse و اعتبارسنجی کنید، بعد تابع خودتان را اجرا کنید.

  4. نتیجه را برگردانید

    پیام assistant همراه tool_calls و برای هر فراخوانی یک پیام role: "tool" با همان tool_call_id بفرستید. مدل پاسخ نهایی را می‌نویسد یا ابزار دیگری می‌خواهد.

import json
from openai import OpenAI

client = OpenAI(base_url="https://gisoo.pro/api/v1", api_key="sk-gisoo-v1-...")

# 1) Describe the functions your program can run.
tools = [{
    "type": "function",
    "function": {
        "name": "get_order_status",
        "description": "Look up the delivery status of a customer's order by its number.",
        "parameters": {
            "type": "object",
            "properties": {
                "order_number": {"type": "string", "description": "Order number, e.g. BK-10492"}
            },
            "required": ["order_number"],
            "additionalProperties": False,
        },
    },
}]

def get_order_status(order_number: str) -> dict:
    # your real database lookup goes here
    return {"order_number": order_number, "status": "shipped", "eta": "2 days"}

messages = [
    {"role": "system", "content": "You are a bookshop support agent. Reply in Persian."},
    {"role": "user", "content": "Where is my order BK-10492?"},
]

# 2) Let the model decide whether to call a tool.
first = client.chat.completions.create(model="gpt-4o-mini", messages=messages, tools=tools)
msg = first.choices[0].message

if msg.tool_calls:
    messages.append(msg)                          # keep the assistant turn with its tool_calls
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)  # validate before trusting it
        result = get_order_status(**args)
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": json.dumps(result, ensure_ascii=False),
        })

    # 3) Send the results back; the model writes the final answer.
    final = client.chat.completions.create(model="gpt-4o-mini", messages=messages, tools=tools)
    print(final.choices[0].message.content)
else:
    print(msg.content)

پاسخی که ابزار می‌خواهد#

JSON finish_reason: tool_calls
{
  "choices": [{
    "index": 0,
    "finish_reason": "tool_calls",
    "message": {
      "role": "assistant",
      "content": null,
      "tool_calls": [{
        "id": "call_Q7wPz1",
        "type": "function",
        "function": { "name": "get_order_status", "arguments": "{\"order_number\":\"BK-10492\"}" }
      }]
    }
  }]
}
  • arguments یک رشته است، نه شیء. همیشه parse کنید و اگر معتبر نبود، خطا را به‌عنوان نتیجهٔ ابزار به مدل برگردانید تا اصلاحش کند.
  • مدل ممکن است در یک پاسخ چند ابزار را با هم بخواهد (Parallel Tool Calls). برای هر کدام یک پیام tool جدا بفرستید. برای خاموش کردنش "parallel_tool_calls": false بفرستید.

کنترل انتخاب ابزار#

متن tool_choice
{ "tool_choice": "auto" }                                              // default: model decides
{ "tool_choice": "none" }                                              // never call a tool
{ "tool_choice": "required" }                                          // must call some tool
{ "tool_choice": {"type": "function", "function": {"name": "get_order_status"}} }  // this one

کدام مدل‌ها ابزار می‌پذیرند#

مدل‌هایی که capabilities.tools آن‌ها true است. مدل‌های بزرگ OpenAI، Claude، Gemini و DeepSeek این قابلیت را دارند؛ برای هر مدل دیگر همین فیلد را ببینید. قالب درخواست برای همه یکی است و تفاوت‌های هر سازنده در گیسو یکسان می‌شود:

  • Gemini: Gemini برای هر فراخوانی ابزار یک امضای فکر (thought signature) می‌سازد و بدون آن نوبت بعدی را رد می‌کند؛ SDKهای معمولی آن را برنمی‌گردانند. گیسو امضا را خودش اضافه می‌کند، پس چرخهٔ ابزار با Gemini هم با همین کد کار می‌کند.
  • Claude: با همین قالب OpenAI و از همین endpoint صدا زده می‌شود؛ لازم نیست قالب Anthropic را یاد بگیرید.
  • مدل‌های کوچک: در انتخاب ابزار و ساختن آرگومان دقت کمتری دارند. برای ایجنت جدی، مدل بزرگ‌تر یا tool_choice صریح بهتر جواب می‌دهد.

ایمنی#

به آرگومان‌ها اعتماد نکنید

آرگومان‌ها را مدل ساخته و متن کاربر روی آن اثر دارد. هر ابزاری که پول جابه‌جا می‌کند، چیزی را پاک می‌کند یا به داده‌ای دسترسی دارد، باید سمت برنامهٔ شما دوباره اعتبارسنجی و دسترسی‌سنجی شود؛ مثلاً فقط سفارش‌های همان کاربری را نشان دهید که وارد شده است.

  • تعداد دورهای ابزار را محدود کنید (مثلاً حداکثر ۵ بار در یک پرسش) تا یک حلقهٔ بی‌پایان اعتبار را خرج نکند.
  • نتیجهٔ ابزار را کوتاه نگه دارید؛ هرچه برگردانید، در درخواست بعدی توکن ورودی حساب می‌شود.
  • برای آزمودن هزینهٔ ایجنت، سقف هزینه روی کلید بگذارید.

پاسخ پرسشتان را پیدا نکردید؟

شناسهٔ درخواست (هدر X-Request-Id) را با پرسشتان در تیکت بفرستید تا دقیق بررسی کنیم.

تیکت پشتیبانی