فراخوانی ابزار ها

معرفی فراخوانی ابزار

فراخوانی ابزار (Tool Calling) یکی از قدرتمندترین قابلیت‌های مدل‌های هوش مصنوعی است که به مدل امکان استفاده از توابع و ابزارهای خارجی را می‌دهد. این قابلیت به مدل اجازه می‌دهد که علاوه بر تولید متن، بتواند عملیات‌های پیچیده‌تری انجام دهد.

با استفاده از این قابلیت، شما می‌توانید مدل را قادر سازید تا اطلاعات آب و هوا دریافت کند، محاسبات ریاضی انجام دهد، با پایگاه‌های داده تعامل کند، یا هر عملیات دیگری که به‌صورت تابع تعریف کرده‌اید را اجرا نماید.

نمونه‌های بدنهٔ درخواست

فراخوانی ابزار در خاتش شامل سه گام کلیدی است. در ادامه فرمت‌های ضروری بدنهٔ درخواست برای هر گام آورده شده است.

گام ۱: درخواست استنتاج همراه ابزارها

Step 1
{  "model": "openai/gpt-4o-mini",  "messages": [    {      "role": "user",      "content": "What are the titles of some James Joyce books?"    }  ],  "tools": [    {      "type": "function",      "function": {        "name": "search_gutenberg_books",        "description": "Search for books in the Project Gutenberg library",        "parameters": {          "type": "object",          "properties": {            "search_terms": {              "type": "array",              "items": {"type": "string"},              "description": "List of search terms to find books"            }          },          "required": ["search_terms"]        }      }    }  ]}

گام ۲: اجرای ابزار (سمت کلاینت)

Step 2 (Python)
# Model responds with tool_calls, you execute the tool locallytool_result = await search_gutenberg_books(["James", "Joyce"])

گام ۳: درخواست استنتاج با نتایج ابزار

Step 3
{  "model": "openai/gpt-4o-mini",  "messages": [    {      "role": "user",      "content": "What are the titles of some James Joyce books?"    },    {      "role": "assistant",      "content": null,      "tool_calls": [        {          "id": "call_abc123",          "type": "function",          "function": {            "name": "search_gutenberg_books",            "arguments": "{"search_terms": ["James", "Joyce"]}"          }        }      ]    },    {      "role": "tool",      "tool_call_id": "call_abc123",      "content": "[{"id": 4300, "title": "Ulysses", "authors": [{"name": "Joyce, James"}]}]"    }  ],  "tools": [    {      "type": "function",      "function": {        "name": "search_gutenberg_books",        "description": "Search for books in the Project Gutenberg library",        "parameters": {          "type": "object",          "properties": {            "search_terms": {              "type": "array",              "items": {"type": "string"},              "description": "List of search terms to find books"            }          },          "required": ["search_terms"]        }      }    }  ]}

نکته: پارامتر tools باید در هر درخواست (گام‌های ۱ و ۳) گنجانده شود تا روتر بتواندschema ابزار را در هر فراخوانی اعتبارسنجی کند.

مثال کامل (پایتون)

در این مثال، با استفاده از کتابخانهٔ OpenAI و تنظیم base_url روی خاتش، به مدل امکان استفاده از ابزار جستجوی کتاب در گوتنبرگ داده می‌شود.

setup.py
import json, requestsfrom openai import OpenAIKHATASH_API_KEY = f"<KHATASH_API_KEY>"# You can use any model that supports tool callingMODEL = "openai/gpt-4o-mini"openai_client = OpenAI(  base_url="https://ai.khatash.com/api/v1",  api_key=KHATASH_API_KEY,)task = "What are the titles of some James Joyce books?"messages = [  {    "role": "system",    "content": "You are a helpful assistant."  },  {    "role": "user",    "content": task,  }]
tool_definition.py
def search_gutenberg_books(search_terms):    search_query = " ".join(search_terms)    url = "https://gutendex.com/books"    response = requests.get(url, params={"search": search_query})    simplified_results = []    for book in response.json().get("results", []):        simplified_results.append({            "id": book.get("id"),            "title": book.get("title"),            "authors": book.get("authors")        })    return simplified_resultstools = [  {    "type": "function",    "function": {      "name": "search_gutenberg_books",      "description": "Search for books in the Project Gutenberg library based on specified search terms",      "parameters": {        "type": "object",        "properties": {          "search_terms": {            "type": "array",            "items": {"type": "string"},            "description": "List of search terms to find books in the Gutenberg library"          }        },        "required": ["search_terms"]      }    }  }]TOOL_MAPPING = {    "search_gutenberg_books": search_gutenberg_books}
tool_use.py
# First callrequest_1 = {  "model": MODEL,  "tools": tools,  "messages": messages}response_1 = openai_client.chat.completions.create(**request_1).choices[0].message# Append assistant message so the model has full contextmessages.append(response_1)# Process requested tool callsfor tool_call in (response_1.tool_calls or []):    tool_name = tool_call.function.name    tool_args = json.loads(tool_call.function.arguments)    tool_response = TOOL_MAPPING[tool_name](**tool_args)    messages.append({      "role": "tool",      "tool_call_id": tool_call.id,      "content": json.dumps(tool_response),    })# Second call with tool resultsrequest_2 = {  "model": MODEL,  "messages": messages,  "tools": tools,}response_2 = openai_client.chat.completions.create(**request_2)print(response_2.choices[0].message.content)

تفکر درهم‌آمیخته (Interleaved Thinking)

با تفکر درهم‌آمیخته، مدل می‌تواند بین فراخوانی‌های ابزار استدلال کند و بر اساس نتایج میانی تصمیم‌های دقیق‌تری بگیرد. توجه کنید که فعال‌سازی این قابلیت می‌تواند مصرف token و زمان پاسخ را افزایش دهد.

initial_request.json
{  "model": "anthropic/claude-3.5-sonnet",  "messages": [    {      "role": "user",      "content": "Research the environmental impact of electric vehicles and provide a comprehensive analysis."    }  ],  "tools": [    {      "type": "function",      "function": {        "name": "search_academic_papers",        "description": "Search for academic papers on a given topic",        "parameters": {          "type": "object",          "properties": {            "query": {"type": "string"},            "field": {"type": "string"}          },          "required": ["query"]        }      }    },    {      "type": "function",      "function": {        "name": "get_latest_statistics",        "description": "Get latest statistics on a topic",        "parameters": {          "type": "object",          "properties": {            "topic": {"type": "string"},            "year": {"type": "integer"}          },          "required": ["topic"]        }      }    }  ]}

حلقهٔ عامل ساده

agentic_loop.py
import jsondef call_llm(msgs):    resp = openai_client.chat.completions.create(        model=MODEL,        tools=tools,        messages=msgs,    )    msgs.append(resp.choices[0].message.dict())    return respdef get_tool_response(response):    tool_call = response.choices[0].message.tool_calls[0]    tool_name = tool_call.function.name    tool_args = json.loads(tool_call.function.arguments)    tool_result = TOOL_MAPPING[tool_name](**tool_args)    return {        "role": "tool",        "tool_call_id": tool_call.id,        "content": json.dumps(tool_result),    }max_iterations = 10iteration_count = 0while iteration_count < max_iterations:    iteration_count += 1    resp = call_llm(messages)    if resp.choices[0].message.tool_calls is not None:        messages.append(get_tool_response(resp))    else:        breakif iteration_count >= max_iterations:    print("Warning: Maximum iterations reached")print(messages[-1]["content"])

راهنمای تعریف توابع

از نام‌های شفاف، توضیحات جامع و پارامترهای ساخت‌یافته استفاده کنید.

function_spec.json
{  "type": "function",  "function": {    "name": "get_weather_forecast",    "description": "Get current weather conditions and 5-day forecast for a specific location. Supports cities, zip codes, and coordinates.",    "parameters": {      "type": "object",      "properties": {        "location": {          "type": "string",          "description": "City name, zip code, or coordinates (lat,lng). Examples: 'New York', '10001', '40.7128,-74.0060'"        },        "units": {          "type": "string",          "enum": ["celsius", "fahrenheit"],          "description": "Temperature unit preference",          "default": "celsius"        }      },      "required": ["location"]    }  }}

استریم در فراخوانی ابزارها (پایتون)

هنگام استفاده از استریم همراه با فراخوانی ابزار، انواع محتوای دریافتی را به‌درستی مدیریت کنید:

  • توکن‌های متن: هرگاه delta.content وجود داشت، آن را به خروجی متنی جاری اضافه و رندر کنید.
  • فراخوانی ابزار: وقتی delta.tool_calls رسید، آیتم‌ها را تجمیع کنید. مقدار arguments در function به‌صورت تکه‌تکه می‌آید و باید به‌صورت رشته به هم چسبانده شود.
  • پایان با tool_calls: اگر finish_reason برابر «tool_calls» شد، استریم متن را موقتاً متوقف کنید، ابزارها را اجرا کنید و پیام‌های نقش tool را با tool_call_id متناظر اضافه کنید، سپس درخواست بعدی را با نتایج ارسال کنید.
  • پایان با stop: وقتی «stop» دریافت شد، استریم کامل است و می‌توانید رندر را خاتمه دهید.
  • همگام‌سازی: نتایج ابزار ممکن است خارج از ترتیب برسند؛ برای نگاشت صحیح هر نتیجه به فراخوان مربوطه از tool_call_id استفاده کنید.
streaming.py
import jsonimport requestsurl = "https://ai.khatash.com/api/v1/chat/completions"headers = {"Authorization": f"Bearer {KHATASH_API_KEY}", "Content-Type": "application/json"}payload = {    "model": MODEL,    "messages": messages,    "tools": tools,    "stream": True,}with requests.post(url, headers=headers, json=payload, stream=True) as resp:    resp.raise_for_status()    tool_calls = []    for line in resp.iter_lines(decode_unicode=True):        if not line:            continue        if line.startswith('data: '):            data = json.loads(line[6:])            delta = data.get('choices', [{}])[0].get('delta', {})            if 'tool_calls' in delta:                tool_calls.extend(delta['tool_calls'])            if delta.get('finish_reason') == 'tool_calls':                # handle tool calls here                pass            elif delta.get('finish_reason') == 'stop':                break

پیکربندی tool_choice

auto.json
{ "tool_choice": "auto" }
none.json
{ "tool_choice": "none" }
force.json
{  "tool_choice": {    "type": "function",    "function": {"name": "search_database"}  }}

فراخوانی موازی ابزارها

با پارامتر parallel_tool_calls مشخص می‌کنید که آیا مدل می‌تواند چند ابزار را به‌صورت هم‌زمان فراخوانی کند یا خیر. وقتی این قابلیت فعال باشد، مدل ممکن است در یک پاسخ چندین tool_call موازی پیشنهاد دهد تا زمان کل کار کاهش یابد. اگر آن را غیرفعال کنید، مدل در هر نوبت فقط یک فراخوانی ابزار انجام می‌دهد و تا دریافت نتیجه همان ابزار منتظر می‌ماند (اجرای ترتیبی).

  • پیش‌فرض: مقدار parallel_tool_calls برای بیشتر مدل‌هاtrue است.
  • چه زمانی موازی‌سازی مناسب است؟ وقتی ابزارها مستقل از هم هستند و اجرای هم‌زمان آن‌ها می‌تواند تأخیر را کم کند (مثلاً «جستجو» در چند سرویس).
  • چه زمانی غیرفعال کنیم؟ وقتی بین ابزارها وابستگی ترتیبی وجود دارد (نتیجهٔ ابزار اول ورودی ابزار دوم است) یا با محدودیت نرخ و ظرفیت سرویس‌ها روبه‌رو هستید.
  • اثرات: موازی‌سازی معمولاً زمان پاسخ را کاهش می‌دهد اما می‌تواند بار سیستم و مصرف سهمیهٔ فراخوانی‌ها را افزایش دهد.
  • نکتهٔ پیاده‌سازی: نتایج ابزارها ممکن است خارج از ترتیب برسند؛ برای تطبیق هر پاسخ ابزار با درخواست مربوطه از فیلد tool_call_id استفاده کنید.

نمونهٔ زیر نحوهٔ غیرفعال‌سازی موازی‌سازی را نشان می‌دهد. در این حالت ابزارها به‌صورت ترتیبی اجرا می‌شوند.

parallel_tool_calls.json
{ "parallel_tool_calls": false }

طراحی جریان‌های چندابزاره

ابزارها را طوری طراحی کنید که بتوانند به‌صورت زنجیره‌ای با هم کار کنند (searchdetailsinventory).

multi_tool_workflow.json
{  "tools": [    {      "type": "function",      "function": {"name": "search_products", "description": "Search for products in the catalog"}    },    {      "type": "function",      "function": {"name": "get_product_details", "description": "Get detailed information about a specific product"}    },    {      "type": "function",      "function": {"name": "check_inventory", "description": "Check current inventory levels for a product"}    }  ]}