Pag‑stream
I-set ang stream sa true at dumarating ang reply bilang server-sent events habang isinusulat ito ng model: reasoning muna, saka ang sagot, saka ang huling chunk na may dahilan ng pagtatapos at usage. Gamitin ito tuwing may taong naghihintay sa text, at para sa mahahabang reply.
POST https://api.shannon-ai.com/v1/chat/completions
Ibinibigay sa iyo ng mga OpenAI SDK ang mga chunk nang isa-isa. Basahin ang bawat chunk ayon sa dala nito: isang piraso ng reasoning, isang piraso ng sagot, isang tool call, o ang wakas ng reply.
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
}' Paano binabalangkas ang stream
- Ang reply ay may status na
200at mga header nacontent-type: text/event-streamatcache-control: no-cache. - Ang bawat event ay isang linyang nagsisimula sa
data:at sinusundan ng walang lamang linya. Ang text pagkatapos ngdata:ay isang JSON chunk. Walang mga linyangevent:oid:. - Ang linyang nagsisimula sa colon, gaya ng
: ping, ay comment na nagpapanatiling bukas sa koneksyon. Laktawan ito. - Nagtatapos ang stream sa
data: [DONE]. Ang stream na huminto nang wala nito ay hindi kumpleto.
Mga chunk ayon sa pagkakasunod
Ang bawat chunk ay isang 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
}
]
} Pareho ang id, created at model na dala ng lahat ng chunk ng isang stream. Palaging isang entry ang laman ng choices. Hawak ng delta nito ang bago, at ang finish_reason ay null hanggang sa huling chunk.
| Key sa delta | Type | Paglalarawan | Ipinadala ng |
|---|---|---|---|
role | string | Palaging assistant. Isang beses itong dumarating, sa simula ng stream. | Mga hosted open-weight model, shannon-2-lite, shannon-2-pro |
reasoning_content | string | Isang piraso ng reasoning ng model. Pagdugtungin ang mga piraso ayon sa pagkakasunod. | Mga hosted open-weight model, pamilyang Shannon 3, shannon-1.6-pro, shannon-coder-1 |
content | string | Isang piraso ng sagot. Pagdugtungin ang mga piraso ayon sa pagkakasunod. | Lahat ng model |
tool_calls | array | Isang kumpletong tool call. Tingnan ang Mga delta ng tool call. | Lahat ng model |
Nauuna ang reasoning, sumusunod ang sagot, saka ang anumang tool call. Basahin ang chunk ayon sa mga key sa delta nito, hindi ayon sa lugar nito sa stream: ang isang delta ay maaaring may role kasama ng unang piraso ng text, at walang laman ang huli.
Ang buong stream kung paano ito naglalakbay. Para panatilihing maikli ang mga linya, inalis dito sa bawat chunk ang id, object, created at 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] Mga reasoning delta
Ipinapadala ng model na nag-re-reason ang reasoning nito sa delta.reasoning_content bago ang sagot. Panatilihing hiwalay ang dalawang text: ipakita ang reasoning bilang hiwalay at natitiklop na bahagi, o huwag itong isama.
Hindi nagpapadala ng reasoning ang mga hosted open-weight model kapag ang reasoning_effort ay off, at wala rin kapag may response_format ang request.
Nag-re-reason din bago sumagot ang shannon-2-lite at shannon-2-pro. Sa endpoint na ito, nagpapadala sila ng mga comment line na : thinking habang ginagawa nila iyon, saka ang sagot.
Wala ang reasoning_content sa mga typed model ng OpenAI SDK. Sa Python, basahin ito gamit ang getattr(delta, "reasoning_content", None); sa JavaScript, gumagana nang direkta ang delta.reasoning_content.
Mga delta ng tool call
Dumarating nang buo ang tool call: isang chunk kada call, na ang delta ay may hawak ng call na may kumpletong arguments string. Binibilang ng index ang mga call ng reply mula 0. Gumagana nang walang pagbabago ang code na nagdurugtong ng arguments pira-piraso, dahil isang piraso ang dinurugtong nito.
{
"tool_calls": [
{
"index": 0,
"id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
} Pagkatapos ng mga call, ang huling chunk ay may finish_reason na tool_calls.
Kapag may tools ang request, ipinapadala ng shannon-1.6-lite, shannon-1.6-pro at shannon-coder-1 ang text ng sagot bilang isang delta sa dulo ng reply.
Ang huling chunk
Ang huling chunk bago ang data: [DONE] ay may walang lamang delta, ang finish_reason at ang usage ng request, lahat sa iisang chunk. Mayroon nito ang bawat stream; hindi mo kailangan ng 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
}
} Sa mga hosted open-weight model, ang usage ay may prompt_tokens_details.cached_tokens at completion_tokens_details.reasoning_tokens din.
Pagkatapos ng request na may web_search: true na may nakitang resulta ang search, dala rin ng huling chunk ang sources, at ang isang chunk bago nito ay may dalang mga marka ng citation bilang delta.annotations. Web search
| finish_reason | Paglalarawan | Ipinadala ng |
|---|---|---|
stop | Natapos ng model ang sagot nito, o lumabas ang isang stop string. | Lahat ng model |
tool_calls | May isa o higit pang tool call ang reply. | Lahat ng model |
length | Naputol ang reply sa output limit. | Pamilyang Shannon 3, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 |
Inilalarawan kasama ng endpoint ang mga field ng usage. Chat Completions
Mga keep-alive line
Habang gumagana ang model at wala pang maipadala, may dalang mga comment line ang stream. Walang data ang mga ito. Kusa silang nilalaktawan ng SSE parser; ang code na nagbabasa ng raw na linya ay dapat lumaktaw sa bawat linyang nagsisimula sa colon.
| Linya | Ipinadala ng | Kailan |
|---|---|---|
: ping | Pamilyang Shannon 3, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 | Tuwing 15 segundo. |
: keepalive | Mga hosted open-weight model | Tuwing 15 segundo habang gumagana ang model. |
: thinking | shannon-2-lite, shannon-2-pro | Habang nag-re-reason ang model. |
Mga error sa loob ng stream
Kapag nagsimula na ang stream, 200 ang status nito, kaya ang pagkabigo ay dumarating sa loob ng stream: isang chunk na may miyembrong error kung saan dapat naroon ang choices.
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] Pagkatapos ng error chunk, sumusunod pa rin ang huling chunk, na may finish_reason at usage, at data: [DONE]. Suriin ang bawat chunk para sa error. Kung hindi, ang reply na nabigo sa kalagitnaan ay mukhang kumpleto.
| Type | Code | Mensahe | Kailan |
|---|---|---|---|
api_error | The model backend failed to answer. Please retry. | Nabigo ang model, o walang naisulat. Ipadala muli ang request. | |
rate_limit_error | Shannon routes are temporarily busy. Please retry. | Abala ang model sa ngayon. Maghintay ng ilang segundo at ipadala muli ang request. | |
invalid_request_error | context_length_exceeded | Mas mahaba ang conversation kaysa sa context window ng model. Paikliin ito bago ipadala muli. Nag-iiba ang text ng mensahe. |
Ipinapadala ng mga hosted open-weight model ang miyembrong error na may type at message lamang.
Itinataas ng mga OpenAI Python at JavaScript SDK ang error chunk bilang API error habang nag-i-iterate ka, kaya balutin ang loop sa iyong karaniwang error handling.
May sariling pahina ang mga status code, ang error body at kung ano ang dapat i-retry. Paghawak ng Error
Pagsasara ng koneksyon
Ang pagsasara ng koneksyon ay humihinto sa paghahatid, hindi sa request. Isinusulat ng model ang reply hanggang dulo at sinisingil ang request na parang binasa mo ang lahat. Para magbayad nang mas kaunti, humingi ng mas kaunti: magtakda ng mas mababang max_tokens sa model na nag-a-apply nito.
Maaari ring matapos nang maaga ang stream sa daan papunta sa iyo, halimbawa sa pagkaputol ng network o habang ina-update ang server. Hihinto ito nang walang huling chunk at walang data: [DONE]. Ituring na hindi kumpleto ang reply na iyon at ipadala muli ang request.
Pagbasa ng stream nang walang SDK
Limang bagay ang ginagawa ng tamang reader: ipinapadala nito sa error handling ang mga error na dumarating bago ang stream, hinahati ang body sa mga linya, nilalaktawan ang mga comment line, humihinto sa data: [DONE], at sinusuri ang bawat chunk para sa 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); Gumagamit ang Python sample ng package na requests. Tumatakbo ang JavaScript sample sa Node.js 18 o mas bago.
Mga stream ng ibang format
Nag-i-stream din ang mga endpoint na Responses at Messages. Ang kanilang mga frame ay may event: line na may pangalan ng event at data: line na may JSON nito. Inililista ng bawat pahina ang mga event nito ayon sa pagkakasunod.
| Sa stream | Chat Completions | Responses | Messages |
|---|---|---|---|
| Mga frame | Mga linyang data: | Mga linyang event: at data: | Mga linyang event: at data: |
| Dumarating ang reasoning sa | delta.reasoning_content | response.reasoning_summary_text.delta | thinking_delta |
| Dumarating ang text ng sagot sa | delta.content | response.output_text.delta | text_delta |
| Dumarating ang usage sa | Ang huling chunk | response.completed | message_delta |
| Nagtatapos ang stream sa | Ang huling chunk, saka data: [DONE] | response.completed | message_stop |