Voogedastus
Määra stream väärtuseks true ja vastus saabub server-sent events kujul, kuni mudel seda kirjutab: kõigepealt arutlus, siis vastus, siis viimane chunk lõpetamise põhjuse ja kasutusega. Kasuta seda alati, kui inimene teksti ootab, ja pikkade vastuste puhul.
POST https://api.shannon-ai.com/v1/chat/completions
OpenAI SDK-d annavad sulle chunkid ükshaaval. Loe iga chunki selle järgi, mida see kannab: arutluse tükk, vastuse tükk, tööriistakutse või vastuse lõpp.
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
}' Kuidas voog on kaadritesse jaotatud
- Vastuse olek on
200ning päisedcontent-type: text/event-streamjacache-control: no-cache. - Iga sündmus on üks rida, mis algab
data:ja millele järgneb tühi rida. Tekst pärastdata:on üks JSON-chunk. Riduevent:võiid:ei ole. - Rida, mis algab koolon, näiteks
: ping, on kommentaar, mis hoiab ühenduse avatuna. Jäta see vahele. - Voog lõpeb
data: [DONE]. Voog, mis peatub ilma selleta, on poolik.
Chunkid järjekorras
Iga chunk on chat.completion.chunk objekt:
{
"id": "chatcmpl-5f0c1e7a9b3d4c62a8e1f07d2b46c9a3",
"object": "chat.completion.chunk",
"created": 1791625200,
"model": "shannon-3",
"choices": [
{
"index": 0,
"delta": {
"content": "Server-sent"
},
"finish_reason": null
}
]
} Ühe voo kõik chunkid kannavad sama id, created ja model. choices sisaldab alati ühte kirjet. Selle delta sisaldab uut ja finish_reason on null viimase chunkini.
| Võti väljas delta | Tüüp | Kirjeldus | Saadab |
|---|---|---|---|
role | string | Alati assistant. See saabub üks kord, voo alguses. | Hostitud avatud kaaludega mudelid, shannon-2-lite, shannon-2-pro |
reasoning_content | string | Mudeli arutluse tükk. Ühenda tükid järjekorras. | Hostitud avatud kaaludega mudelid, Shannon 3 perekond, shannon-1.6-pro, shannon-coder-1 |
content | string | Vastuse tükk. Ühenda tükid järjekorras. | Kõik mudelid |
tool_calls | array | Üks täielik tööriistakutse. Vaata Tööriistakutse deltad. | Kõik mudelid |
Esimesena tuleb arutlus, seejärel vastus, seejärel tööriistakutsed. Loe chunki oma delta võtmete, mitte voos oleva koha järgi: delta võib sisaldada role koos esimese tekstitükiga ja viimane on tühi.
Terve voog nii, nagu see liigub. Ridade lühendamiseks on id, object, created ja model siin igast chunkist välja jäetud.
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] Arutluse deltad
Arutlev mudel saadab oma arutluse väljal delta.reasoning_content enne vastust. Hoia need kaks teksti lahus: näita arutlust eraldi, kokku volditava osana, või jäta see välja.
Hostitud avatud kaaludega mudelid ei saada arutlust, kui reasoning_effort on off, ega ka siis, kui päringul on response_format.
shannon-2-lite ja shannon-2-pro arutlevad enne vastamist samuti. Selles lõpp-punktis saadavad nad arutlemise ajal kommentaarirealisi : thinking ja seejärel vastuse.
reasoning_content ei ole OpenAI SDK-de tüübitud mudelites. Pythonis loe seda getattr(delta, "reasoning_content", None) abil; JavaScriptis töötab delta.reasoning_content nii, nagu see on.
Tööriistakutse deltad
Tööriistakutse saabub tervikuna: üks chunk kutse kohta, mille delta sisaldab kutset koos täieliku arguments stringiga. index nummerdab vastuse kutseid alates 0. Kood, mis ühendab arguments tükkhaaval, töötab muutmata kujul, sest see ühendab ühe tüki.
{
"tool_calls": [
{
"index": 0,
"id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
} Pärast kutseid on viimasel chunkil finish_reason tool_calls.
Kui päringul on tools, saadavad shannon-1.6-lite, shannon-1.6-pro ja shannon-coder-1 vastuse teksti ühe deltana vastuse lõpus.
Viimane chunk
Viimasel chunkil enne data: [DONE] on tühi delta, finish_reason ja päringu usage, kõik samas chunkis. Igal voos see on; stream_options ei ole vaja.
{
"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
}
} Hostitud avatud kaaludega mudelitel on usage hulgas ka prompt_tokens_details.cached_tokens ja completion_tokens_details.reasoning_tokens.
Pärast päringut, milles on web_search: true ja mille otsing leidis midagi, kannab viimane chunk ka sources ning üks chunk enne seda kannab viitemärgid kujul delta.annotations. Veebiotsing
| finish_reason | Kirjeldus | Saadab |
|---|---|---|
stop | Mudel lõpetas vastuse või ilmus üks stop string. | Kõik mudelid |
tool_calls | Vastus sisaldab ühte või mitut tööriistakutset. | Kõik mudelid |
length | Vastus katkestati väljundi piirangu juures. | Shannon 3 perekond, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 |
Välja usage kirjeldatakse lõpp-punkti juures. Chat Completions
Keep-alive read
Kuni mudel töötab ja tal pole veel midagi saata, kannab voog kommentaarirealisi. Need ei sisalda andmeid. SSE parser jätab need ise vahele; kood, mis loeb toorridu, peab vahele jätma iga rea, mis algab koolonaga.
| Rida | Saadab | Millal |
|---|---|---|
: ping | Shannon 3 perekond, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 | Iga 15 sekundi järel. |
: keepalive | Hostitud avatud kaaludega mudelid | Iga 15 sekundi järel, kuni mudel töötab. |
: thinking | shannon-2-lite, shannon-2-pro | Kuni mudel arutleb. |
Vead voo sees
Kui voog on alanud, on selle olek 200, seega saabub tõrge voo sees: chunk, millel on error liige seal, kus oleks 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] Pärast veachunki järgnevad siiski viimane chunk koos finish_reason ja usage ning data: [DONE]. Kontrolli iga chunki error suhtes. Ilma selle kontrollita näeb pooleldi ebaõnnestunud vastus välja täielik.
| Tüüp | Kood | Teade | Millal |
|---|---|---|---|
api_error | The model backend failed to answer. Please retry. | Mudel ebaõnnestus või ei kirjutanud midagi. Saada päring uuesti. | |
rate_limit_error | Shannon routes are temporarily busy. Please retry. | Mudel on praegu hõivatud. Oota mõni sekund ja saada päring uuesti. | |
invalid_request_error | context_length_exceeded | Vestlus on pikem kui mudeli kontekstiaken. Lühenda seda enne uuesti saatmist. Teate tekst varieerub. |
Hostitud avatud kaaludega mudelid saadavad error liikme ainult väljadega type ja message.
OpenAI Python ja JavaScript SDK-d tõstavad veachunki API veana, kuni itereerid, seega mähi tsükkel oma tavalisse veakäsitlusse.
Olekukoodidel, vea sisul ja sellel, mida korrata, on oma leht. Vigade käsitlus
Ühenduse sulgemine
Ühenduse sulgemine peatab edastamise, mitte päringu. Mudel kirjutab vastuse lõpuni ja päringu eest arveldatakse nii, nagu oleksid selle kõik läbi lugenud. Vähema eest maksmiseks küsi vähem: määra madalam max_tokens mudelil, mis seda rakendab.
Voog võib ka teel sinuni varakult lõppeda, näiteks võrgukatkestuse korral või serveri uuendamise ajal. Siis peatub see ilma viimase chunkita ja ilma data: [DONE]. Käsitle sellist vastust poolikuna ja saada päring uuesti.
Voo lugemine ilma SDK-ta
Õige lugeja teeb viit asja: suunab enne voogu saabuvad vead oma veakäsitlusse, jagab sisu ridadeks, jätab kommentaarread vahele, peatub data: [DONE] juures ja kontrollib iga chunki error suhtes.
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); Pythoni näide kasutab paketti requests. JavaScripti näide töötab Node.js 18 või uuemaga.
Teiste formaatide voogud
Ka lõpp-punktid Responses ja Messages voogedastavad. Nende kaadrid kannavad event:-rida sündmuse nimega ja data:-rida selle JSON-iga. Iga leht loetleb oma sündmused järjekorras.
| Voos | Chat Completions | Responses | Messages |
|---|---|---|---|
| Kaadrid | data: read | event: ja data: read | event: ja data: read |
| Arutlus saabub | delta.reasoning_content | response.reasoning_summary_text.delta | thinking_delta |
| Vastuse tekst saabub | delta.content | response.output_text.delta | text_delta |
| Kasutus saabub | Viimane chunk | response.completed | message_delta |
| Voog lõpeb | Viimane chunk, seejärel data: [DONE] | response.completed | message_stop |