Oqim
stream'ni true qiling va javob model yozayotgan paytda server-sent events sifatida keladi: avval mulohaza, keyin javob, so'ng tugash sababi va usage bilan oxirgi chunk. Undan matnni inson kutayotganda va uzun javoblar uchun foydalaning.
POST https://api.shannon-ai.com/v1/chat/completions
OpenAI SDK'lar chunk'larni bittadan beradi. Har bir chunk'ni u nima olib kelishiga qarab o'qing: mulohaza bo'lagi, javob bo'lagi, tool chaqiruvi yoki javob oxiri.
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
}' Oqim qanday freymlanadi
- Javob
200holati hamdacontent-type: text/event-streamvacache-control: no-cachesarlavhalari bilan keladi. - Har bir hodisa
data:bilan boshlanadigan va bo'sh satr ergashadigan bitta satr.data:dan keyingi matn bitta JSON chunk'i.event:yokiid:satrlari yo'q. : pingkabi ikki nuqta bilan boshlanadigan satr ulanishni ochiq ushlab turadigan izoh. Uni o'tkazib yuboring.- Oqim
data: [DONE]bilan tugaydi. Usiz to'xtagan oqim to'liq emas.
Chunk'lar tartibda
Har bir chunk — chat.completion.chunk obyekti:
{
"id": "chatcmpl-5f0c1e7a9b3d4c62a8e1f07d2b46c9a3",
"object": "chat.completion.chunk",
"created": 1791625200,
"model": "shannon-3",
"choices": [
{
"index": 0,
"delta": {
"content": "Server-sent"
},
"finish_reason": null
}
]
} Bitta oqimning barcha chunk'lari bir xil id, created va modelni olib keladi. choices doim bitta yozuvni o'z ichiga oladi. Uning deltasi yangi narsani, finish_reason esa oxirgi chunk'gacha null.
| Delta'dagi kalit | Tur | Tavsif | Yuboruvchi |
|---|---|---|---|
role | string | Doim assistant. U oqim boshida bir marta keladi. | Xostingdagi open-weight modellar, shannon-2-lite, shannon-2-pro |
reasoning_content | string | Modelning mulohazasidan bir bo'lak. Bo'laklarni tartib bilan birlashtiring. | Xostingdagi open-weight modellar, Shannon 3 oilasi, shannon-1.6-pro, shannon-coder-1 |
content | string | Javobning bir bo'lagi. Bo'laklarni tartib bilan birlashtiring. | Barcha modellar |
tool_calls | array | Bitta to'liq tool chaqiruvi. Tool chaqiruv deltalariga qarang. | Barcha modellar |
Avval mulohaza, keyin javob, keyin tool chaqiruvlari keladi. Chunk'ni oqimdagi o'rni bo'yicha emas, deltadagi kalitlar bo'yicha o'qing: delta roleni matnning birinchi bo'lagi bilan birga olib kelishi mumkin, oxirgisi esa bo'sh.
Butun oqim yo'ldagidek. Satrlarni qisqa tutish uchun bu yerda har bir chunk'dan id, object, created va model chiqarib tashlangan.
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] Mulohaza deltalari
Mulohaza qiladigan model o'z mulohazasini javobdan oldin delta.reasoning_contentda yuboradi. Ikki matnni ajrating: mulohazani alohida, yig'iladigan qism sifatida ko'rsating yoki tashlab yuboring.
Xostingdagi open-weight modellar reasoning_effort off bo'lganda mulohaza yubormaydi, so'rovda response_format bo'lganda ham yubormaydi.
shannon-2-lite va shannon-2-pro ham javob berishdan oldin mulohaza qiladi. Bu endpointda ular mulohaza qilayotganda : thinking izoh satrlarini, keyin javobni yuboradi.
reasoning_content OpenAI SDK'larning tiplangan modellarida yo'q. Python'da uni getattr(delta, "reasoning_content", None) bilan o'qing; JavaScript'da delta.reasoning_content o'z holicha ishlaydi.
Tool chaqiruv deltalari
Tool chaqiruvi butunligicha keladi: har bir chaqiruvga bitta chunk, uning deltasi chaqiruvni to'liq arguments satri bilan o'z ichiga oladi. index javob chaqiruvlarini 0 dan raqamlaydi. argumentsni bo'lak-bo'lak birlashtiradigan kod o'zgarishsiz ishlaydi, chunki u bitta bo'lakni birlashtiradi.
{
"tool_calls": [
{
"index": 0,
"id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
} Chaqiruvlardan keyin oxirgi chunk'da finish_reason tool_calls bo'ladi.
So'rovda tools bo'lganda shannon-1.6-lite, shannon-1.6-pro va shannon-coder-1 javob matnini javob oxirida bitta deltada yuboradi.
Oxirgi chunk
data: [DONE]dan oldingi oxirgi chunk'da bo'sh delta, finish_reason va so'rovning usagei bor, hammasi bir chunk'da. Uni har bir oqim olib keladi; stream_options kerak emas.
{
"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
}
} Xostingdagi open-weight modellarda usageda prompt_tokens_details.cached_tokens va completion_tokens_details.reasoning_tokens ham bor.
Qidiruvi nimadir topgan web_search: true so'rovidan keyin oxirgi chunk sources ni ham olib keladi, undan oldingi bitta chunk esa iqtibos belgilarini delta.annotations sifatida olib keladi. O‘rnatilgan veb qidiruv
| finish_reason | Tavsif | Yuboruvchi |
|---|---|---|
stop | Model javobini tugatdi yoki stop satri paydo bo'ldi. | Barcha modellar |
tool_calls | Javobda bir yoki bir nechta tool chaqiruvi bor. | Barcha modellar |
length | Javob chiqish limitida uzildi. | Shannon 3 oilasi, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 |
usage maydonlari endpoint bilan birga tasvirlangan. Chat Completions
Keep-alive satrlari
Model ishlayotgan va hali yuboradigan narsasi bo'lmagan paytda oqim izoh satrlarini olib keladi. Ularda ma'lumot yo'q. SSE parseri ularni o'zi o'tkazib yuboradi; xom satrlarni o'qiydigan kod ikki nuqta bilan boshlanadigan har bir satrni o'tkazib yuborishi kerak.
| Satr | Yuboruvchi | Qachon |
|---|---|---|
: ping | Shannon 3 oilasi, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 | Har 15 soniyada. |
: keepalive | Xostingdagi open-weight modellar | Model ishlayotgan paytda har 15 soniyada. |
: thinking | shannon-2-lite, shannon-2-pro | Model mulohaza qilayotgan paytda. |
Oqim ichidagi xatolar
Oqim boshlangach uning holati 200, shuning uchun nosozlik oqim ichida keladi: choices bo'ladigan joyda error a'zosi bor chunk.
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] Xato chunk'idan keyin finish_reason va usageli oxirgi chunk va data: [DONE] baribir ergashadi. Har bir chunk'ni error uchun tekshiring. Bu tekshiruvsiz yarim yo'lda muvaffaqiyatsiz bo'lgan javob to'liq ko'rinadi.
| Tur | Kod | Xabar | Qachon |
|---|---|---|---|
api_error | The model backend failed to answer. Please retry. | Model muvaffaqiyatsiz bo'ldi yoki hech narsa yozmadi. So'rovni qayta yuboring. | |
rate_limit_error | Shannon routes are temporarily busy. Please retry. | Model hozir band. Bir necha soniya kuting va so'rovni qayta yuboring. | |
invalid_request_error | context_length_exceeded | Suhbat modelning kontekst oynasidan uzun. Qayta yuborishdan oldin uni qisqartiring. Xabar matni o'zgaruvchan. |
Xostingdagi open-weight modellar error a'zosini faqat type va message bilan yuboradi.
OpenAI Python va JavaScript SDK'lari siz iteratsiya qilayotganda xato chunk'ini API xatosi sifatida ko'taradi, shuning uchun siklni odatdagi xatolarni qayta ishlash bilan o'rang.
Holat kodlari, xato tanasi va nimani qayta urinish kerakligi o'z sahifasida. Xatolarni boshqarish
Ulanishni yopish
Ulanishni yopish yetkazishni to'xtatadi, so'rovni emas. Model javobni oxirigacha yozadi va so'rov butun javobni o'qiganingizdek hisoblanadi. Kamroq to'lash uchun kamroq so'rang: uni qo'llaydigan modelda pastroq max_tokens o'rnating.
Oqim sizga yo'lda ham erta tugashi mumkin, masalan tarmoq uzilganda yoki server yangilanayotganda. Shunda u oxirgi chunk'siz va data: [DONE]siz to'xtaydi. Bunday javobni to'liq emas deb hisoblang va so'rovni qayta yuboring.
Oqimni SDK'siz o'qish
To'g'ri o'quvchi beshta ish qiladi: oqimdan oldin kelgan xatolarni o'z xato ishlovchisiga yuboradi, tanani satrlarga ajratadi, izoh satrlarini o'tkazib yuboradi, data: [DONE]da to'xtaydi va har bir chunk'ni error uchun tekshiradi.
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 namunasi requests paketidan foydalanadi. JavaScript namunasi Node.js 18 yoki undan yangisida ishlaydi.
Boshqa formatlarning oqimlari
Responses va Messages endpointlari ham streaming qiladi. Ularning freymlari hodisa nomi bilan event: satrini va uning JSON'i bilan data: satrini olib keladi. Har bir sahifa o'z hodisalarini tartibda sanab beradi.
| Oqimda | Chat Completions | Responses | Messages |
|---|---|---|---|
| Freymlar | data: satrlari | event: va data: satrlari | event: va data: satrlari |
| Mulohaza shu yerda keladi | delta.reasoning_content | response.reasoning_summary_text.delta | thinking_delta |
| Javob matni shu yerda keladi | delta.content | response.output_text.delta | text_delta |
| Usage shu yerda keladi | Oxirgi chunk | response.completed | message_delta |
| Oqim shu bilan tugaydi | Oxirgi chunk, keyin data: [DONE] | response.completed | message_stop |