함수 호출
요청에 함수를 설명하면 모델이 실행하려는 호출로 응답합니다. 사용자의 코드가 이를 실행하고 결과를 되돌려 보냅니다. 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) 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"]
}
}
}]
}' 첫 번째 응답은 질문에 답하지 않습니다. 호출을 요청합니다:
{
"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 | 사용자 | assistant 메시지와 호출마다 tool 메시지 하나를 messages에 추가한 뒤, 같은 tools로 요청을 다시 보냅니다. |
| 5 | 모델 | 모델이 finish_reason: "stop"과 함께 텍스트로 답하거나, 호출을 더 요청합니다. 후자의 경우 3단계로 돌아갑니다. |
요청 하나가 모델의 한 턴입니다. API는 요청 사이에 대화를 보관하지 않으며 라운드 수도 정하지 않습니다. messages를 보관하고 언제 멈출지 결정하는 것은 사용자의 코드입니다.
도구 정의
tools는 함수마다 항목 하나가 있는 배열입니다. 카탈로그의 모든 모델이 이를 지원하며, GET /v1/models는 모든 id에 대해 capabilities.tools: true를 보고합니다.
| 필드 | 유형 | 설명 |
|---|---|---|
type | string | 항상 function입니다. |
function.name | string | 모델이 이 함수를 요청할 때 사용하는 이름입니다. 필수. |
function.description | string | 함수가 하는 일을 쉬운 말로 설명합니다. |
function.parameters | object | 최상위에 type: "object"가 있는 JSON Schema 형태의 인자입니다. 아래의 스키마 키워드를 참조하세요. |
엔드포인트마다 도구의 표기가 다릅니다. 호출하는 엔드포인트에 맞는 것을 보내세요:
{
"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는 모델이 도구를 호출해도 되는지, 또는 반드시 호출해야 하는지를 정합니다. tools와 함께 있을 때만 읽습니다.
| 값 | 설명 | 적용 대상 |
|---|---|---|
"auto" | 모델이 텍스트로 답할지 도구를 호출할지 결정합니다. 기본값입니다. | 모든 모델 |
"required" | 응답이 도구를 하나 이상 호출합니다. | 호스팅 오픈 웨이트 모델 |
{"type": "function", "function": {"name": "get_weather"}} | 응답이 이 함수를 호출합니다. 이름은 tools에 있는 함수 중 하나여야 합니다. 다른 함수에 대한 호출은 응답에서 제외됩니다. | 호스팅 오픈 웨이트 모델 |
Shannon 모델(shannon-*)은 auto처럼 매 요청마다 스스로 결정합니다.
required나 이름이 지정된 함수를 사용할 때는 tool_calls를 읽기 전에 finish_reason을 읽으세요. 모델이 호출을 만들지 않으면 응답은 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에서는 output의 function_call 항목이며 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\"}"
}
}
]
}
} {
"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"}
}
]
} 한 턴의 여러 호출
응답에는 호출이 여러 개 담길 수 있습니다. 모두 실행하고, 다음 요청에서 호출마다 결과를 하나씩, 각각 자신의 tool_call_id와 함께 보내세요.
호스팅 오픈 웨이트 모델은 서로 다른 호출을 각각 한 번씩 반환합니다. 이름과 인자가 같은 호출 두 개는 하나로 도착합니다.
스트리밍 도구 호출
stream: true에서는 호출이 한 덩어리로 도착합니다. 청크에 완전한 arguments 문자열이 들어 있으므로 이어 붙일 조각이 없습니다. index는 턴의 호출을 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
}
]
} | 엔드포인트 | 도착하는 것 |
|---|---|
/v1/chat/completions | 호출마다 chat.completion.chunk 하나이며, 호출은 delta.tool_calls[0]에 있습니다. 마지막 청크에 finish_reason: "tool_calls"와 usage가 있습니다. |
/v1/responses | 호출마다: response.output_item.added(arguments가 빈 function_call 항목), response.function_call_arguments.delta(문자열 전체), response.function_call_arguments.done, response.output_item.done. |
/v1/messages | 호출마다: content_block_start(input이 빈 tool_use 블록), input_json_delta.partial_json이 인자 텍스트 전체인 content_block_delta 하나, 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 델타로 전달합니다. 스트리밍
결과 되돌려 보내기
두 번째 요청은 대화를 반복하면서 두 가지를 추가합니다: 호출을 요청한 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\"}"
}
]
} {
"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\"}"
}
]
}
]
} - assistant 턴을 받은 그대로 결과 앞에 되돌려 보내세요. 각 결과는 id로 호출과 연결됩니다:
/v1/chat/completions에서는tool_call_id,/v1/responses에서는call_id,/v1/messages에서는tool_use_id. - 결과는 텍스트입니다. 객체는 JSON 문자열로 직렬화하여
content에 넣으세요(/v1/responses에서는output)./v1/messages에서tool_result블록의content는 문자열 또는 텍스트 블록 목록입니다. - assistant 턴에서
function.arguments는 도착한 그대로 JSON 문자열로 유지됩니다. - 대화는 도구 결과로 끝날 수 있습니다. 새 사용자 메시지는 필요하지 않습니다. 모델이 결과에서 이어갑니다.
- 함수가 실패하면 실패 내용을 결과 텍스트로 보내세요. 그러면 모델이 이를 보고하거나 다른 호출을 요청할 수 있습니다.
스키마 키워드
parameters(/v1/messages에서는 input_schema)는 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는 기본temperature0.2를 사용합니다. 다른 값을 설정하려면temperature를 보내세요. - 각 라운드는 별도의 요청입니다. 다른 요청과 마찬가지로 잔액에서 차감되고 플러드 보호에 집계됩니다. 한도 및 잔액
오류
도구 호출은 상태 200의 정상 응답입니다. 다음 오류는 요청 자체와 관련된 것입니다:
| 상태 | 유형 | 메시지 | 시점 |
|---|---|---|---|
400 | invalid_request_error | unknown model: <id> | model이 공개된 목록의 id가 아닙니다. |
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"가 담겨 있습니다. |
인자는 모델이 작성합니다. 다른 외부 입력과 마찬가지로, 함수를 실행하기 전에 스키마와 대조해 확인하세요.
인증, 잔액, 서버 오류는 모든 요청과 동일합니다. 오류 처리