דילוג לתוכן
קריאת פונקציות

קריאת פונקציות

תארו את הפונקציות שלכם בבקשה והמודל משיב עם הקריאות שהוא רוצה שיבוצעו. הקוד שלכם מריץ אותן ושולח את התוצאות בחזרה: ה-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 אתם הוסיפו ל-messages את הודעת ה-assistant והודעת tool אחת לכל קריאה, ושלחו שוב את הבקשה עם אותו 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" בראשו. ראו מילות מפתח של הסכמה בהמשך.

לכל endpoint יש איות משלו לכלי. שלחו את זה ששייך ל-endpoint שאליו אתם קוראים:

{
  "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" התשובה קוראת לפחות לכלי אחד. מודלי open-weight מתארחים
{"type": "function", "function": {"name": "get_weather"}} התשובה קוראת לפונקציה הזו. השם חייב להיות אחת הפונקציות ב-tools. קריאות לפונקציות אחרות מושמטות מהתשובה. מודלי open-weight מתארחים

מודלי 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 כשהתשובה מכילה קריאות בלבד. מודלי ה-open-weight המתארחים יכולים להחזיר טקסט לצד הקריאות; מודלי 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 משלה, בבקשה הבאה.

מודלי ה-open-weight המתארחים מחזירים כל קריאה ייחודית פעם אחת: שתי קריאות עם אותו שם ואותם ארגומנטים מגיעות כקריאה אחת.

קריאות לכלים ב-streaming

עם stream: true, קריאה מגיעה בחתיכה אחת: ה-chunk מכיל את מחרוזת arguments השלמה, ולכן אין שברים לחבר. index סופר את הקריאות של התור החל מ-0.

data: chunk אחד, מעוצב
{
  "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
    }
  ]
}
Endpoint מה מגיע
/v1/chat/completions chat.completion.chunk אחד לכל קריאה, עם הקריאה ב-delta.tool_calls[0]. ה-chunk האחרון נושא 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, בקשה ב-streaming שנושאת tools מוסרת את טקסט התשובה שלה ב-delta אחד של content בסוף התור. הזרמה

שליחת תוצאות בחזרה

הבקשה השנייה חוזרת על השיחה ומוסיפה שני דברים: תור ה-assistant שביקש את הקריאות, ותוצאה אחת לכל קריאה.

{
  "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\"}"
    }
  ]
}
  • שלחו את תור ה-assistant בחזרה כפי שקיבלתם אותו, לפני התוצאות. כל תוצאה מותאמת לקריאה שלה לפי מזהה: 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 הוא מחרוזת או רשימה של בלוקי טקסט.
  • בתור ה-assistant, function.arguments נשאר מחרוזת JSON, בדיוק כפי שהגיע.
  • השיחה יכולה להסתיים בתוצאה של כלי. אין צורך בהודעת משתמש חדשה: המודל ממשיך מהתוצאה.
  • כשהפונקציה שלכם נכשלת, שלחו את הכשל כטקסט התוצאה. המודל יכול אז לדווח עליו או לבקש קריאה אחרת.

מילות מפתח של הסכמה

parameters (input_schema ב-/v1/messages) הוא JSON Schema. משפחת Shannon 3 (shannon-3, shannon-3-pro, shannon-3.1, shannon-3.1-pro) ומודלי ה-open-weight המתארחים מקבלים אותו כפי שאתם שולחים אותו.

shannon-1.6-lite, shannon-1.6-pro, shannon-2-lite, shannon-2-pro ו-shannon-coder-1 מקבלים את תת-הקבוצה הזו, בשלושת ה-endpoints:

טיפול מילות מפתח
נקרא כפי שנשלח כל מילת מפתח שאינה נזכרת בשורות שלהלן, למשל 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 משתמשים ב-temperature ברירת מחדל של 0.2. שלחו 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".

המודל כותב את הארגומנטים. בדקו אותם מול הסכמה שלכם לפני שאתם מריצים את הפונקציה, כמו שבודקים כל קלט חיצוני.

שגיאות אימות, יתרה ושרת זהות לאלה של כל בקשה. טיפול בשגיאות