Дамжуулалт
stream-ийг true болговол хариу загвар бичих явцад server-sent events хэлбэрээр ирнэ: эхлээд reasoning, дараа нь хариулт, төгсгөлд finish reason ба usage-тэй сүүлийн chunk. Текстийг хүн хүлээж байгаа үед болон урт хариунд үүнийг ашиглана уу.
POST https://api.shannon-ai.com/v1/chat/completions
OpenAI SDK-ууд chunk-уудыг нэг нэгээр нь өгнө. Chunk бүрийг агуулж буй зүйлээр нь унших: reasoning-ийн хэсэг, хариултын хэсэг, tool дуудлага, эсвэл хариуны төгсгөл.
from openai import OpenAI, APIError
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.shannon-ai.com/v1",
)
stream = client.chat.completions.create(
model="shannon-3",
messages=[{"role": "user", "content": "Explain server-sent events in three sentences."}],
stream=True,
)
answer, reasoning, tool_calls = [], [], []
finish_reason = usage = None
try:
for chunk in stream:
if chunk.usage:
usage = chunk.usage
if not chunk.choices:
continue
choice = chunk.choices[0]
delta = choice.delta
thought = getattr(delta, "reasoning_content", None)
if thought:
reasoning.append(thought)
if delta.content:
answer.append(delta.content)
print(delta.content, end="", flush=True)
for call in delta.tool_calls or []:
tool_calls.append((call.id, call.function.name, call.function.arguments))
if choice.finish_reason:
finish_reason = choice.finish_reason
except APIError as error:
# A failure after the stream started arrives as an error chunk.
print(f"\nstream failed: {error}")
print(f"\n{finish_reason} {usage}") import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://api.shannon-ai.com/v1",
});
const stream = await client.chat.completions.create({
model: "shannon-3",
messages: [{ role: "user", content: "Explain server-sent events in three sentences." }],
stream: true,
});
let answer = "";
let reasoning = "";
const toolCalls = [];
let finishReason = null;
let usage = null;
try {
for await (const chunk of stream) {
if (chunk.usage) usage = chunk.usage;
const choice = chunk.choices?.[0];
if (!choice) continue;
const delta = choice.delta;
if (delta.reasoning_content) reasoning += delta.reasoning_content;
if (delta.content) {
answer += delta.content;
process.stdout.write(delta.content);
}
for (const call of delta.tool_calls ?? []) {
toolCalls.push({ id: call.id, name: call.function.name, arguments: call.function.arguments });
}
if (choice.finish_reason) finishReason = choice.finish_reason;
}
} catch (error) {
// A failure after the stream started arrives as an error chunk.
console.error("\nstream failed:", error.message);
}
console.log("\n", finishReason, usage); curl -N https://api.shannon-ai.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "shannon-3",
"messages": [{"role": "user", "content": "Explain server-sent events in three sentences."}],
"stream": true
}' Stream хэрхэн frame хийгддэг
- Хариу
200статустай бөгөөдcontent-type: text/event-streamбаcache-control: no-cacheheader-тэй. - Event бүр
data:-аар эхэлсэн нэг мөр бөгөөд араас нь хоосон мөр орно.data:-ийн дараах текст нь нэг JSON chunk.event:эсвэлid:мөр байхгүй. : pingшиг хоёр цэгээр эхэлсэн мөр нь холболтыг нээлттэй байлгадаг тайлбар. Алгасна уу.- Stream
data: [DONE]-оор төгсөнө. Түүнгүйгээр зогссон stream дутуу.
Chunk-ууд дарааллаар
Chunk бүр chat.completion.chunk объект:
{
"id": "chatcmpl-5f0c1e7a9b3d4c62a8e1f07d2b46c9a3",
"object": "chat.completion.chunk",
"created": 1791625200,
"model": "shannon-3",
"choices": [
{
"index": 0,
"delta": {
"content": "Server-sent"
},
"finish_reason": null
}
]
} Нэг stream-ийн бүх chunk ижил id, created, model агуулна. choices үргэлж нэг бичлэгтэй. Түүний delta шинийг агуулах бөгөөд finish_reason сүүлийн chunk хүртэл null.
| Delta дахь түлхүүр | Төрөл | Тайлбар | Илгээгч |
|---|---|---|---|
role | string | Үргэлж assistant. Stream-ийн эхэнд нэг удаа ирнэ. | Hosted open-weight загварууд, shannon-2-lite, shannon-2-pro |
reasoning_content | string | Загварын reasoning-ийн нэг хэсэг. Хэсгүүдийг дарааллаар нь залгана. | Hosted open-weight загварууд, Shannon 3 гэр бүл, shannon-1.6-pro, shannon-coder-1 |
content | string | Хариултын нэг хэсэг. Хэсгүүдийг дарааллаар нь залгана. | Бүх загвар |
tool_calls | array | Нэг бүрэн tool дуудлага. Tool дуудлагын delta хэсгийг үзнэ үү. | Бүх загвар |
Эхлээд reasoning, дараа нь хариулт, дараа нь tool дуудлага ирнэ. Chunk-ийг stream доторх байрнаар нь бус delta доторх түлхүүрээр нь уншина уу: delta нь role-ийг эхний текстийн хамт агуулж болох ба сүүлийнх нь хоосон байна.
Бүтэн stream явж буй хэлбэрээрээ. Мөрийг богино байлгахын тулд энд chunk бүрээс id, object, created, model-ийг орхисон.
data: {"choices":[{"index":0,"delta":{"reasoning_content":"Three sentences:"},"finish_reason":null}]}
data: {"choices":[{"index":0,"delta":{"reasoning_content":" what it is, how it is framed, why it is used."},"finish_reason":null}]}
: ping
data: {"choices":[{"index":0,"delta":{"content":"Server-sent"},"finish_reason":null}]}
data: {"choices":[{"index":0,"delta":{"content":" events let a server push text to a client over one HTTP reply."},"finish_reason":null}]}
data: {"choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":1190,"completion_tokens":84,"total_tokens":1274}}
data: [DONE] Reasoning delta
Reasoning хийдэг загвар reasoning-ээ хариултаас өмнө delta.reasoning_content-д илгээнэ. Хоёр текстийг тусад нь байлгана уу: reasoning-ийг тусдаа, нугалж болох хэсэг болгон харуулах, эсвэл орхино.
reasoning_effort нь off үед, мөн хүсэлт response_format агуулсан үед hosted open-weight загварууд reasoning илгээхгүй.
shannon-2-lite ба shannon-2-pro мөн хариулахаасаа өмнө reasoning хийнэ. Энэ endpoint дээр тэд reasoning хийх хугацаандаа : thinking тайлбар мөр илгээж, дараа нь хариултыг илгээнэ.
reasoning_content нь OpenAI SDK-ийн төрөлжсөн загваруудад байхгүй. Python дээр getattr(delta, "reasoning_content", None)-ээр уншина; JavaScript дээр delta.reasoning_content хэвээр нь ажиллана.
Tool дуудлагын delta
Tool дуудлага бүтнээрээ ирнэ: дуудлага бүрт нэг chunk, түүний delta нь бүрэн arguments string-тэй дуудлагыг агуулна. index нь хариуны дуудлагуудыг 0-ээс дугаарлана. arguments-ийг хэсэг хэсгээр нь залгадаг код нэг хэсгийг л залгадаг тул өөрчлөлтгүй ажиллана.
{
"tool_calls": [
{
"index": 0,
"id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
} Дуудлагуудын дараа сүүлийн chunk finish_reason нь tool_calls.
Хүсэлт tools агуулсан үед shannon-1.6-lite, shannon-1.6-pro ба shannon-coder-1 хариултын текстийг хариуны төгсгөлд нэг delta болгон илгээнэ.
Сүүлийн chunk
data: [DONE]-оос өмнөх сүүлийн chunk хоосон delta, finish_reason ба хүсэлтийн usage-ийг бүгдийг нэг chunk-д агуулна. Stream бүрд байх тул stream_options хэрэггүй.
{
"id": "chatcmpl-5f0c1e7a9b3d4c62a8e1f07d2b46c9a3",
"object": "chat.completion.chunk",
"created": 1791625200,
"model": "shannon-3",
"choices": [
{
"index": 0,
"delta": {},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 1190,
"completion_tokens": 84,
"total_tokens": 1274
}
} Hosted open-weight загварууд дээр usage нь prompt_tokens_details.cached_tokens ба completion_tokens_details.reasoning_tokens-ийг бас агуулна.
Хайлт нь ямар нэг зүйл олсон web_search: true-тай хүсэлтийн дараа сүүлийн chunk sources-ийг бас агуулна, түүнээс өмнөх нэг chunk иш татсан тэмдгүүдийг delta.annotations хэлбэрээр агуулна. Вэб хайлт
| finish_reason | Тайлбар | Илгээгч |
|---|---|---|
stop | Загвар хариултаа дуусгасан, эсвэл stop string гарч ирсэн. | Бүх загвар |
tool_calls | Хариу нэг буюу хэд хэдэн tool дуудлага агуулна. | Бүх загвар |
length | Хариу гаралтын хязгаарт тасарсан. | Shannon 3 гэр бүл, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 |
usage-ийн талбаруудыг endpoint-ийн хамт тайлбарласан. Chat Completions
Keep-alive мөрүүд
Загвар ажиллаж байгаа ч илгээх зүйл хараахан байхгүй үед stream тайлбар мөр агуулна. Тэд өгөгдөл агуулахгүй. SSE parser өөрөө алгасна; түүхий мөр уншдаг код хоёр цэгээр эхэлсэн мөр бүрийг алгасах ёстой.
| Мөр | Илгээгч | Хэзээ |
|---|---|---|
: ping | Shannon 3 гэр бүл, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 | 15 секунд тутам. |
: keepalive | Hosted open-weight загварууд | Загвар ажиллах хугацаанд 15 секунд тутам. |
: thinking | shannon-2-lite, shannon-2-pro | Загвар reasoning хийх хугацаанд. |
Stream доторх алдаа
Stream эхэлсэн даруйд статус 200 байдаг тул алдаа stream дотор ирнэ: choices байх газар error гишүүнтэй chunk.
data: {"error":{"message":"The model backend failed to answer. Please retry.","type":"api_error","code":null,"param":null}}
data: {"choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":1190,"completion_tokens":12,"total_tokens":1202}}
data: [DONE] Алдааны chunk-ийн дараа finish_reason ба usage-тэй сүүлийн chunk, мөн data: [DONE] мөн л дагана. Chunk бүрийг error-т шалгана уу. Шалгахгүй бол дундаа амжилтгүй болсон хариу бүрэн мэт харагдана.
| Төрөл | Код | Мессеж | Хэзээ |
|---|---|---|---|
api_error | The model backend failed to answer. Please retry. | Загвар амжилтгүй болсон, эсвэл юу ч бичээгүй. Хүсэлтийг дахин илгээнэ үү. | |
rate_limit_error | Shannon routes are temporarily busy. Please retry. | Загвар яг одоо завгүй байна. Хэдэн секунд хүлээгээд хүсэлтийг дахин илгээнэ үү. | |
invalid_request_error | context_length_exceeded | Харилцан яриа загварын контекст цонхноос урт байна. Дахин илгээхээсээ өмнө богиносгоно уу. Мессежийн текст өөр өөр байна. |
Hosted open-weight загварууд error гишүүнийг зөвхөн type ба message-тэй илгээнэ.
OpenAI Python ба JavaScript SDK-ууд алдааны chunk-ийг давтах явцад API алдаа болгон гаргадаг тул давталтаа ердийн алдаа боловсруулалтаар ороож бичнэ үү.
Статус код, алдааны body, юуг дахин оролдох нь тусдаа хуудастай. Алдаа боловсруулах
Холболтыг хаах
Холболтыг хаах нь хүсэлтийг биш, хүргэлтийг зогсооно. Загвар хариуг төгсгөл хүртэл бичих бөгөөд хүсэлтийг таныг бүгдийг уншсан мэт тооцно. Бага төлөхийн тулд бага хүс: үүнийг хэрэгжүүлдэг загвар дээр бага max_tokens тогтооно уу.
Stream танд хүрэх замдаа эрт дуусч болно, жишээлбэл сүлжээ тасрах эсвэл сервер шинэчлэгдэх үед. Тэгвэл сүүлийн chunk ба data: [DONE]-гүйгээр зогсоно. Тийм хариуг дутуу гэж үзэж, хүсэлтийг дахин илгээнэ үү.
SDK-гүйгээр stream унших
Зөв уншигч таван зүйл хийнэ: stream-ээс өмнө ирсэн алдааг өөрийн алдаа боловсруулалт руу илгээнэ, body-г мөрүүдэд хуваана, тайлбар мөрийг алгасна, data: [DONE] дээр зогсоно, chunk бүрийг error-т шалгана.
import json
import requests
response = requests.post(
"https://api.shannon-ai.com/v1/chat/completions",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"model": "shannon-3",
"messages": [{"role": "user", "content": "Explain server-sent events in three sentences."}],
"stream": True,
},
stream=True,
)
# 1. Errors before the stream are plain JSON with their own status.
if response.status_code != 200:
raise RuntimeError(f"{response.status_code}: {response.text}")
answer, done = [], False
for raw in response.iter_lines(): # 2. one line at a time
line = raw.decode("utf-8")
if not line.startswith("data: "): # 3. empty lines and ": ping" comments
continue
data = line[len("data: "):]
if data == "[DONE]": # 4. the end of the stream
done = True
break
chunk = json.loads(data)
if "error" in chunk: # 5. a failure inside the stream
raise RuntimeError(chunk["error"]["message"])
delta = chunk["choices"][0]["delta"]
if delta.get("content"):
answer.append(delta["content"])
if chunk.get("usage"):
print(chunk["choices"][0]["finish_reason"], chunk["usage"])
if not done:
raise RuntimeError("the stream ended before [DONE]")
print("".join(answer)) const response = await fetch("https://api.shannon-ai.com/v1/chat/completions", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "shannon-3",
messages: [{ role: "user", content: "Explain server-sent events in three sentences." }],
stream: true,
}),
});
// 1. Errors before the stream are plain JSON with their own status.
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const decoder = new TextDecoder();
let buffer = "";
let answer = "";
let done = false;
read: for await (const bytes of response.body) {
buffer += decoder.decode(bytes, { stream: true });
const lines = buffer.split("\n"); // 2. one line at a time
buffer = lines.pop(); // keep the unfinished line
for (const line of lines) {
if (!line.startsWith("data: ")) continue; // 3. empty lines and ": ping" comments
const data = line.slice(6);
if (data === "[DONE]") { // 4. the end of the stream
done = true;
break read;
}
const chunk = JSON.parse(data);
if (chunk.error) throw new Error(chunk.error.message); // 5. a failure inside the stream
const choice = chunk.choices[0];
if (choice.delta.content) answer += choice.delta.content;
if (chunk.usage) console.log(choice.finish_reason, chunk.usage);
}
}
if (!done) throw new Error("the stream ended before [DONE]");
console.log(answer); Python жишээ requests багц ашиглана. JavaScript жишээ Node.js 18 буюу түүнээс дээш хувилбар дээр ажиллана.
Бусад форматын stream
Responses ба Messages endpoint-ууд бас stream хийнэ. Тэдний frame-үүд event-ийн нэртэй event: мөр ба түүний JSON-той data: мөр агуулна. Хуудас бүр event-үүдээ дарааллаар нь жагсаасан.
| Stream дотор | Chat Completions | Responses | Messages |
|---|---|---|---|
| Frame-үүд | data: мөрүүд | event: ба data: мөрүүд | event: ба data: мөрүүд |
| Reasoning ирэх газар | delta.reasoning_content | response.reasoning_summary_text.delta | thinking_delta |
| Хариултын текст ирэх газар | delta.content | response.output_text.delta | text_delta |
| Usage ирэх газар | Сүүлийн chunk | response.completed | message_delta |
| Stream төгсөх нь | Сүүлийн chunk, дараа нь data: [DONE] | response.completed | message_stop |