ስትሪሚንግ
stream ን ወደ true ያዘጋጁ እና ምላሹ ሞዴሉ ሲጽፈው እንደ server-sent events ይደርሳል፦ መጀመሪያ reasoning፣ ከዚያ መልሱ፣ ከዚያ የማጠናቀቂያ ምክንያቱ እና usage ያለው የመጨረሻ chunk። አንድ ሰው ጽሑፉን እየጠበቀ ሲሆን እና ለረጅም ምላሾች ይጠቀሙበት።
POST https://api.shannon-ai.com/v1/chat/completions
የOpenAI SDKs chunks ን አንድ በአንድ ይሰጡዎታል። እያንዳንዱን 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 እንዴት እንደሚቀረጽ
- ምላሹ status
200እናcontent-type: text/event-streamእናcache-control: no-cacheheaders አለው። - እያንዳንዱ event በ
data:የሚጀምር እና ባዶ መስመር የሚከተለው አንድ መስመር ነው። ከdata:በኋላ ያለው ጽሑፍ አንድ JSON chunk ነው። የevent:ወይም የid:መስመሮች የሉም። - በኮሎን የሚጀምር መስመር፣ ለምሳሌ
: ping፣ ግንኙነቱን ክፍት የሚያደርግ comment ነው። ይዝለሉት። - stream የሚያበቃው በ
data: [DONE]ነው። ያለ እሱ የሚቆም stream ያልተሟላ ነው።
Chunks በቅደም ተከተል
እያንዳንዱ chunk chat.completion.chunk object ነው፦
{
"id": "chatcmpl-5f0c1e7a9b3d4c62a8e1f07d2b46c9a3",
"object": "chat.completion.chunk",
"created": 1791625200,
"model": "shannon-3",
"choices": [
{
"index": 0,
"delta": {
"content": "Server-sent"
},
"finish_reason": null
}
]
} የአንድ stream ሁሉም chunks ተመሳሳይ id፣ created እና model ይይዛሉ። choices ሁልጊዜ አንድ ግቤት ይይዛል። delta አዲሱን ይይዛል፣ finish_reason ደግሞ እስከ መጨረሻው chunk null ነው።
| በdelta ውስጥ ያለ ቁልፍ | ዓይነት | መግለጫ | የሚልከው |
|---|---|---|---|
role | string | ሁልጊዜ assistant። በstream መጀመሪያ አንድ ጊዜ ይደርሳል። | የተስተናገዱ open-weight ሞዴሎች፣ shannon-2-lite፣ shannon-2-pro |
reasoning_content | string | የሞዴሉ reasoning አንድ ቁራጭ። ቁርጥራጮቹን በቅደም ተከተል ያጣምሩ። | የተስተናገዱ open-weight ሞዴሎች፣ የShannon 3 ቤተሰብ፣ shannon-1.6-pro፣ shannon-coder-1 |
content | string | የመልሱ አንድ ቁራጭ። ቁርጥራጮቹን በቅደም ተከተል ያጣምሩ። | ሁሉም ሞዴሎች |
tool_calls | array | አንድ ሙሉ የtool ጥሪ። የTool call deltas ን ይመልከቱ። | ሁሉም ሞዴሎች |
መጀመሪያ reasoning፣ ከዚያ መልሱ፣ ከዚያ ማንኛውም የtool ጥሪዎች ይመጣሉ። chunk ን በstream ውስጥ ባለበት ቦታ ሳይሆን በdelta ውስጥ ባሉት ቁልፎች ያንብቡ፦ delta role ን ከመጀመሪያው የጽሑፍ ቁራጭ ጋር ሊይዝ ይችላል፣ የመጨረሻው ደግሞ ባዶ ነው።
ሙሉ stream በሚጓዝበት መልኩ። መስመሮቹ አጭር እንዲሆኑ id፣ object፣ created እና model እዚህ ከእያንዳንዱ chunk ተትተዋል።
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 deltas
የሚያስብ ሞዴል reasoning ውን ከመልሱ በፊት በdelta.reasoning_content ይልካል። ሁለቱን ጽሑፎች ለይተው ያስቀምጡ፦ reasoning ን እንደ የተለየ ሊታጠፍ የሚችል ክፍል ያሳዩ፣ ወይም ይተዉት።
የተስተናገዱ open-weight ሞዴሎች reasoning_effort off ሲሆን reasoning አይልኩም፣ ጥያቄው response_format ሲኖረውም አይልኩም።
shannon-2-lite እና shannon-2-pro ከመመለሳቸው በፊት ያስባሉ። በዚህ endpoint ላይ ሲያስቡ : thinking comment መስመሮችን ይልካሉ፣ ከዚያ መልሱን።
reasoning_content በOpenAI SDKs typed ሞዴሎች ውስጥ የለም። በPython getattr(delta, "reasoning_content", None) ያንብቡ፤ በJavaScript delta.reasoning_content እንዳለ ይሰራል።
የTool call deltas
የ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
}
} በተስተናገዱ 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 comment መስመሮችን ይይዛል። ምንም data የላቸውም። SSE parser ራሱ ይዘለሉቸዋል፤ ጥሬ መስመሮችን የሚያነብ ኮድ በኮሎን የሚጀምሩትን መስመሮች ሁሉ መዝለል አለበት።
| መስመር | የሚልከው | መቼ |
|---|---|---|
: ping | የShannon 3 ቤተሰብ፣ shannon-1.6-lite፣ shannon-1.6-pro፣ shannon-coder-1 | በየ15 ሰከንዱ። |
: keepalive | የተስተናገዱ open-weight ሞዴሎች | ሞዴሉ በሚሰራበት ጊዜ በየ15 ሰከንዱ። |
: thinking | shannon-2-lite, shannon-2-pro | ሞዴሉ በሚያስብበት ጊዜ። |
በstream ውስጥ ያሉ ስህተቶች
stream አንዴ ከጀመረ status 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 ይመርምሩ። ያለ ይህ ፍተሻ በግማሽ መንገድ የከሸፈ ምላሽ የተሟላ ይመስላል።
| አይነት | Code | መልእክት | መቼ |
|---|---|---|---|
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 | ውይይቱ ከሞዴሉ context window ይረዝማል። እንደገና ከመላክዎ በፊት ያሳጥሩት። የመልእክቱ ጽሑፍ ይለያያል። |
የተስተናገዱ open-weight ሞዴሎች error አባልን በtype እና በmessage ብቻ ይልካሉ።
የOpenAI Python እና JavaScript SDKs በሚደግሙበት ጊዜ የስህተት chunk ን እንደ API ስህተት ያነሳሉ፣ ስለዚህ loop ን በተለመደው የስህተት አያያዝዎ ይጠቅልሉት።
የstatus ኮዶች፣ የስህተት body እና ምን እንደገና መላክ እንዳለበት የራሳቸው ገጽ አላቸው። ስህተት አስተዳደር
ግንኙነቱን መዝጋት
ግንኙነቱን መዝጋት ማድረሱን ያቆማል እንጂ ጥያቄውን አይደለም። ሞዴሉ ምላሹን እስከ መጨረሻው ይጽፋል እና ጥያቄው ሁሉንም እንዳነበቡ ሆኖ ይከፈላል። ያነሰ ለመክፈል ያነሰ ይጠይቁ፦ በሚተገብረው ሞዴል ላይ ዝቅተኛ max_tokens ያዘጋጁ።
stream ወደ እርስዎ በሚመጣበት መንገድ ላይም ቀድሞ ሊያበቃ ይችላል፣ ለምሳሌ በኔትወርክ መቋረጥ ወይም server በሚዘመንበት ጊዜ። ያኔ ያለ የመጨረሻው chunk እና ያለ data: [DONE] ይቆማል። እንዲህ ያለውን ምላሽ እንደ ያልተሟላ ይውሰዱት እና ጥያቄውን እንደገና ይላኩ።
ያለ SDK stream ማንበብ
ትክክለኛ አንባቢ አምስት ነገሮችን ያደርጋል፦ ከstream በፊት የሚደርሱ ስህተቶችን ወደ ስህተት አያያዙ ይልካል፣ body ን ወደ መስመሮች ይከፍላል፣ comment መስመሮችን ይዘላል፣ በ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 ወይም ከዚያ በኋላ ይሰራል።
የሌሎች ፎርማቶች streams
የResponses እና የMessages endpoints እንዲሁ stream ያደርጋሉ። frames ቸው የevent ስም ያለው event: መስመር እና JSON ያለው data: መስመር ይይዛሉ። እያንዳንዱ ገጽ events ን በቅደም ተከተል ይዘረዝራል።
| በstream ውስጥ | Chat Completions | Responses | Messages |
|---|---|---|---|
| Frames | 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 |