تخطَّ إلى المحتوى
استدعاء الدوال

استدعاء الدوال

صِف دوالك في الطلب فيرد النموذج بالاستدعاءات التي يريد تنفيذها. وتشغّلها شيفرتك وترسل النتائج مرة أخرى: تعيد API استدعاءات الأدوات ولا تشغّل أي أداة بنفسها.

POST https://api.shannon-ai.com/v1/chat/completions

تستخدم الأمثلة في هذه الصفحة /v1/chat/completions. وتعمل الحلقة نفسها على /v1/responses و/v1/messages؛ وحيث تكتب صيغة ما شيئاً بشكل مختلف، تعرض الأقسام أدناه الصيغ الثلاث.

import json
from openai import OpenAI

client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.shannon-ai.com/v1")

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get the current weather for a city.",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "City name, for example Paris"},
                "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
            },
            "required": ["city"],
        },
    },
}]

def get_weather(city, unit="celsius"):
    # Your code: ask a weather service here.
    return {"city": city, "temperature": 18, "unit": unit, "conditions": "cloudy"}

messages = [{"role": "user", "content": "What is the weather in Paris right now?"}]
answer = None

for _ in range(5):  # the API sets no limit on rounds: set your own
    response = client.chat.completions.create(
        model="Kimi-K3-3BIT-REAP",
        messages=messages,
        tools=tools,
    )
    choice = response.choices[0]
    if choice.finish_reason != "tool_calls":
        answer = choice.message.content
        break

    messages.append(choice.message)  # the assistant turn with its tool_calls
    for call in choice.message.tool_calls:
        args = json.loads(call.function.arguments)  # arguments is a JSON string
        result = get_weather(**args)
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": json.dumps(result),
        })

print(answer)

لا يجيب الرد الأول عن السؤال. بل يطلب استدعاءً:

200 JSON
{
  "id": "chatcmpl-5b0c1d8e7f6a4b3c9d2e1f0a8b7c6d5e",
  "object": "chat.completion",
  "created": 1791590400,
  "model": "Kimi-K3-3BIT-REAP",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "reasoning_content": "The user asks for the current weather in Paris. I should call get_weather.",
        "tool_calls": [
          {
            "id": "call_9f1c2ab34d5e4f60a7b8c9d0e1f2a3b4",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\":\"Paris\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ],
  "usage": {
    "prompt_tokens": 312,
    "completion_tokens": 58,
    "total_tokens": 370,
    "prompt_tokens_details": {"cached_tokens": 0},
    "completion_tokens_details": {"reasoning_tokens": 31}
  }
}

بعد أن ترسل النتيجة، يكون الرد التالي إجابة عادية: يحمل message.content النص وتكون قيمة finish_reason هي stop.

الحلقة، خطوة بخطوة

الخطوة من ما يحدث
1 أنت أرسل messages مع tools، وهي قائمة الدوال التي يجوز للنموذج طلبها.
2 النموذج يحمل الرد tool_calls وfinish_reason: "tool_calls". كل استدعاء يسمّي دالة ويعطي وسائطها.
3 أنت حلّل arguments في كل استدعاء وشغّل دالتك.
4 أنت أضف رسالة المساعد ورسالة tool واحدة لكل استدعاء إلى messages، ثم أعد إرسال الطلب مع tools نفسها.
5 النموذج يجيب النموذج بنص مع finish_reason: "stop"، أو يطلب استدعاءات إضافية. وفي هذه الحالة ارجع إلى الخطوة 3.

الطلب الواحد هو دور واحد للنموذج. لا تحتفظ API بمحادثة بين الطلبات ولا تحدد عدداً للجولات: شيفرتك هي التي تحتفظ بـ messages وتقرر متى تتوقف.

تعريف الأدوات

tools مصفوفة بعنصر واحد لكل دالة. كل نموذج في الفهرس يقبلها؛ ويعرض GET /v1/models القيمة capabilities.tools: true لكل معرّف.

الحقل النوع الوصف
type string دائماً function.
function.name string الاسم الذي يستخدمه النموذج عندما يطلب هذه الدالة. مطلوب.
function.description string ما تفعله الدالة، بلغة واضحة.
function.parameters object الوسائط كـ JSON Schema مع type: "object" في أعلاه. انظر الكلمات المفتاحية للمخطط أدناه.

لكل نقطة نهاية طريقتها الخاصة في كتابة الأداة. أرسل الطريقة التي تخص نقطة النهاية التي تستدعيها:

{
  "type": "function",
  "function": {
    "name": "get_weather",
    "description": "Get the current weather for a city.",
    "parameters": {
      "type": "object",
      "properties": {
        "city": {
          "type": "string",
          "description": "City name, for example Paris"
        },
        "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
      },
      "required": ["city"]
    }
  }
}

tool_choice

يحدد tool_choice ما إذا كان يجوز للنموذج أن يستدعي أداة، أو يجب عليه ذلك. ولا يُقرأ إلا مع tools.

القيمة الوصف يطبّقه
"auto" يقرر النموذج ما إذا كان سيجيب بنص أو يستدعي أداة. هذا هو الافتراضي. جميع النماذج
"required" يستدعي الرد أداة واحدة على الأقل. النماذج المفتوحة الأوزان المستضافة
{"type": "function", "function": {"name": "get_weather"}} يستدعي الرد هذه الدالة. يجب أن يكون الاسم إحدى الدوال في tools. وتُستبعد من الرد الاستدعاءات إلى دوال أخرى. النماذج المفتوحة الأوزان المستضافة

تقرر نماذج Shannon (shannon-*) في كل طلب، كما في auto.

مع required أو دالة مسماة، اقرأ finish_reason قبل أن تقرأ tool_calls. وعندما لا ينتج النموذج استدعاءً، يكون الرد إجابة نصية مع finish_reason: "stop".

المعنى /v1/chat/completions /v1/responses /v1/messages
يقرر النموذج "auto" "auto" {"type": "auto"}
استدعاء أداة واحدة على الأقل "required" "required" {"type": "any"}
استدعاء دالة مسماة واحدة {"type": "function", "function": {"name": "get_weather"}} {"type": "function", "name": "get_weather"} {"type": "tool", "name": "get_weather"}

مقبولان للتوافق: tool_choice: "none" وparallel_tool_calls. وللحصول على دور بلا استدعاءات أدوات، أرسل الطلب من دون tools.

استدعاءات الأدوات في الرد

الحقل النوع الوصف
finish_reason string tool_calls عندما يحمل الرد استدعاءً واحداً على الأقل.
message.tool_calls array عنصر واحد لكل استدعاء. يوجد الحقل فقط عندما يطلب النموذج استدعاءً.
tool_calls[].id string call_ متبوعاً بـ 32 رمزاً سداسياً عشرياً. أعده كـ tool_call_id مع النتيجة.
tool_calls[].type string دائماً function.
tool_calls[].function.name string الدالة المطلوب تشغيلها.
tool_calls[].function.arguments string الوسائط كـ سلسلة JSON، و"{}" عند عدم وجودها. حلّلها قبل الاستخدام.
message.content string | null null عندما يحتوي الرد على استدعاءات فقط. يمكن للنماذج المفتوحة الأوزان المستضافة إعادة نص بجانب الاستدعاءات؛ أما نماذج Shannon فتعيد null.

الاستدعاء نفسه في كل صيغة. على /v1/responses هو عنصر function_call في output، وarguments فيه سلسلة JSON. وعلى /v1/messages هو كتلة محتوى tool_use قيمة input فيها كائن JSON، ويبدأ id فيها بـ toolu_، وقيمة stop_reason هي tool_use.

{
  "finish_reason": "tool_calls",
  "message": {
    "role": "assistant",
    "content": null,
    "tool_calls": [
      {
        "id": "call_9f1c2ab34d5e4f60a7b8c9d0e1f2a3b4",
        "type": "function",
        "function": {
          "name": "get_weather",
          "arguments": "{\"city\":\"Paris\"}"
        }
      }
    ]
  }
}

عدة استدعاءات في دور واحد

يمكن أن يحمل الرد عدة استدعاءات. شغّلها كلها وأرسل نتيجة واحدة لكل استدعاء، لكل منها tool_call_id الخاص بها، في الطلب التالي.

تعيد النماذج المفتوحة الأوزان المستضافة كل استدعاء مختلف مرة واحدة: استدعاءان بالاسم نفسه والوسائط نفسها يصلان كاستدعاء واحد.

استدعاءات الأدوات المبثوثة

مع stream: true يصل الاستدعاء قطعة واحدة: يحمل الجزء سلسلة arguments كاملة، فلا توجد أجزاء مجزأة لتجمعها. ويعدّ index استدعاءات الدور بدءاً من 0.

data: جزء واحد، منسّق
{
  "id": "chatcmpl-5b0c1d8e7f6a4b3c9d2e1f0a8b7c6d5e",
  "object": "chat.completion.chunk",
  "created": 1791590400,
  "model": "Kimi-K3-3BIT-REAP",
  "choices": [
    {
      "index": 0,
      "delta": {
        "tool_calls": [
          {
            "index": 0,
            "id": "call_9f1c2ab34d5e4f60a7b8c9d0e1f2a3b4",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\":\"Paris\"}"
            }
          }
        ]
      },
      "finish_reason": null
    }
  ]
}
نقطة النهاية ما الذي يصل
/v1/chat/completions جزء chat.completion.chunk واحد لكل استدعاء، والاستدعاء في delta.tool_calls[0]. ويحمل الجزء الأخير finish_reason: "tool_calls" وusage.
/v1/responses لكل استدعاء: response.output_item.added (عنصر function_call بقيمة arguments فارغة)، ثم response.function_call_arguments.delta (السلسلة كاملة)، ثم response.function_call_arguments.done، ثم response.output_item.done.
/v1/messages لكل استدعاء: content_block_start (كتلة tool_use بقيمة input فارغة)، وحدث content_block_delta واحد تكون input_json_delta.partial_json فيه نص الوسائط كاملاً، ثم content_block_stop. بعدها يحمل message_delta القيمة stop_reason: "tool_use".

في shannon-1.6-lite وshannon-1.6-pro وshannon-2-lite وshannon-2-pro وshannon-coder-1، يسلّم الطلب المبثوث الذي يحمل tools نص إجابته في دلتا content واحدة في نهاية الدور. البث

إرجاع النتائج

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

{
  "messages": [
    {"role": "user", "content": "What is the weather in Paris right now?"},
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [
        {
          "id": "call_9f1c2ab34d5e4f60a7b8c9d0e1f2a3b4",
          "type": "function",
          "function": {
            "name": "get_weather",
            "arguments": "{\"city\":\"Paris\"}"
          }
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_9f1c2ab34d5e4f60a7b8c9d0e1f2a3b4",
      "content": "{\"city\":\"Paris\",\"temperature\":18,\"unit\":\"celsius\",\"conditions\":\"cloudy\"}"
    }
  ]
}
  • أعد دور المساعد كما استلمته، قبل النتائج. تُطابق كل نتيجة مع استدعائها بالمعرّف: tool_call_id على /v1/chat/completions، وcall_id على /v1/responses، وtool_use_id على /v1/messages.
  • النتيجة نص. حوّل الكائن إلى سلسلة JSON لتضعها في content (output على /v1/responses). وعلى /v1/messages يكون content في كتلة tool_result سلسلة نصية أو قائمة من كتل النص.
  • في دور المساعد، تبقى function.arguments سلسلة JSON، تماماً كما وصلت.
  • يجوز أن تنتهي المحادثة بنتيجة أداة. ولا حاجة إلى رسالة مستخدم جديدة: يواصل النموذج من النتيجة.
  • عندما تفشل دالتك، أرسل الفشل كنص للنتيجة. يمكن للنموذج حينها أن يبلّغ عنه أو يطلب استدعاءً آخر.

الكلمات المفتاحية للمخطط

parameters (input_schema على /v1/messages) هو JSON Schema. تتلقاه عائلة Shannon 3 (shannon-3 وshannon-3-pro وshannon-3.1 وshannon-3.1-pro) والنماذج المفتوحة الأوزان المستضافة كما ترسله.

تتلقى shannon-1.6-lite وshannon-1.6-pro وshannon-2-lite وshannon-2-pro وshannon-coder-1 هذه المجموعة الجزئية، على نقاط النهاية الثلاث:

المعالجة الكلمات المفتاحية
تُقرأ كما أُرسلت كل كلمة مفتاحية غير مسماة في الصفوف أدناه، مثل type وproperties وrequired وitems وenum وdescription وminimum وmaximum وanyOf وallOf، في كل مستوى من المخطط.
format تُقرأ للقيم int32 وint64 وfloat وdouble وbyte وdate وdate-time وenum.
oneOf تُقرأ على أنها anyOf.
ليست جزءاً من المخطط الذي تتلقاه هذه النماذج $schema, $id, $ref, $defs, $comment, definitions, additionalProperties, unevaluatedProperties, patternProperties, propertyNames, examples, default, title, const, not, if, then, else, contains, minContains, maxContains, dependentRequired, dependentSchemas, dependencies, readOnly, writeOnly, deprecated, contentEncoding, contentMediaType, contentSchema, multipleOf, uniqueItems؛ وexclusiveMinimum وexclusiveMaximum عندما تكون أرقاماً؛ وقيم format الأخرى.

السلوك والحدود

  • لا تضع API حداً أقصى لعدد الأدوات ولا لعدد الجولات.
  • يمكن أن يصل نص الطلب إلى 32 MiB، ويجب أن تتسع المحادثة مع نتائجها في نافذة سياق النموذج.
  • عندما يحمل الطلب tools، تستخدم shannon-1.6-lite وshannon-1.6-pro وshannon-2-lite وshannon-2-pro القيمة الافتراضية 0.2 لـ temperature. أرسل temperature لتحديد قيمة أخرى.
  • كل جولة طلب قائم بذاته: يسحب من رصيدك ويُحتسب ضمن الحماية من الإغراق كأي طلب آخر. الحدود والرصيد

الأخطاء

استدعاء الأداة رد عادي بالحالة 200. وتتعلق هذه الأخطاء بالطلب نفسه:

الحالة النوع الرسالة متى
400 invalid_request_error unknown model: <id> model ليس معرّفاً في القائمة المنشورة.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … tools ليست مصفوفة، أو أن نوع JSON لحقل آخر خاطئ.
413 invalid_request_error Failed to buffer the request body: … نص الطلب أكبر من 32 MiB. ويحمل الخطأ code: "request_too_large".

النموذج هو من يكتب الوسائط. تحقق منها بمخططك قبل تشغيل الدالة، كما تتحقق من أي مدخل خارجي.

أخطاء المصادقة والرصيد والخادم هي نفسها في كل طلب. معالجة الأخطاء