Streaming
Issettja stream għal true u t-tweġiba tasal bħala server-sent events waqt li l-mudell jiktibha: l-ewwel ir-raġunament, imbagħad it-tweġiba, imbagħad l-aħħar chunk bir-raġuni tat-tmiem u l-usage. Uża kull meta persuna tkun qed tistenna t-test, u għal tweġibiet twal.
POST https://api.shannon-ai.com/v1/chat/completions
L-SDKs ta' OpenAI jagħtuk il-chunks wieħed wieħed. Aqra kull chunk skont dak li jġorr: biċċa raġunament, biċċa tat-tweġiba, sejħa ta' tool, jew it-tmiem tat-tweġiba.
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
}' Kif jiġi ffrejmjat stream
- It-tweġiba għandha status
200u l-headerscontent-type: text/event-streamucache-control: no-cache. - Kull avveniment huwa linja waħda li tibda b'
data:u hija segwita minn linja vojta. It-test waradata:huwa chunk JSON wieħed. M'hemm l-ebda linjievent:jewid:. - Linja li tibda b'żewġ punti, bħal
: ping, hija kummentarju li jżomm il-konnessjoni miftuħa. Aqbeżha. - L-istream jintemm b'
data: [DONE]. Stream li jieqaf mingħajru mhuwiex komplut.
Chunks f'ordni
Kull chunk huwa oġġett 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
}
]
} Il-chunks kollha ta' stream wieħed iġorru l-istess id, created u model. choices dejjem iżomm daħla waħda. Id-delta tagħha żżomm dak li hu ġdid, u finish_reason huwa null sal-aħħar chunk.
| Ċavetta fid-delta | Tip | Deskrizzjoni | Mibgħut minn |
|---|---|---|---|
role | string | Dejjem assistant. Jasal darba, fil-bidu tal-istream. | Mudelli open-weight ospitati, shannon-2-lite, shannon-2-pro |
reasoning_content | string | Biċċa mir-raġunament tal-mudell. Għaqqad il-biċċiet f'ordni. | Mudelli open-weight ospitati, familja Shannon 3, shannon-1.6-pro, shannon-coder-1 |
content | string | Biċċa mit-tweġiba. Għaqqad il-biċċiet f'ordni. | Il-mudelli kollha |
tool_calls | array | Sejħa kompluta ta' tool. Ara Tool call deltas. | Il-mudelli kollha |
Ir-raġunament jiġi l-ewwel, imbagħad it-tweġiba, imbagħad kwalunkwe sejħa ta' tools. Aqra chunk skont iċ-ċwievet fid-delta tiegħu, mhux skont postu fl-istream: delta jista' jkun fih role flimkien mal-ewwel biċċa test, u l-aħħar waħda hija vojta.
Stream sħiħ kif jivvjaġġa. Biex il-linji jibqgħu qosra, id, object, created u model jitħallew barra minn kull chunk hawn.
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 tar-raġunament
Mudell li jirraġuna jibgħat ir-raġunament tiegħu f'delta.reasoning_content qabel it-tweġiba. Żomm iż-żewġ testi separati: uri r-raġunament bħala parti separata li tista' titwaħħad, jew ħallih barra.
Il-mudelli open-weight ospitati ma jibagħtu l-ebda raġunament meta reasoning_effort ikun off, u l-ebda wieħed meta t-talba jkollha response_format.
shannon-2-lite u shannon-2-pro jirraġunaw qabel ma jwieġbu wkoll. Fuq dan l-endpoint jibagħtu linji ta' kummentarju : thinking waqt li jagħmlu dan, u mbagħad it-tweġiba.
reasoning_content mhuwiex fil-mudelli tipizzati tal-SDKs ta' OpenAI. Fi Python aqrah b'getattr(delta, "reasoning_content", None); f'JavaScript delta.reasoning_content jaħdem kif inhu.
Deltas ta' sejħiet ta' tools
Sejħa ta' tool tasal kollha: chunk wieħed għal kull sejħa, li d-delta tiegħu jżomm is-sejħa bl-istring kompluta ta' arguments. index iniżżel in-numri tas-sejħiet tat-tweġiba minn 0. Kodiċi li jgħaqqad arguments biċċa biċċa jaħdem mingħajr tibdil, għax jgħaqqad biċċa waħda.
{
"tool_calls": [
{
"index": 0,
"id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
} Wara s-sejħiet, l-aħħar chunk għandu finish_reason tool_calls.
Meta t-talba jkollha tools, shannon-1.6-lite, shannon-1.6-pro u shannon-coder-1 jibagħtu t-test tat-tweġiba bħala delta waħda fl-aħħar tat-tweġiba.
L-aħħar chunk
L-aħħar chunk qabel data: [DONE] għandu delta vojta, il-finish_reason u l-usage tat-talba, kollha fl-istess chunk. Kull stream għandu dan; ma teħtieġx 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
}
} Fuq il-mudelli open-weight ospitati usage għandu wkoll prompt_tokens_details.cached_tokens u completion_tokens_details.reasoning_tokens.
Wara talba b'web_search: true li t-tiftix tagħha sab xi ħaġa, l-aħħar chunk iġorr ukoll sources, u chunk wieħed qablu jġorr il-marki taċ-ċitazzjonijiet bħala delta.annotations. Tfittxija Web inkorporata
| finish_reason | Deskrizzjoni | Mibgħut minn |
|---|---|---|
stop | Il-mudell spiċċa t-tweġiba tiegħu, jew deher string stop. | Il-mudelli kollha |
tool_calls | It-tweġiba żżomm sejħa waħda jew aktar ta' tools. | Il-mudelli kollha |
length | It-tweġiba nqatgħet fil-limitu tal-output. | Familja Shannon 3, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 |
Il-kampi ta' usage huma deskritti mal-endpoint. Chat Completions
Linji keep-alive
Waqt li l-mudell jaħdem u għad m'għandu xejn x'jibgħat, l-istream iġorr linji ta' kummentarju. M'għandhom l-ebda data. Parser SSE jaqbeżhom waħdu; kodiċi li jaqra linji raw irid jaqbeż kull linja li tibda b'żewġ punti.
| Linja | Mibgħut minn | Meta |
|---|---|---|
: ping | Familja Shannon 3, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 | Kull 15-il sekonda. |
: keepalive | Mudelli open-weight ospitati | Kull 15-il sekonda waqt li l-mudell jaħdem. |
: thinking | shannon-2-lite, shannon-2-pro | Waqt li l-mudell jirraġuna. |
Żbalji ġewwa stream
Ladarba stream jibda l-istatus tiegħu huwa 200, għalhekk falliment jasal ġewwa l-istream: chunk b'membru error fejn kien ikun 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] Wara l-chunk tal-iżball jiġu wkoll l-aħħar chunk, b'finish_reason u usage, u data: [DONE]. Iċċekkja kull chunk għal error. Mingħajr dan il-kontroll tweġiba li fallet f'nofs triq tidher kompluta.
| Tip | Kodiċi | Messaġġ | Meta |
|---|---|---|---|
api_error | The model backend failed to answer. Please retry. | Il-mudell falla, jew ma kiteb xejn. Ibgħat it-talba mill-ġdid. | |
rate_limit_error | Shannon routes are temporarily busy. Please retry. | Il-mudell huwa impenjat f'dan il-mument. Stenna ftit sekondi u ibgħat it-talba mill-ġdid. | |
invalid_request_error | context_length_exceeded | Il-konversazzjoni hija itwal mit-tieqa tal-kuntest tal-mudell. Qassarha qabel ma tibgħatha mill-ġdid. It-test tal-messaġġ jvarja. |
Il-mudelli open-weight ospitati jibagħtu l-membru error b'type u message biss.
L-SDKs ta' OpenAI għal Python u JavaScript jgħollu chunk ta' żball bħala żball tal-API waqt li tiġġira fuqhom, għalhekk qiegħed iċ-ċiklu fil-ġestjoni tas-soltu tal-iżbalji.
Il-kodiċijiet ta' status, il-body tal-iżball u x'għandu jerġa' jiġi pprovat għandhom paġna tagħhom. Ġestjoni tal-iżbalji
Għeluq tal-konnessjoni
Jekk tagħlaq il-konnessjoni twaqqaf it-twassil, mhux it-talba. Il-mudell jikteb it-tweġiba sa tmiemha u t-talba titħallas daqs li kont qrajtha kollha. Biex tħallas inqas, itlob inqas: issettja max_tokens aktar baxx fuq mudell li japplikah.
Stream jista' jintemm kmieni wkoll fi triqtu lejk, pereżempju fuq waqfa tan-netwerk jew waqt li server jiġi aġġornat. Imbagħad jieqaf mingħajr l-aħħar chunk u mingħajr data: [DONE]. Qis dik it-tweġiba bħala mhux kompluta u ibgħat it-talba mill-ġdid.
Kif taqra stream mingħajr SDK
Qarrej korrett jagħmel ħames affarijiet: jibgħat l-iżbalji li jaslu qabel l-istream lill-ġestjoni tal-iżbalji tiegħu, jaqsam il-body f'linji, jaqbeż il-linji ta' kummentarju, jieqaf fi data: [DONE], u jiċċekkja kull chunk għal 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); L-eżempju ta' Python juża l-pakkett requests. L-eżempju ta' JavaScript jaħdem fuq Node.js 18 jew aktar tard.
Streams tal-formats l-oħra
L-endpoints Responses u Messages jagħmlu streaming ukoll. Il-frames tagħhom iġorru linja event: bl-isem tal-avveniment u linja data: bil-JSON tiegħu. Kull paġna telenka l-avvenimenti tagħha f'ordni.
| Fl-istream | Chat Completions | Responses | Messages |
|---|---|---|---|
| Frames | Linji data: | Linji event: u data: | Linji event: u data: |
| Ir-raġunament jasal f' | delta.reasoning_content | response.reasoning_summary_text.delta | thinking_delta |
| It-test tat-tweġiba jasal f' | delta.content | response.output_text.delta | text_delta |
| L-usage jasal f' | L-aħħar chunk | response.completed | message_delta |
| L-istream jintemm b' | L-aħħar chunk, imbagħad data: [DONE] | response.completed | message_stop |