Sisanwọle
Ṣètò stream sí true, èsì sì ń dé bí server-sent events bí model ṣe ń kọ ọ́: ìrònú ní àkọ́kọ́, lẹ́yìn náà ìdáhùn, lẹ́yìn náà chunk tó gbẹ̀yìn pẹ̀lú ìdí ìparí àti usage. Lò ó nígbà gbogbo tí ènìyàn bá ń dúró de ọ̀rọ̀ náà, àti fún àwọn èsì gígùn.
POST https://api.shannon-ai.com/v1/chat/completions
Àwọn SDK OpenAI ń fún ọ ní àwọn chunk ọ̀kọ̀ọ̀kan. Ka chunk kọ̀ọ̀kan nípasẹ̀ ohun tó gbé: ègé ìrònú, ègé ìdáhùn, ìpè tool, tàbí òpin èsì.
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
}' Bí a ṣe ń ṣe frame stream
- Èsì ní status
200àti àwọn headercontent-type: text/event-streamàticache-control: no-cache. - Event kọ̀ọ̀kan jẹ́ ìlà kan tó bẹ̀rẹ̀ pẹ̀lú
data:tí ìlà òfo tẹ̀lé. Ọ̀rọ̀ lẹ́yìndata:jẹ́ chunk JSON kan. Kò sí àwọn ìlàevent:tàbíid:. - Ìlà tó bẹ̀rẹ̀ pẹ̀lú àmì colon, bíi
: ping, jẹ́ ọ̀rọ̀ ìṣàlàyé tó ń jẹ́ kí asopọ̀ ṣí. Fò ó. - Stream ń parí pẹ̀lú
data: [DONE]. Stream tó dúró láìsí i jẹ́ aláìpé.
Àwọn chunk lẹ́sẹẹsẹ
Chunk kọ̀ọ̀kan jẹ́ object 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
}
]
} Gbogbo chunk ti stream kan ń gbé id, created àti model kan náà. choices máa ń ní ìkọ̀sílẹ̀ kan. delta rẹ̀ ní ohun tuntun, finish_reason sì jẹ́ null títí di chunk tó gbẹ̀yìn.
| Key nínú delta | Irú | Àpèjúwe | Ẹni tó fi ránṣẹ́ |
|---|---|---|---|
role | string | Nígbà gbogbo assistant. Ó ń dé lẹ́ẹ̀kan, ní ìbẹ̀rẹ̀ stream. | Àwọn model open-weight tí a gbàlejò, shannon-2-lite, shannon-2-pro |
reasoning_content | string | Ègé ìrònú model. So àwọn ègé náà pọ̀ lẹ́sẹẹsẹ. | Àwọn model open-weight tí a gbàlejò, ìdílé Shannon 3, shannon-1.6-pro, shannon-coder-1 |
content | string | Ègé ìdáhùn. So àwọn ègé náà pọ̀ lẹ́sẹẹsẹ. | Gbogbo model |
tool_calls | array | Ìpè tool pípé kan. Wo Àwọn delta ìpè tool. | Gbogbo model |
Ìrònú ló kọ́kọ́ dé, lẹ́yìn náà ìdáhùn, lẹ́yìn náà àwọn ìpè tool èyíkéyìí. Ka chunk nípasẹ̀ àwọn key inú delta rẹ̀, kì í ṣe nípasẹ̀ ipò rẹ̀ nínú stream: delta lè ní role pẹ̀lú ègé ọ̀rọ̀ àkọ́kọ́, èyí tó gbẹ̀yìn sì jẹ́ òfo.
Gbogbo stream bí ó ṣe ń rìn. Láti jẹ́ kí àwọn ìlà kúrú, a fi id, object, created àti model sílẹ̀ kúrò nínú chunk kọ̀ọ̀kan níbí.
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] Àwọn delta ìrònú
Model tó ń ronú ń fi ìrònú rẹ̀ ránṣẹ́ nínú delta.reasoning_content ṣáájú ìdáhùn. Pa àwọn ọ̀rọ̀ méjèèjì mọ́ lọ́tọ̀ọ̀tọ̀: fi ìrònú hàn bí apá tó yàtọ̀ tí a lè pa dé, tàbí fi sílẹ̀.
Àwọn model open-weight tí a gbàlejò kì í fi ìrònú ránṣẹ́ nígbà tí reasoning_effort bá jẹ́ off, tàbí nígbà tí ìbéèrè bá ní response_format.
shannon-2-lite àti shannon-2-pro náà ń ronú kí wọ́n tó dáhùn. Lórí endpoint yìí, wọ́n ń fi àwọn ìlà ọ̀rọ̀ ìṣàlàyé : thinking ránṣẹ́ nígbà tí wọ́n bá ń ṣe bẹ́ẹ̀, lẹ́yìn náà ìdáhùn.
reasoning_content kò sí nínú àwọn typed model ti SDK OpenAI. Nínú Python, ka á pẹ̀lú getattr(delta, "reasoning_content", None); nínú JavaScript, delta.reasoning_content ń ṣiṣẹ́ bí ó ṣe wà.
Àwọn delta ìpè tool
Ìpè tool ń dé ní kíkún: chunk kan fún ìpè kọ̀ọ̀kan, tí delta rẹ̀ gbé ìpè náà pẹ̀lú string arguments pípé. index ń nọ́ńbà àwọn ìpè èsì láti 0. Code tó ń so arguments pọ̀ ègé-ègé ń ṣiṣẹ́ láìyípadà, nítorí ó ń so ègé kan.
{
"tool_calls": [
{
"index": 0,
"id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
} Lẹ́yìn àwọn ìpè, chunk tó gbẹ̀yìn ní finish_reason tool_calls.
Nígbà tí ìbéèrè bá ní tools, shannon-1.6-lite, shannon-1.6-pro àti shannon-coder-1 ń fi ọ̀rọ̀ ìdáhùn ránṣẹ́ bí delta kan ní òpin èsì.
Chunk tó gbẹ̀yìn
Chunk tó gbẹ̀yìn ṣáájú data: [DONE] ní delta òfo, finish_reason àti usage ti ìbéèrè náà, gbogbo wọn nínú chunk kan náà. Gbogbo stream ní i; o kò nílò 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
}
} Lórí àwọn model open-weight tí a gbàlejò, usage tún ní prompt_tokens_details.cached_tokens àti completion_tokens_details.reasoning_tokens.
Lẹ́yìn ìbéèrè tó ní web_search: true tí ìwádìí rẹ̀ rí nǹkan, chunk ìkẹyìn tún ní sources, chunk kan ṣáájú rẹ̀ sì ní àwọn àmì ìtọ́kasí gẹ́gẹ́ bí delta.annotations. Iwadi Wẹẹbu ti a ṣe sinu
| finish_reason | Àpèjúwe | Ẹni tó fi ránṣẹ́ |
|---|---|---|
stop | Model parí ìdáhùn rẹ̀, tàbí string stop kan hàn. | Gbogbo model |
tool_calls | Èsì ní ìpè tool kan tàbí jù bẹ́ẹ̀ lọ. | Gbogbo model |
length | A gé èsì náà ní ààlà output. | Ìdílé Shannon 3, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 |
A ṣàpèjúwe àwọn field ti usage pẹ̀lú endpoint. Chat Completions
Àwọn ìlà keep-alive
Nígbà tí model ń ṣiṣẹ́ tí kò sì tíì ní nǹkan láti fi ránṣẹ́, stream ń gbé àwọn ìlà ọ̀rọ̀ ìṣàlàyé. Wọn kò ní data. Parser SSE ń fò wọ́n fúnra rẹ̀; code tó ń ka àwọn ìlà aláìṣàtúnṣe gbọdọ̀ fo gbogbo ìlà tó bá bẹ̀rẹ̀ pẹ̀lú colon.
| Ìlà | Ẹni tó fi ránṣẹ́ | Nígbà wo |
|---|---|---|
: ping | Ìdílé Shannon 3, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 | Ní ìṣẹ́jú-àáyá 15 kọ̀ọ̀kan. |
: keepalive | Àwọn model open-weight tí a gbàlejò | Ní ìṣẹ́jú-àáyá 15 kọ̀ọ̀kan nígbà tí model ń ṣiṣẹ́. |
: thinking | shannon-2-lite, shannon-2-pro | Nígbà tí model ń ronú. |
Àwọn àṣìṣe inú stream
Nígbà tí stream bá ti bẹ̀rẹ̀, status rẹ̀ jẹ́ 200, nítorí náà ìkùnà ń dé nínú stream: chunk pẹ̀lú ẹ̀yà error níbi tí choices yóò wà.
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] Lẹ́yìn chunk àṣìṣe, chunk tó gbẹ̀yìn, pẹ̀lú finish_reason àti usage, àti data: [DONE] ṣì tẹ̀lé e. Ṣàyẹ̀wò gbogbo chunk fún error. Láìsí ìṣàyẹ̀wò yẹn, èsì tó kùnà láàrín ọ̀nà dà bí èyí tó pé.
| Irú | Code | Ìfiránṣẹ́ | Nígbà wo |
|---|---|---|---|
api_error | The model backend failed to answer. Please retry. | Model kùnà, tàbí kò kọ nǹkankan. Tún fi ìbéèrè náà ránṣẹ́. | |
rate_limit_error | Shannon routes are temporarily busy. Please retry. | Model kún lọ́wọ́ ní àkókò yìí. Dúró ìṣẹ́jú-àáyá díẹ̀ kí o sì tún fi ìbéèrè náà ránṣẹ́. | |
invalid_request_error | context_length_exceeded | Ìjíròrò gùn ju context window ti model. Dín in kù kí o tó tún fi ránṣẹ́. Ọ̀rọ̀ ìfiránṣẹ́ náà ń yàtọ̀. |
Àwọn model open-weight tí a gbàlejò ń fi ẹ̀yà error ránṣẹ́ pẹ̀lú type àti message nìkan.
Àwọn SDK OpenAI Python àti JavaScript ń gbé chunk àṣìṣe sókè bí àṣìṣe API nígbà tí o bá ń yípo, nítorí náà fi ìtọ́jú àṣìṣe àtọwọ́dọ́wọ́ rẹ yí loop náà ká.
Àwọn status code, body àṣìṣe àti ohun tí a ó tún gbìyànjú ní ojú-ìwé tiwọn. Mimu Aṣiṣe
Pípa asopọ̀
Pípa asopọ̀ dé ń dá ìfijiṣẹ́ dúró, kì í ṣe ìbéèrè náà. Model ń kọ èsì dé òpin rẹ̀, a sì ń gba owó ìbéèrè náà bí ẹni pé o ti ka gbogbo rẹ̀. Láti sanwó díẹ̀, béèrè fún díẹ̀: ṣètò max_tokens tó kéré jù lórí model tó ń lò ó.
Stream tún lè parí ní kùtùkùtù lójú ọ̀nà rẹ̀ sí ọ, fún àpẹẹrẹ nígbà tí nẹ́tíwọ́ọ̀kì bá já tàbí nígbà tí a ń ṣàtúnṣe server. Ó máa dúró láìsí chunk tó gbẹ̀yìn àti láìsí data: [DONE]. Ka èsì yẹn sí aláìpé kí o sì tún fi ìbéèrè náà ránṣẹ́.
Kíka stream láìsí SDK
Olùkà tó tọ̀ ń ṣe nǹkan márùn-ún: ó ń fi àwọn àṣìṣe tó dé ṣáájú stream ránṣẹ́ sí ìtọ́jú àṣìṣe rẹ̀, ó ń pín body sí àwọn ìlà, ó ń fo àwọn ìlà ọ̀rọ̀ ìṣàlàyé, ó ń dúró ní data: [DONE], ó sì ń ṣàyẹ̀wò chunk kọ̀ọ̀kan fún 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); Àpẹẹrẹ Python ń lo package requests. Àpẹẹrẹ JavaScript ń ṣiṣẹ́ lórí Node.js 18 tàbí tó ga jù.
Àwọn stream ti àwọn ọ̀nà mìíràn
Àwọn endpoint Responses àti Messages náà ń ṣe streaming. Àwọn frame wọn ń gbé ìlà event: pẹ̀lú orúkọ event àti ìlà data: pẹ̀lú JSON rẹ̀. Ojú-ìwé kọ̀ọ̀kan ń ṣàkójọ àwọn event rẹ̀ lẹ́sẹẹsẹ.
| Nínú stream | Chat Completions | Responses | Messages |
|---|---|---|---|
| Àwọn frame | Àwọn ìlà data: | Àwọn ìlà event: àti data: | Àwọn ìlà event: àti data: |
| Ìrònú ń dé nínú | delta.reasoning_content | response.reasoning_summary_text.delta | thinking_delta |
| Ọ̀rọ̀ ìdáhùn ń dé nínú | delta.content | response.output_text.delta | text_delta |
| Usage ń dé nínú | Chunk tó gbẹ̀yìn | response.completed | message_delta |
| Stream ń parí pẹ̀lú | Chunk tó gbẹ̀yìn, lẹ́yìn náà data: [DONE] | response.completed | message_stop |