فراخوانی ابزار (Function Calling) یعنی مدل بهجای جواب دادن از حافظهٔ خودش، از برنامهٔ شما بخواهد تابعی را اجرا کند: وضعیت سفارش را از پایگاه دادهٔ شما بخواند، قیمت روز را بگیرد، نوبت ثبت کند. مدل فقط نام تابع و آرگومانها را پیشنهاد میدهد؛ اجرای تابع کار برنامهٔ شماست و نتیجه را به مدل برمیگردانید تا پاسخ نهایی را بنویسد. ایجنتها (Agent) روی همین چرخه ساخته میشوند.
چرخهٔ کامل#
- ابزارها را تعریف کنید
نام، توضیح و ورودی هر تابع را با JSON Schema در فیلد
toolsبفرستید. توضیح خوب مهمترین بخش است؛ مدل از روی آن تصمیم میگیرد. - مدل تصمیم میگیرد
اگر ابزاری لازم باشد، پاسخ
finish_reason: "tool_calls"و فهرستtool_callsدارد. - تابع را اجرا کنید
آرگومانها رشتهٔ JSON هستند؛ parse و اعتبارسنجی کنید، بعد تابع خودتان را اجرا کنید.
- نتیجه را برگردانید
پیام 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)
const 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" } },
required: ["order_number"],
additionalProperties: false,
},
},
}];
const messages = [
{ role: "system", content: "You are a bookshop support agent. Reply in Persian." },
{ role: "user", content: "Where is my order BK-10492?" },
];
const first = await client.chat.completions.create({ model: "gpt-4o-mini", messages, tools });
const msg = first.choices[0].message;
if (msg.tool_calls?.length) {
messages.push(msg);
for (const call of msg.tool_calls) {
const args = JSON.parse(call.function.arguments);
const result = await getOrderStatus(args.order_number); // your code
messages.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify(result) });
}
const final = await client.chat.completions.create({ model: "gpt-4o-mini", messages, tools });
console.log(final.choices[0].message.content);
} else {
console.log(msg.content);
}
curl https://gisoo.pro/api/v1/chat/completions \
-H "Authorization: Bearer $GISOO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "Where is my order BK-10492?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_order_status",
"description": "Look up the delivery status of an order",
"parameters": {
"type": "object",
"properties": {"order_number": {"type": "string"}},
"required": ["order_number"]
}
}
}]
}'
پاسخی که ابزار میخواهد#
{
"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": "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) را با پرسشتان در تیکت بفرستید تا دقیق بررسی کنیم.