Function calling
Beschrijf je functies in de aanvraag en het model antwoordt met de calls die het wil laten uitvoeren. Jouw code voert ze uit en stuurt de resultaten terug: de API geeft toolcalls terug en voert zelf geen tool uit.
POST https://api.shannon-ai.com/v1/chat/completions
De voorbeelden op deze pagina gebruiken /v1/chat/completions. Dezelfde loop werkt op /v1/responses en /v1/messages; waar een formaat iets anders schrijft, tonen de onderstaande secties alle drie.
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) import OpenAI from "openai";
const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.shannon-ai.com/v1" });
const 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"],
},
},
}];
// Your code: ask a weather service here.
function getWeather({ city, unit = "celsius" }) {
return { city, temperature: 18, unit, conditions: "cloudy" };
}
const messages = [{ role: "user", content: "What is the weather in Paris right now?" }];
let answer = null;
// The API sets no limit on rounds: set your own.
for (let round = 0; round < 5; round++) {
const response = await client.chat.completions.create({
model: "Kimi-K3-3BIT-REAP",
messages,
tools,
});
const choice = response.choices[0];
if (choice.finish_reason !== "tool_calls") {
answer = choice.message.content;
break;
}
messages.push(choice.message); // the assistant turn with its tool_calls
for (const call of choice.message.tool_calls) {
const args = JSON.parse(call.function.arguments); // arguments is a JSON string
messages.push({
role: "tool",
tool_call_id: call.id,
content: JSON.stringify(getWeather(args)),
});
}
}
console.log(answer); # 1. Send the conversation with the tools.
curl https://api.shannon-ai.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "Kimi-K3-3BIT-REAP",
"messages": [
{"role": "user", "content": "What is the weather in Paris right now?"}
],
"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"]
}
}
}]
}'
# 2. Run the function yourself, then send the assistant turn and the result.
# Use the id of the call you received.
curl https://api.shannon-ai.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "Kimi-K3-3BIT-REAP",
"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\"}"}
],
"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"]
}
}
}]
}' Het eerste antwoord beantwoordt de vraag niet. Het vraagt om een call:
{
"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}
}
} Nadat je het resultaat hebt verstuurd, is het volgende antwoord een gewoon antwoord: message.content bevat de tekst en finish_reason is stop.
De loop, stap voor stap
| Stap | Wie | Wat er gebeurt |
|---|---|---|
| 1 | Jij | Stuur messages samen met tools, de lijst met functies waarom het model mag vragen. |
| 2 | Model | Het antwoord bevat tool_calls en finish_reason: "tool_calls". Elke call noemt een functie en geeft de argumenten. |
| 3 | Jij | Parse de arguments van elke call en voer je functie uit. |
| 4 | Jij | Voeg het assistant-bericht en één tool-bericht per call toe aan messages en verstuur de aanvraag opnieuw met dezelfde tools. |
| 5 | Model | Het model antwoordt in tekst met finish_reason: "stop", of vraagt om meer calls. Ga in dat geval terug naar stap 3. |
Eén aanvraag is één beurt van het model. De API bewaart geen gesprek tussen aanvragen en bepaalt geen aantal rondes: jouw code houdt messages bij en beslist wanneer te stoppen.
Tools definiëren
tools is een array met één item per functie. Elk model uit de catalogus accepteert het; GET /v1/models meldt voor elk id capabilities.tools: true.
| Veld | Type | Beschrijving |
|---|---|---|
type | string | Altijd function. |
function.name | string | De naam die het model gebruikt als het om deze functie vraagt. Verplicht. |
function.description | string | Wat de functie doet, in gewone taal. |
function.parameters | object | De argumenten als JSON Schema met bovenaan type: "object". Zie Schema-keywords hieronder. |
Elk endpoint heeft zijn eigen schrijfwijze voor een tool. Stuur die van het endpoint dat je aanroept:
{
"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"]
}
}
} {
"type": "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"]
}
} {
"name": "get_weather",
"description": "Get the current weather for a city.",
"input_schema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "City name, for example Paris"
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["city"]
}
} tool_choice
tool_choice bepaalt of het model een tool mag of moet aanroepen. Het wordt alleen samen met tools gelezen.
| Waarde | Beschrijving | Toegepast door |
|---|---|---|
"auto" | Het model beslist of het in tekst antwoordt of een tool aanroept. Dit is de standaard. | Alle modellen |
"required" | Het antwoord roept ten minste één tool aan. | Gehoste open-weight modellen |
{"type": "function", "function": {"name": "get_weather"}} | Het antwoord roept deze functie aan. De naam moet een van de functies in tools zijn. Calls naar andere functies worden uit het antwoord weggelaten. | Gehoste open-weight modellen |
De Shannon-modellen (shannon-*) beslissen bij elke aanvraag zelf, zoals bij auto.
Lees bij required of een benoemde functie finish_reason voordat je tool_calls leest. Als het model geen call produceert, is het antwoord een tekstantwoord met finish_reason: "stop".
| Betekenis | /v1/chat/completions | /v1/responses | /v1/messages |
|---|---|---|---|
| Het model beslist | "auto" | "auto" | {"type": "auto"} |
| Ten minste één tool aanroepen | "required" | "required" | {"type": "any"} |
| Eén benoemde functie aanroepen | {"type": "function", "function": {"name": "get_weather"}} | {"type": "function", "name": "get_weather"} | {"type": "tool", "name": "get_weather"} |
Geaccepteerd voor compatibiliteit: tool_choice: "none" en parallel_tool_calls. Verstuur voor een beurt zonder toolcalls de aanvraag zonder tools.
Toolcalls in het antwoord
| Veld | Type | Beschrijving |
|---|---|---|
finish_reason | string | tool_calls als het antwoord ten minste één call bevat. |
message.tool_calls | array | Eén item per call. Het veld is alleen aanwezig als het model om een call vroeg. |
tool_calls[].id | string | call_ gevolgd door 32 hexadecimale tekens. Stuur het terug als tool_call_id met het resultaat. |
tool_calls[].type | string | Altijd function. |
tool_calls[].function.name | string | De functie die moet worden uitgevoerd. |
tool_calls[].function.arguments | string | De argumenten als JSON-string, "{}" als er geen zijn. Parse ze voor gebruik. |
message.content | string | null | null als het antwoord alleen calls bevat. De gehoste open-weight modellen kunnen tekst naast de calls teruggeven; de Shannon-modellen geven null terug. |
Dezelfde call in elk formaat. Op /v1/responses is het een function_call-item van output, met arguments als JSON-string. Op /v1/messages is het een tool_use-contentblok waarvan input een JSON-object is, waarvan de id met toolu_ begint en waarvan stop_reason tool_use is.
{
"finish_reason": "tool_calls",
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_9f1c2ab34d5e4f60a7b8c9d0e1f2a3b4",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
}
} {
"output": [
{
"id": "fc_3d2c1b0a9f8e4d7c6b5a4f3e2d1c0b9a",
"type": "function_call",
"call_id": "call_9f1c2ab34d5e4f60a7b8c9d0e1f2a3b4",
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}",
"status": "completed"
}
]
} {
"stop_reason": "tool_use",
"content": [
{
"type": "tool_use",
"id": "toolu_9f1c2ab34d5e4f60a7b8c9d0e1f2a3b4",
"name": "get_weather",
"input": {"city": "Paris"}
}
]
} Meerdere calls in één beurt
Een antwoord kan meerdere calls bevatten. Voer ze allemaal uit en stuur in de volgende aanvraag één resultaat per call, elk met zijn eigen tool_call_id.
De gehoste open-weight modellen geven elke unieke call één keer terug: twee calls met dezelfde naam en dezelfde argumenten komen als één binnen.
Gestreamde toolcalls
Met stream: true komt een call in één stuk binnen: de chunk bevat de complete arguments-string, dus er zijn geen fragmenten om samen te voegen. index telt de calls van de beurt vanaf 0.
{
"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 | Wat binnenkomt |
|---|---|
/v1/chat/completions | Eén chat.completion.chunk per call, met de call in delta.tool_calls[0]. De laatste chunk heeft finish_reason: "tool_calls" en usage. |
/v1/responses | Per call: response.output_item.added (een function_call-item met lege arguments), response.function_call_arguments.delta (de hele string), response.function_call_arguments.done, response.output_item.done. |
/v1/messages | Per call: content_block_start (een tool_use-blok met lege input), één content_block_delta waarvan input_json_delta.partial_json de hele argumententekst is, content_block_stop. message_delta bevat daarna stop_reason: "tool_use". |
Op shannon-1.6-lite, shannon-1.6-pro, shannon-2-lite, shannon-2-pro en shannon-coder-1 levert een gestreamde aanvraag met tools de antwoordtekst in één content-delta aan het einde van de beurt. Streaming
Resultaten terugsturen
De tweede aanvraag herhaalt het gesprek en voegt twee dingen toe: de assistant-beurt die om de calls vroeg, en één resultaat per call.
{
"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\"}"
}
]
} {
"input": [
{"role": "user", "content": "What is the weather in Paris right now?"},
{
"type": "function_call",
"call_id": "call_9f1c2ab34d5e4f60a7b8c9d0e1f2a3b4",
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
},
{
"type": "function_call_output",
"call_id": "call_9f1c2ab34d5e4f60a7b8c9d0e1f2a3b4",
"output": "{\"city\":\"Paris\",\"temperature\":18,\"unit\":\"celsius\",\"conditions\":\"cloudy\"}"
}
]
} {
"messages": [
{"role": "user", "content": "What is the weather in Paris right now?"},
{
"role": "assistant",
"content": [
{
"type": "tool_use",
"id": "toolu_9f1c2ab34d5e4f60a7b8c9d0e1f2a3b4",
"name": "get_weather",
"input": {"city": "Paris"}
}
]
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_9f1c2ab34d5e4f60a7b8c9d0e1f2a3b4",
"content": "{\"city\":\"Paris\",\"temperature\":18,\"unit\":\"celsius\",\"conditions\":\"cloudy\"}"
}
]
}
]
} - Stuur de assistant-beurt terug zoals je hem hebt ontvangen, vóór de resultaten. Elk resultaat wordt op id aan zijn call gekoppeld:
tool_call_idop/v1/chat/completions,call_idop/v1/responses,tool_use_idop/v1/messages. - Een resultaat is tekst. Serialiseer een object naar een JSON-string voor
content(outputop/v1/responses). Op/v1/messagesis decontentvan eentool_result-blok een string of een lijst met tekstblokken. - In de assistant-beurt blijft
function.argumentseen JSON-string, precies zoals hij binnenkwam. - Het gesprek mag eindigen met een toolresultaat. Een nieuw gebruikersbericht is niet nodig: het model gaat verder vanaf het resultaat.
- Als je functie mislukt, stuur de fout dan als resultaattekst. Het model kan die dan melden of om een andere call vragen.
Schema-keywords
parameters (input_schema op /v1/messages) is een JSON Schema. De Shannon 3-familie (shannon-3, shannon-3-pro, shannon-3.1, shannon-3.1-pro) en de gehoste open-weight modellen ontvangen het zoals je het verstuurt.
shannon-1.6-lite, shannon-1.6-pro, shannon-2-lite, shannon-2-pro en shannon-coder-1 ontvangen deze subset, op alle drie de endpoints:
| Behandeling | Keywords |
|---|---|
| Gelezen zoals verstuurd | Elk keyword dat niet in de onderstaande rijen wordt genoemd, bijvoorbeeld type, properties, required, items, enum, description, minimum, maximum, anyOf en allOf, op elk niveau van het schema. |
format | Gelezen voor de waarden int32, int64, float, double, byte, date, date-time en enum. |
oneOf | Gelezen als anyOf. |
| Geen onderdeel van het schema dat deze modellen ontvangen | $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 en exclusiveMaximum als het getallen zijn; andere waarden van format. |
Gedrag en limieten
- De API stelt geen maximumaantal tools en geen maximumaantal rondes in.
- Een request-body mag tot 32 MiB groot zijn, en het gesprek met de resultaten moet in het contextvenster van het model passen.
- Als een aanvraag
toolsbevat, gebruikenshannon-1.6-lite,shannon-1.6-pro,shannon-2-liteenshannon-2-proeen standaard-temperaturevan 0.2. Stuurtemperaturemee om een andere waarde in te stellen. - Elke ronde is een eigen aanvraag: ze gebruikt je saldo en telt mee voor flood protection zoals elke andere aanvraag. Limieten en saldo
Fouten
Een toolcall is een normaal antwoord met status 200. Deze fouten betreffen de aanvraag zelf:
| Status | Type | Bericht | Wanneer |
|---|---|---|---|
400 | invalid_request_error | unknown model: <id> | model is geen id uit de gepubliceerde lijst. |
422 | invalid_request_error | Failed to deserialize the JSON body into the target type: … | tools is geen array, of een ander veld heeft het verkeerde JSON-type. |
413 | invalid_request_error | Failed to buffer the request body: … | De request-body is groter dan 32 MiB. De fout bevat code: "request_too_large". |
Het model schrijft de argumenten. Controleer ze aan de hand van je schema voordat je de functie uitvoert, zoals je elke externe input zou controleren.
Authenticatie-, saldo- en serverfouten zijn hetzelfde als bij elke aanvraag. Foutafhandeling