Streaming
Setzt stream op true, an d'Äntwert kënnt als Server-sent Events un, wärend de Modell se schreift: fir d'éischt d'Reasoning, dann d'Äntwert, dann e leschte Chunk mam Grond fir d'Enn an der Usage. Benotzt et ëmmer, wann e Mënsch op den Text waart, a bei laangen Äntwerten.
POST https://api.shannon-ai.com/v1/chat/completions
D'OpenAI-SDKs ginn Iech d'Chunken een nom aneren. Liest all Chunk dorno, wat en enthält: e Stéck Reasoning, e Stéck vun der Äntwert, en Tool-Ruff, oder d'Enn vun der Äntwert.
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
}' Wéi e Stream opgebaut ass
- D'Äntwert huet de Status
200an d'Headercontent-type: text/event-streamancache-control: no-cache. - All Event ass eng Zeil, déi mat
data:ufänkt a vun enger eidel Zeil gefollegt gëtt. Den Text nodata:ass ee JSON-Chunk. Et gëtt kengevent:- oderid:-Zeilen. - Eng Zeil, déi mat engem Doppelpunkt ufänkt, wéi
: ping, ass e Kommentar, deen d'Verbindung oppen hält. Iwwersprang se. - De Stream hält mat
data: [DONE]op. E Stream, dee ouni et stoppt, ass onkomplett.
Chunke vun der Reiefolleg no
All Chunk ass e chat.completion.chunk-Objet:
{
"id": "chatcmpl-5f0c1e7a9b3d4c62a8e1f07d2b46c9a3",
"object": "chat.completion.chunk",
"created": 1791625200,
"model": "shannon-3",
"choices": [
{
"index": 0,
"delta": {
"content": "Server-sent"
},
"finish_reason": null
}
]
} All Chunke vun engem Stream hunn déiselwecht id, created an model. choices enthält ëmmer een Eintrag. Säin delta enthält dat, wat nei ass, an finish_reason ass null bis zum leschte Chunk.
| Schlëssel am Delta | Typ | Beschreiwung | Geschéckt vun |
|---|---|---|---|
role | string | Ëmmer assistant. Et kënnt eemol, um Ufank vum Stream. | Hosted Open-Weight-Modeller, shannon-2-lite, shannon-2-pro |
reasoning_content | string | E Stéck vun der Reasoning vum Modell. Setzt d'Stécker der Reiefolleg no zesummen. | Hosted Open-Weight-Modeller, Shannon-3-Famill, shannon-1.6-pro, shannon-coder-1 |
content | string | E Stéck vun der Äntwert. Setzt d'Stécker der Reiefolleg no zesummen. | All Modeller |
tool_calls | array | Een komplette Tool-Ruff. Kuckt Tool-Ruff-Deltaen. | All Modeller |
D'Reasoning kënnt als éischt, dann d'Äntwert, dann all Tool-Ruffer. Liest e Chunk no de Schlësselen a sengem delta, net no senger Plaz am Stream: e delta ka role zesumme mam éischte Stéck Text enthalen, an dee leschte ass eidel.
E ganze Stream, wéi en ënnerwee ass. Fir d'Zeilen kuerz ze halen, sinn id, object, created an model hei aus all Chunk erausgelooss.
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-Deltaen
E Modell, dee reasonéiert, schéckt seng Reasoning an delta.reasoning_content virun der Äntwert. Haalt déi zwee Texter getrennt: weist d'Reasoning als separaten, zouklappbaren Deel, oder looss se eraus.
D'Hosted Open-Weight-Modeller schécken keng Reasoning, wann reasoning_effort off ass, a keng, wann d'Ufro e response_format huet.
shannon-2-lite an shannon-2-pro reasonéieren och, ier si äntweren. Op dësem Endpoint schécken si : thinking-Kommentar-Zeilen, wärend si dat maachen, an dann d'Äntwert.
reasoning_content ass net an den typiséierte Modeller vun den OpenAI-SDKs. Liest et a Python mat getattr(delta, "reasoning_content", None); a JavaScript funktionéiert delta.reasoning_content esou, wéi et ass.
Tool-Ruff-Deltaen
E Tool-Ruff kënnt ganz un: ee Chunk pro Ruff, deem säin delta de Ruff mam kompletten arguments-String enthält. index nummeréiert d'Ruffer vun der Äntwert vun 0 un. Code, dee arguments Stéck fir Stéck zesummesetzt, funktionéiert onverännert, well en een Stéck zesummesetzt.
{
"tool_calls": [
{
"index": 0,
"id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
} No de Ruffer huet de leschte Chunk finish_reason tool_calls.
Wann d'Ufro tools huet, schécken shannon-1.6-lite, shannon-1.6-pro a shannon-coder-1 den Äntwert-Text als een Delta um Enn vun der Äntwert.
De leschte Chunk
De leschte Chunk virun data: [DONE] huet en eidelt delta, de finish_reason an den usage vun der Ufro, alles am selwechte Chunk. All Stream huet en; Dir braucht stream_options net.
{
"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
}
} Bei den Hosted Open-Weight-Modeller huet usage och prompt_tokens_details.cached_tokens an completion_tokens_details.reasoning_tokens.
No enger Ufro mat web_search: true, där hir Sich eppes fonnt huet, dréit de leschte Chunk och sources, an ee Chunk virdrun dréit d'Zitatmarkéierungen als delta.annotations. Integréiert Websich
| finish_reason | Beschreiwung | Geschéckt vun |
|---|---|---|
stop | De Modell huet seng Äntwert fäerdeg gemaach, oder e stop-String ass opgetaucht. | All Modeller |
tool_calls | D'Äntwert enthält een oder méi Tool-Ruffer. | All Modeller |
length | D'Äntwert gouf bei der Output-Limit ofgeschnidden. | Shannon-3-Famill, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 |
D'Felder vun usage si beim Endpoint beschriwwen. Chat Completions
Keep-alive-Zeilen
Wärend de Modell schafft an nach näischt ze schécken huet, enthält de Stream Kommentar-Zeilen. Si enthalen keng Daten. E SSE-Parser iwwersprengt se vu selwer; Code, deen rau Zeilen liest, muss all Zeil iwwerspréngen, déi mat engem Doppelpunkt ufänkt.
| Zeil | Geschéckt vun | Wéini |
|---|---|---|
: ping | Shannon-3-Famill, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 | All 15 Sekonnen. |
: keepalive | Hosted Open-Weight-Modeller | All 15 Sekonne, wärend de Modell schafft. |
: thinking | shannon-2-lite, shannon-2-pro | Wärend de Modell reasonéiert. |
Feeler an engem Stream
Wann e Stream ugefaang huet, ass säi Status 200, dofir kënnt e Feeler am Stream: e Chunk mat engem error-Member do, wou choices wier.
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] No dem Feeler-Chunk folgen nach de leschte Chunk, mat finish_reason an usage, an data: [DONE]. Kontrolléiert all Chunk op error. Ouni dës Kontroll gesäit eng Äntwert, déi hallef feelgeschloen ass, komplett aus.
| Typ | Code | Message | Wéini |
|---|---|---|---|
api_error | The model backend failed to answer. Please retry. | De Modell ass gescheitert, oder huet näischt geschriwwen. Schéckt d'Ufro nach eng Kéier. | |
rate_limit_error | Shannon routes are temporarily busy. Please retry. | De Modell ass an dësem Moment beschäftegt. Waart e puer Sekonnen a schéckt d'Ufro nach eng Kéier. | |
invalid_request_error | context_length_exceeded | D'Konversatioun ass méi laang wéi d'Kontextfënster vum Modell. Kierzt se, ier Dir se nach eng Kéier schéckt. Den Text vun der Message variéiert. |
D'Hosted Open-Weight-Modeller schécken den error-Member just mat type a message.
D'OpenAI-SDKs fir Python a JavaScript werfen e Feeler-Chunk als API-Feeler, wärend Dir iteréiert, sou datt Dir d'Loop an Är gewinnten Feelerbehandlung packt.
Status-Coden, de Feeler-Body a wat nach eng Kéier probéiert gëtt, hunn eng eege Säit. Feelerbehandlung
D'Verbindung zoumaachen
D'Verbindung zoumaachen stoppt d'Liwwerung, net d'Ufro. De Modell schreift d'Äntwert bis zum Enn, an d'Ufro gëtt berechent, wéi wann Dir se ganz gelies hätt. Fir manner ze bezuelen, freet manner: setzt e méi niddrege max_tokens bei engem Modell, dee en benotzt.
E Stream kann och op sengem Wee zu Iech fréi ophalen, zum Beispill bei engem Netzwierk-Ofbroch oder wärend e Server aktualiséiert gëtt. Hie stoppt dann ouni de leschte Chunk an ouni data: [DONE]. Behandelt dës Äntwert als onkomplett a schéckt d'Ufro nach eng Kéier.
E Stream ouni SDK liesen
E korrekte Reader mécht fënnef Saachen: hie schéckt Feeler, déi virum Stream ukommen, un seng Feelerbehandlung, deelt de Body a Zeilen, iwwersprengt Kommentar-Zeilen, hält bei data: [DONE] op a kontrolléiert all Chunk op 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); D'Python-Beispill benotzt de Package requests. D'JavaScript-Beispill leeft op Node.js 18 oder méi spéit.
Streams vun deenen anere Formater
D'Responses- an d'Messages-Endpoints streamen och. Hir Frames enthalen eng event:-Zeil mam Numm vum Event an eng data:-Zeil mat sengem JSON. All Säit lëscht hir Events der Reiefolleg no op.
| Am Stream | Chat Completions | Responses | Messages |
|---|---|---|---|
| Frames | data:-Zeilen | event:- an data:-Zeilen | event:- an data:-Zeilen |
| D'Reasoning kënnt an | delta.reasoning_content | response.reasoning_summary_text.delta | thinking_delta |
| Den Äntwert-Text kënnt an | delta.content | response.output_text.delta | text_delta |
| Usage kënnt an | De leschte Chunk | response.completed | message_delta |
| De Stream hält op mat | De leschte Chunk, dann data: [DONE] | response.completed | message_stop |