Aller au contenu
Appel de fonction

Appel de fonction

Décrivez vos fonctions dans la requête et le modèle répond avec les appels qu'il veut faire. Votre code les exécute et renvoie les résultats : l'API renvoie des appels d'outil et n'exécute aucun outil elle-même.

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

Les exemples de cette page utilisent /v1/chat/completions. La même boucle fonctionne sur /v1/responses et /v1/messages ; là où un format écrit une chose différemment, les sections ci-dessous montrent les trois.

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)

La première réponse ne répond pas à la question. Elle demande un appel :

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}
  }
}

Après l'envoi du résultat, la réponse suivante est une réponse ordinaire : message.content contient le texte et finish_reason vaut stop.

La boucle, étape par étape

Étape Qui Ce qui se passe
1 Vous Envoyez messages avec tools, la liste des fonctions que le modèle peut demander.
2 Modèle La réponse porte tool_calls et finish_reason: "tool_calls". Chaque appel nomme une fonction et donne ses arguments.
3 Vous Analysez les arguments de chaque appel et exécutez votre fonction.
4 Vous Ajoutez à messages le message de l'assistant et un message tool par appel, puis renvoyez la requête avec les mêmes tools.
5 Modèle Le modèle répond par du texte avec finish_reason: "stop", ou demande d'autres appels. Dans ce cas, retournez à l'étape 3.

Une requête est un tour de modèle. L'API ne conserve aucune conversation entre les requêtes et ne fixe aucun nombre de tours : votre code détient messages et décide quand s'arrêter.

Définir les outils

tools est un tableau avec une entrée par fonction. Chaque modèle du catalogue l'accepte ; GET /v1/models indique capabilities.tools: true pour chaque id.

Champ Type Description
type string Toujours function.
function.name string Le nom que le modèle utilise pour demander cette fonction. Obligatoire.
function.description string Ce que fait la fonction, en langage clair.
function.parameters object Les arguments sous forme de JSON Schema avec type: "object" au sommet. Voir Mots-clés du schéma ci-dessous.

Chaque point de terminaison a sa propre écriture d'un outil. Envoyez celle qui correspond au point de terminaison que vous appelez :

{
  "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 indique si le modèle peut, ou doit, appeler un outil. Il n'est lu qu'avec tools.

Valeur Description Appliqué par
"auto" Le modèle décide s'il répond par du texte ou appelle un outil. C'est la valeur par défaut. Tous les modèles
"required" La réponse appelle au moins un outil. Modèles open-weight hébergés
{"type": "function", "function": {"name": "get_weather"}} La réponse appelle cette fonction. Le nom doit être celui d'une des fonctions de tools. Les appels à d'autres fonctions sont retirés de la réponse. Modèles open-weight hébergés

Les modèles Shannon (shannon-*) décident à chaque requête, comme avec auto.

Avec required ou une fonction nommée, lisez finish_reason avant de lire tool_calls. Quand le modèle ne produit aucun appel, la réponse est un texte avec finish_reason: "stop".

Signification /v1/chat/completions /v1/responses /v1/messages
Le modèle décide "auto" "auto" {"type": "auto"}
Appeler au moins un outil "required" "required" {"type": "any"}
Appeler une fonction nommée {"type": "function", "function": {"name": "get_weather"}} {"type": "function", "name": "get_weather"} {"type": "tool", "name": "get_weather"}

Acceptés pour la compatibilité : tool_choice: "none" et parallel_tool_calls. Pour un tour sans appel d'outil, envoyez la requête sans tools.

Appels d'outil dans la réponse

Champ Type Description
finish_reason string tool_calls quand la réponse porte au moins un appel.
message.tool_calls array Une entrée par appel. Le champ n'est présent que si le modèle a demandé un appel.
tool_calls[].id string call_ suivi de 32 caractères hexadécimaux. Renvoyez-le comme tool_call_id avec le résultat.
tool_calls[].type string Toujours function.
tool_calls[].function.name string La fonction à exécuter.
tool_calls[].function.arguments string Les arguments sous forme de chaîne JSON, "{}" s'il n'y en a pas. Analysez-la avant de l'utiliser.
message.content string | null null quand la réponse ne contient que des appels. Les modèles open-weight hébergés peuvent renvoyer du texte à côté des appels ; les modèles Shannon renvoient null.

Le même appel dans chaque format. Sur /v1/responses, c'est un élément function_call de output, avec arguments sous forme de chaîne JSON. Sur /v1/messages, c'est un bloc de contenu tool_use dont input est un objet JSON, son id commence par toolu_, et stop_reason vaut 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\"}"
        }
      }
    ]
  }
}

Plusieurs appels en un tour

Une réponse peut porter plusieurs appels. Exécutez-les tous et envoyez un résultat par appel, chacun avec son propre tool_call_id, dans la requête suivante.

Les modèles open-weight hébergés renvoient chaque appel distinct une seule fois : deux appels avec le même nom et les mêmes arguments arrivent comme un seul.

Appels d'outil en streaming

Avec stream: true, un appel arrive d'un seul bloc : le chunk contient la chaîne arguments complète, il n'y a donc aucun fragment à assembler. index compte les appels du tour à partir de 0.

data : un chunk, mis en forme
{
  "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
    }
  ]
}
Point de terminaison Ce qui arrive
/v1/chat/completions Un chat.completion.chunk par appel, avec l'appel dans delta.tool_calls[0]. Le dernier chunk a finish_reason: "tool_calls" et usage.
/v1/responses Par appel : response.output_item.added (un élément function_call avec des arguments vides), response.function_call_arguments.delta (la chaîne entière), response.function_call_arguments.done, response.output_item.done.
/v1/messages Par appel : content_block_start (un bloc tool_use avec un input vide), un content_block_delta dont input_json_delta.partial_json est tout le texte des arguments, content_block_stop. message_delta porte ensuite stop_reason: "tool_use".

Sur shannon-1.6-lite, shannon-1.6-pro, shannon-2-lite, shannon-2-pro et shannon-coder-1, une requête en streaming qui porte tools livre le texte de sa réponse dans un seul delta content à la fin du tour. Diffusion en continu

Renvoyer les résultats

La deuxième requête répète la conversation et ajoute deux choses : le tour de l'assistant qui a demandé les appels, et un résultat par appel.

{
  "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\"}"
    }
  ]
}
  • Renvoyez le tour de l'assistant tel que vous l'avez reçu, avant les résultats. Chaque résultat est associé à son appel par id : tool_call_id sur /v1/chat/completions, call_id sur /v1/responses, tool_use_id sur /v1/messages.
  • Un résultat est du texte. Sérialisez un objet en chaîne JSON pour content (output sur /v1/responses). Sur /v1/messages, le content d'un bloc tool_result est une chaîne ou une liste de blocs de texte.
  • Dans le tour de l'assistant, function.arguments reste une chaîne JSON, exactement comme elle est arrivée.
  • La conversation peut se terminer par un résultat d'outil. Aucun nouveau message utilisateur n'est nécessaire : le modèle continue à partir du résultat.
  • Quand votre fonction échoue, envoyez l'échec comme texte du résultat. Le modèle peut alors le signaler ou demander un autre appel.

Mots-clés du schéma

parameters (input_schema sur /v1/messages) est un JSON Schema. La famille Shannon 3 (shannon-3, shannon-3-pro, shannon-3.1, shannon-3.1-pro) et les modèles open-weight hébergés le reçoivent tel que vous l'envoyez.

shannon-1.6-lite, shannon-1.6-pro, shannon-2-lite, shannon-2-pro et shannon-coder-1 reçoivent ce sous-ensemble, sur les trois points de terminaison :

Traitement Mots-clés
Lus tels qu'envoyés Tous les mots-clés qui ne sont pas nommés dans les lignes ci-dessous, par exemple type, properties, required, items, enum, description, minimum, maximum, anyOf et allOf, à chaque niveau du schéma.
format Lu pour les valeurs int32, int64, float, double, byte, date, date-time et enum.
oneOf Lu comme anyOf.
Ne fait pas partie du schéma que reçoivent ces modèles $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 et exclusiveMaximum quand ce sont des nombres ; les autres valeurs de format.

Comportement et limites

  • L'API ne fixe ni nombre maximal d'outils ni nombre maximal de tours.
  • Un corps de requête peut atteindre 32 MiB, et la conversation avec ses résultats doit tenir dans la fenêtre de contexte du modèle.
  • Quand une requête porte tools, shannon-1.6-lite, shannon-1.6-pro, shannon-2-lite et shannon-2-pro utilisent une temperature par défaut de 0.2. Envoyez temperature pour définir une autre valeur.
  • Chaque tour est une requête à part entière : il puise dans votre solde et compte pour la protection anti-flood comme toute autre requête. Limites et solde

Erreurs

Un appel d'outil est une réponse normale avec le statut 200. Ces erreurs concernent la requête elle-même :

Statut Type Message Quand
400 invalid_request_error unknown model: <id> model n'est pas un id de la liste publiée.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … tools n'est pas un tableau, ou un autre champ a un mauvais type JSON.
413 invalid_request_error Failed to buffer the request body: … Le corps de la requête dépasse 32 MiB. L'erreur porte code: "request_too_large".

Le modèle écrit les arguments. Vérifiez-les par rapport à votre schéma avant d'exécuter la fonction, comme pour toute entrée extérieure.

Les erreurs d'authentification, de solde et de serveur sont les mêmes que pour toute requête. Gestion des erreurs