Streaminga
Ezarri stream true gisa eta erantzuna server-sent events gisa iristen da modeloak idazten duen heinean: lehenengo arrazonamendua, gero erantzuna, gero azken chunk bat amaiera-arrazoiarekin eta erabilerarekin. Erabili pertsona bat testuaren zain dagoenean, eta erantzun luzeetarako.
POST https://api.shannon-ai.com/v1/chat/completions
OpenAI SDKek chunk-ak banan-banan ematen dizkizute. Irakurri chunk bakoitza daramanaren arabera: arrazonamendu zati bat, erantzunaren zati bat, tresna-dei bat, edo erantzunaren amaiera.
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 bat nola dago markotuta
- Erantzunak
200egoera etacontent-type: text/event-streametacache-control: no-cachegoiburuak ditu. - Gertaera bakoitza
data:-ekin hasten den lerro bat da, eta lerro huts bat dator ondoren.data:ondorengo testua JSON chunk bat da. Ez dagoevent:edoid:lerrorik. - Bi puntuekin hasten den lerro bat, adibidez
: ping, konexioa irekita mantentzen duen iruzkin bat da. Saltatu. - Streama
data: [DONE]-rekin amaitzen da. Hori gabe gelditzen den stream bat osatu gabea da.
Chunk-ak ordenan
Chunk bakoitza chat.completion.chunk objektu bat da:
{
"id": "chatcmpl-5f0c1e7a9b3d4c62a8e1f07d2b46c9a3",
"object": "chat.completion.chunk",
"created": 1791625200,
"model": "shannon-3",
"choices": [
{
"index": 0,
"delta": {
"content": "Server-sent"
},
"finish_reason": null
}
]
} Stream bateko chunk guztiek id, created eta model berak dituzte. choices-ek beti sarrera bakarra dauka. Bere delta-k berria dena dauka, eta finish_reason null da azken chunk-a arte.
| Gakoa delta-n | Mota | Deskribapena | Nork bidalia |
|---|---|---|---|
role | string | Beti assistant. Behin iristen da, streamaren hasieran. | Pisu irekiko modelo ostatatuak, shannon-2-lite, shannon-2-pro |
reasoning_content | string | Modeloaren arrazonamenduaren zati bat. Elkartu zatiak ordenan. | Pisu irekiko modelo ostatatuak, Shannon 3 familia, shannon-1.6-pro, shannon-coder-1 |
content | string | Erantzunaren zati bat. Elkartu zatiak ordenan. | Modelo guztiak |
tool_calls | array | Tresna-dei osatu bat. Ikusi Tool call deltas. | Modelo guztiak |
Arrazonamendua lehenengo dator, gero erantzuna, gero tresna-deiak. Irakurri chunk bat bere delta-ko gakoen arabera, ez streamean duen lekuaren arabera: delta batek role izan dezake testuaren lehen zatiarekin batera, eta azkena hutsik dago.
Stream oso bat bidean doan bezala. Lerroak laburrak izateko, id, object, created eta model chunk bakoitzetik kanpo utzi dira hemen.
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] Arrazonamendu-deltak
Arrazoitzen duen modelo batek bere arrazonamendua delta.reasoning_content-en bidaltzen du erantzunaren aurretik. Mantendu bi testuak bereizita: erakutsi arrazonamendua zati bereizi eta tolesgarri gisa, edo utzi kanpoan.
Pisu irekiko modelo ostatatuek ez dute arrazonamendurik bidaltzen reasoning_effort off denean, ezta eskaerak response_format bat duenean ere.
shannon-2-lite eta shannon-2-pro ere arrazoitu egiten dute erantzun aurretik. Endpoint honetan : thinking iruzkin-lerroak bidaltzen dituzte hori egiten duten bitartean, eta gero erantzuna.
reasoning_content ez dago OpenAI SDKen modelo tipatuetan. Python-en irakurri getattr(delta, "reasoning_content", None) erabiliz; JavaScript-en delta.reasoning_content bere horretan funtzionatzen du.
Tool call deltas
Tresna-dei bat osorik iristen da: chunk bat dei bakoitzeko, eta bere delta-k deia dauka arguments kate osoarekin. index-ek erantzunaren deiak 0tik zenbatzen ditu. arguments zati-zati elkartzen duen kodeak aldatu gabe funtzionatzen du, zati bakarra elkartzen baitu.
{
"tool_calls": [
{
"index": 0,
"id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
} Deien ondoren, azken chunk-ak finish_reason tool_calls du.
Eskaerak tools dituenean, shannon-1.6-lite, shannon-1.6-pro eta shannon-coder-1-ek erantzunaren testua delta bakar gisa bidaltzen dute erantzunaren amaieran.
Azken chunk-a
data: [DONE] baino lehenagoko azken chunk-ak delta hutsa, finish_reason eta eskaeraren usage ditu, guztiak chunk berean. Stream guztiek dute; ez duzu stream_options behar.
{
"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
}
} Pisu irekiko modelo ostatatuetan usage-k prompt_tokens_details.cached_tokens eta completion_tokens_details.reasoning_tokens ere baditu.
web_search: true duen eskaera baten ondoren, azken chunk-ak sources ere badauka, eta haren aurreko chunk batek aipu-markak darama delta.annotations gisa. Web bilaketa
| finish_reason | Deskribapena | Nork bidalia |
|---|---|---|
stop | Modeloak erantzuna amaitu du, edo stop kate bat agertu da. | Modelo guztiak |
tool_calls | Erantzunak tresna-dei bat edo gehiago ditu. | Modelo guztiak |
length | Erantzuna irteera-mugan moztu zen. | Shannon 3 familia, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 |
usage-ren eremuak endpointarekin batera azaltzen dira. Chat Completions
Keep-alive lerroak
Modeloak lan egiten duen bitartean eta oraindik bidaltzeko ezer ez duenean, streamak iruzkin-lerroak darama. Ez dute daturik. SSE parser batek berez saltatzen ditu; lerro gordinak irakurtzen dituen kodeak bi puntuekin hasten den lerro guztiak saltatu behar ditu.
| Lerroa | Nork bidalia | Noiz |
|---|---|---|
: ping | Shannon 3 familia, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 | 15 segundoz behin. |
: keepalive | Pisu irekiko modelo ostatatuak | 15 segundoz behin modeloak lan egiten duen bitartean. |
: thinking | shannon-2-lite, shannon-2-pro | Modeloak arrazoitzen duen bitartean. |
Stream baten barruko erroreak
Stream bat hasi ondoren bere egoera 200 da, beraz hutsegitea streamaren barruan iristen da: choices egongo zen lekuan error kidea duen chunk bat.
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] Errore-chunk-aren ondoren azken chunk-a, finish_reason eta usage dituena, eta data: [DONE] ere badatoz. Egiaztatu chunk bakoitzean error dagoen. Egiaztapen hori gabe, erdian huts egin duen erantzun bat osorik dagoela ematen du.
| Mota | Kodea | Mezua | Noiz |
|---|---|---|---|
api_error | The model backend failed to answer. Please retry. | Modeloak huts egin du, edo ez du ezer idatzi. Bidali eskaera berriro. | |
rate_limit_error | Shannon routes are temporarily busy. Please retry. | Modeloa lanpetuta dago une honetan. Itxaron segundo batzuk eta bidali eskaera berriro. | |
invalid_request_error | context_length_exceeded | Elkarrizketa modeloaren context window-a baino luzeagoa da. Laburtu bidali aurretik. Mezuaren testua aldatu egiten da. |
Pisu irekiko modelo ostatatuek error kidea type eta message soilik dituela bidaltzen dute.
OpenAI Python eta JavaScript SDKek errore-chunk bat API errore gisa jaurtitzen dute iteratzen ari zaren bitartean, beraz bildu begizta zure ohiko errore-kudeaketan.
Egoera-kodeek, errore-gorputzak eta zer berriz saiatu behar den beren orria dute. Errore‑kudeaketa
Konexioa ixtea
Konexioa ixteak entrega gelditzen du, ez eskaera. Modeloak erantzuna amaierara arte idazten du eta eskaera osorik irakurri bazenu bezala kobratzen da. Gutxiago ordaintzeko, eskatu gutxiago: ezarri max_tokens txikiago bat hura aplikatzen duen modelo batean.
Stream bat zuregana bidean ere amaitu daiteke goizegi, adibidez sare-etenaldi batean edo zerbitzari bat eguneratzen ari denean. Orduan azken chunk-a gabe eta data: [DONE] gabe gelditzen da. Hartu erantzun hori osatu gabetzat eta bidali eskaera berriro.
Stream bat SDKrik gabe irakurtzea
Irakurle zuzen batek bost gauza egiten ditu: streamaren aurretik iristen diren erroreak bere errore-kudeaketara bidaltzen ditu, gorputza lerrotan banatzen du, iruzkin-lerroak saltatzen ditu, data: [DONE]-n gelditzen da, eta chunk bakoitzean error dagoen egiaztatzen du.
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 adibideak requests paketea erabiltzen du. JavaScript adibidea Node.js 18 edo berriagoan exekutatzen da.
Beste formatuetako streamak
Responses eta Messages endpointek ere streaming egiten dute. Haien frame-ek gertaeraren izena duen event: lerro bat eta bere JSON duen data: lerro bat daramate. Orri bakoitzak bere gertaerak ordenan zerrendatzen ditu.
| Streamean | Chat Completions | Responses | Messages |
|---|---|---|---|
| Frame-ak | data: lerroak | event: eta data: lerroak | event: eta data: lerroak |
| Arrazonamendua hemen iristen da | delta.reasoning_content | response.reasoning_summary_text.delta | thinking_delta |
| Erantzunaren testua hemen iristen da | delta.content | response.output_text.delta | text_delta |
| Erabilera hemen iristen da | Azken chunk-a | response.completed | message_delta |
| Streama honekin amaitzen da | Azken chunk-a, gero data: [DONE] | response.completed | message_stop |