Kutiririsha
Weka stream kuwa true na jibu hufika kama server-sent events model inapoliandika: reasoning kwanza, kisha jibu, kisha chunk ya mwisho yenye sababu ya kumaliza na usage. Itumie kila wakati mtu anasubiri maandishi, na kwa majibu marefu.
POST https://api.shannon-ai.com/v1/chat/completions
SDK za OpenAI zinakupa chunks moja moja. Soma kila chunk kwa kile inachobeba: kipande cha reasoning, kipande cha jibu, wito wa tool, au mwisho wa jibu.
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
}' Jinsi stream inavyopangwa kwa frames
- Jibu lina hali
200na headerscontent-type: text/event-streamnacache-control: no-cache. - Kila tukio ni mstari mmoja unaoanza na
data:na kufuatiwa na mstari mtupu. Maandishi baada yadata:ni chunk moja ya JSON. Hakuna mistari yaevent:walaid:. - Mstari unaoanza na nukta mbili, kama
: ping, ni maoni yanayoweka muunganisho wazi. Uruke. - Stream huisha na
data: [DONE]. Stream inayosimama bila hiyo haijakamilika.
Chunks kwa mpangilio
Kila chunk ni kitu cha 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
}
]
} Chunks zote za stream moja hubeba id, created na model zile zile. choices daima ina entry moja. delta yake ina kipya, na finish_reason ni null hadi chunk ya mwisho.
| Key kwenye delta | Aina | Maelezo | Hutumwa na |
|---|---|---|---|
role | string | Daima assistant. Hufika mara moja, mwanzoni mwa stream. | Model za open-weight zinazopangishwa, shannon-2-lite, shannon-2-pro |
reasoning_content | string | Kipande cha reasoning ya model. Unganisha vipande kwa mpangilio. | Model za open-weight zinazopangishwa, familia ya Shannon 3, shannon-1.6-pro, shannon-coder-1 |
content | string | Kipande cha jibu. Unganisha vipande kwa mpangilio. | Model zote |
tool_calls | array | Wito mmoja kamili wa tool. Tazama Deltas za wito wa tool. | Model zote |
Reasoning huja kwanza, kisha jibu, kisha wito wowote wa tools. Soma chunk kwa keys zilizo kwenye delta yake, si kwa mahali pake kwenye stream: delta inaweza kuwa na role pamoja na kipande cha kwanza cha maandishi, na ya mwisho ni tupu.
Stream nzima kama inavyosafiri. Ili kuweka mistari mifupi, id, object, created na model zimeachwa nje ya kila chunk hapa.
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] Deltas za reasoning
Model inayofikiri hutuma reasoning yake kwenye delta.reasoning_content kabla ya jibu. Weka maandishi hayo mawili kando: onyesha reasoning kama sehemu tofauti inayokunjika, au iache.
Model za open-weight zinazopangishwa hazitumi reasoning wakati reasoning_effort ni off, wala ombi likiwa na response_format.
shannon-2-lite na shannon-2-pro pia hufikiri kabla ya kujibu. Kwenye endpoint hii hutuma mistari ya maoni : thinking zinapofanya hivyo, kisha jibu.
reasoning_content haimo kwenye typed models za SDK za OpenAI. Kwenye Python isome kwa getattr(delta, "reasoning_content", None); kwenye JavaScript delta.reasoning_content inafanya kazi kama ilivyo.
Deltas za wito wa tool
Wito wa tool hufika mzima: chunk moja kwa kila wito, ambayo delta yake ina wito pamoja na string kamili ya arguments. index hupa wito wa jibu namba kuanzia 0. Code inayounganisha arguments kipande kwa kipande inafanya kazi bila mabadiliko, kwa sababu inaunganisha kipande kimoja.
{
"tool_calls": [
{
"index": 0,
"id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
} Baada ya wito, chunk ya mwisho ina finish_reason tool_calls.
Ombi likiwa na tools, shannon-1.6-lite, shannon-1.6-pro na shannon-coder-1 hutuma maandishi ya jibu kama delta moja mwishoni mwa jibu.
Chunk ya mwisho
Chunk ya mwisho kabla ya data: [DONE] ina delta tupu, finish_reason na usage ya ombi, vyote kwenye chunk ile ile. Kila stream inayo; huhitaji 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
}
} Kwenye model za open-weight zinazopangishwa usage pia ina prompt_tokens_details.cached_tokens na completion_tokens_details.reasoning_tokens.
Baada ya ombi lenye web_search: true ambalo utafutaji wake ulipata kitu, chunk ya mwisho pia hubeba sources, na chunk moja kabla yake hubeba alama za marejeo kama delta.annotations. Utafutaji wa wavuti
| finish_reason | Maelezo | Hutumwa na |
|---|---|---|
stop | Model imemaliza jibu lake, au string ya stop imeonekana. | Model zote |
tool_calls | Jibu lina wito mmoja au zaidi wa tools. | Model zote |
length | Jibu lilikatwa kwenye kikomo cha output. | Familia ya Shannon 3, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 |
Fields za usage zimeelezwa pamoja na endpoint. Chat Completions
Mistari ya keep-alive
Model inapofanya kazi na haina cha kutuma bado, stream hubeba mistari ya maoni. Haina data. SSE parser huiruka yenyewe; code inayosoma mistari ghafi lazima iruke kila mstari unaoanza na nukta mbili.
| Mstari | Hutumwa na | Lini |
|---|---|---|
: ping | Familia ya Shannon 3, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 | Kila sekunde 15. |
: keepalive | Model za open-weight zinazopangishwa | Kila sekunde 15 model inapofanya kazi. |
: thinking | shannon-2-lite, shannon-2-pro | Wakati model inafikiri. |
Makosa ndani ya stream
Stream ikishaanza hali yake ni 200, kwa hiyo hitilafu hufika ndani ya stream: chunk yenye member ya error mahali ambapo choices ingekuwa.
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] Baada ya chunk ya kosa, chunk ya mwisho, yenye finish_reason na usage, na data: [DONE] bado zinafuata. Kagua kila chunk kwa error. Bila ukaguzi huo jibu lililoshindwa katikati linaonekana kamili.
| Aina | Code | Ujumbe | Lini |
|---|---|---|---|
api_error | The model backend failed to answer. Please retry. | Model ilishindwa, au haikuandika chochote. Tuma ombi tena. | |
rate_limit_error | Shannon routes are temporarily busy. Please retry. | Model ina shughuli nyingi kwa sasa. Subiri sekunde chache na utume ombi tena. | |
invalid_request_error | context_length_exceeded | Mazungumzo ni marefu kuliko dirisha la muktadha la model. Yafupishe kabla ya kutuma tena. Maandishi ya ujumbe hutofautiana. |
Model za open-weight zinazopangishwa hutuma member ya error yenye type na message pekee.
SDK za OpenAI za Python na JavaScript hutoa chunk ya kosa kama API error unapopitia (iterate), kwa hiyo funga loop kwenye ushughulikiaji wako wa kawaida wa makosa.
Status codes, mwili wa kosa na cha kujaribu tena vina ukurasa wake. Ushughulikiaji wa Makosa
Kufunga muunganisho
Kufunga muunganisho husimamisha uwasilishaji, si ombi. Model huandika jibu hadi mwisho na ombi hutozwa kana kwamba ulisoma lote. Ili kulipia kidogo, omba kidogo: weka max_tokens ndogo zaidi kwenye model inayoitumia.
Stream inaweza pia kuisha mapema njiani kwako, kwa mfano kwa kukatika kwa mtandao au wakati seva inasasishwa. Kisha husimama bila chunk ya mwisho na bila data: [DONE]. Chukulia jibu hilo kama lisilokamilika na utume ombi tena.
Kusoma stream bila SDK
Msomaji sahihi hufanya mambo matano: hupeleka makosa yanayofika kabla ya stream kwenye ushughulikiaji wake wa makosa, hugawanya mwili kuwa mistari, huruka mistari ya maoni, husimama kwenye data: [DONE], na hukagua kila chunk kwa 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); Mfano wa Python unatumia package ya requests. Mfano wa JavaScript unaendeshwa kwenye Node.js 18 au mpya zaidi.
Streams za maumbizo mengine
Endpoint za Responses na Messages pia hufanya stream. Frames zake hubeba mstari wa event: wenye jina la tukio na mstari wa data: wenye JSON yake. Kila ukurasa unaorodhesha matukio yake kwa mpangilio.
| Kwenye stream | Chat Completions | Responses | Messages |
|---|---|---|---|
| Frames | Mistari ya data: | Mistari ya event: na data: | Mistari ya event: na data: |
| Reasoning hufika kwenye | delta.reasoning_content | response.reasoning_summary_text.delta | thinking_delta |
| Maandishi ya jibu hufika kwenye | delta.content | response.output_text.delta | text_delta |
| Usage hufika kwenye | Chunk ya mwisho | response.completed | message_delta |
| Stream huisha na | Chunk ya mwisho, kisha data: [DONE] | response.completed | message_stop |