Axın
Stream-i true təyin edin və cavab model onu yazarkən server-sent events kimi gəlir: əvvəl reasoning, sonra cavab, sonra bitmə səbəbi və usage ilə son chunk. Mətni insan gözlədikdə və uzun cavablar üçün istifadə edin.
POST https://api.shannon-ai.com/v1/chat/completions
OpenAI SDK-ları chunk-ları sizə bir-bir verir. Hər chunk-ı daşıdığına görə oxuyun: reasoning hissəsi, cavab hissəsi, alət çağırışı və ya cavabın sonu.
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
}' Axın necə çərçivələnir
- Cavabın statusu
200, başlıqları isəcontent-type: text/event-streamvəcache-control: no-cache-dir. - Hər hadisə
data:ilə başlayan və ardınca boş sətir gələn bir sətirdir.data:sonrakı mətn bir JSON chunk-dır.event:və yaid:sətirləri yoxdur. : pingkimi iki nöqtə ilə başlayan sətir bağlantını açıq saxlayan şərhdir. Onu keçin.- Axın
data: [DONE]ilə bitir. Onsuz dayanan axın tamamlanmamışdır.
Chunk-lar ardıcıllıqla
Hər chunk chat.completion.chunk obyektidir:
{
"id": "chatcmpl-5f0c1e7a9b3d4c62a8e1f07d2b46c9a3",
"object": "chat.completion.chunk",
"created": 1791625200,
"model": "shannon-3",
"choices": [
{
"index": 0,
"delta": {
"content": "Server-sent"
},
"finish_reason": null
}
]
} Bir axının bütün chunk-ları eyni id, created və model daşıyır. choices həmişə bir element saxlayır. Onun delta-sı yenini saxlayır və finish_reason son chunk-a qədər null-dır.
| Delta-da açar | Tip | Təsvir | Göndərən |
|---|---|---|---|
role | string | Həmişə assistant. Axının əvvəlində bir dəfə gəlir. | Host edilən açıq çəkili modellər, shannon-2-lite, shannon-2-pro |
reasoning_content | string | Modelin reasoning-inin bir hissəsi. Hissələri ardıcıllıqla birləşdirin. | Host edilən açıq çəkili modellər, Shannon 3 ailəsi, shannon-1.6-pro, shannon-coder-1 |
content | string | Cavabın bir hissəsi. Hissələri ardıcıllıqla birləşdirin. | Bütün modellər |
tool_calls | array | Bir tam alət çağırışı. Alət çağırışı delta-larına baxın. | Bütün modellər |
Əvvəl reasoning, sonra cavab, sonra hər hansı alət çağırışları gəlir. Chunk-ı axındakı yerinə görə yox, delta-dakı açarlara görə oxuyun: delta role-u mətnin ilk hissəsi ilə birlikdə saxlaya bilər, sonuncusu isə boşdur.
Bütöv axın getdiyi kimi. Sətirlər qısa qalsın deyə burada hər chunk-dan id, object, created və model çıxarılı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] Reasoning delta-ları
Reasoning edən model reasoning-ini cavabdan əvvəl delta.reasoning_content-də göndərir. İki mətni ayrı saxlayın: reasoning-i ayrıca, yığıla bilən hissə kimi göstərin və ya buraxın.
Host edilən açıq çəkili modellər reasoning_effort off olduqda reasoning göndərmir, sorğuda response_format olduqda da göndərmir.
shannon-2-lite və shannon-2-pro da cavab verməzdən əvvəl reasoning edir. Bu endpoint-də onlar reasoning edərkən : thinking şərh sətirləri, sonra cavabı göndərir.
reasoning_content OpenAI SDK-larının tipli modellərində yoxdur. Python-da onu getattr(delta, "reasoning_content", None) ilə oxuyun; JavaScript-də delta.reasoning_content olduğu kimi işləyir.
Alət çağırışı delta-ları
Alət çağırışı bütöv gəlir: hər çağırış üçün bir chunk, onun delta-sı çağırışı tam arguments sətri ilə saxlayır. index cavabın çağırışlarını 0-dan nömrələyir. arguments-i hissə-hissə birləşdirən kod dəyişmədən işləyir, çünki bir hissə birləşdirir.
{
"tool_calls": [
{
"index": 0,
"id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
} Çağırışlardan sonra son chunk-da finish_reason tool_calls olur.
Sorğuda tools olduqda shannon-1.6-lite, shannon-1.6-pro və shannon-coder-1 cavab mətnini cavabın sonunda bir delta kimi göndərir.
Son chunk
data: [DONE]-dan əvvəlki son chunk-da boş delta, finish_reason və sorğunun usage-i var, hamısı eyni chunk-da. Hər axında o var; stream_options lazım deyil.
{
"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
}
} Host edilən açıq çəkili modellərdə usage həmçinin prompt_tokens_details.cached_tokens və completion_tokens_details.reasoning_tokens saxlayır.
web_search: true olan və axtarışı nəsə tapan sorğudan sonra son chunk həmçinin sources daşıyır, ondan əvvəlki bir chunk isə istinad işarələrini delta.annotations kimi daşıyır. Veb axtarışı
| finish_reason | Təsvir | Göndərən |
|---|---|---|
stop | Model cavabını bitirdi və ya stop sətri göründü. | Bütün modellər |
tool_calls | Cavab bir və ya bir neçə alət çağırışı saxlayır. | Bütün modellər |
length | Cavab output limitində kəsildi. | Shannon 3 ailəsi, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 |
usage sahələri endpoint ilə birlikdə təsvir olunub. Chat Completions
Keep-alive sətirləri
Model işləyərkən və hələ göndəriləsi bir şey olmadıqda axın şərh sətirləri daşıyır. Onlarda data yoxdur. SSE parser-i onları özü keçir; xam sətirləri oxuyan kod iki nöqtə ilə başlayan hər sətri keçməlidir.
| Sətir | Göndərən | Nə vaxt |
|---|---|---|
: ping | Shannon 3 ailəsi, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 | Hər 15 saniyədən bir. |
: keepalive | Host edilən açıq çəkili modellər | Model işlədiyi müddətdə hər 15 saniyədən bir. |
: thinking | shannon-2-lite, shannon-2-pro | Model reasoning edərkən. |
Axın daxilindəki xətalar
Axın başladıqdan sonra statusu 200 olur, ona görə uğursuzluq axının içində gəlir: choices-in olacağı yerdə error üzvü olan 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] Xəta chunk-ından sonra finish_reason və usage olan son chunk və data: [DONE] yenə gəlir. Hər chunk-da error-u yoxlayın. Bu yoxlama olmadan yarı yolda uğursuz olan cavab tam görünür.
| Tip | Kod | Mesaj | Nə vaxt |
|---|---|---|---|
api_error | The model backend failed to answer. Please retry. | Model uğursuz oldu və ya heç nə yazmadı. Sorğunu yenidən göndərin. | |
rate_limit_error | Shannon routes are temporarily busy. Please retry. | Model bu anda məşğuldur. Bir neçə saniyə gözləyin və sorğunu yenidən göndərin. | |
invalid_request_error | context_length_exceeded | Söhbət modelin kontekst pəncərəsindən uzundur. Yenidən göndərməzdən əvvəl onu qısaldın. Mesaj mətni dəyişir. |
Host edilən açıq çəkili modellər error üzvünü yalnız type və message ilə göndərir.
OpenAI Python və JavaScript SDK-ları siz iterasiya edərkən xəta chunk-ını API xətası kimi qaldırır, ona görə dövrü adi xəta emalınıza bükün.
Status kodları, xəta gövdəsi və nəyi yenidən cəhd etməli olduğunuz ayrıca səhifədədir. Xəta idarəetməsi
Bağlantının bağlanması
Bağlantını bağlamaq çatdırılmanı dayandırır, sorğunu yox. Model cavabı sonuna qədər yazır və sorğu sanki hamısını oxumusunuz kimi hesablanır. Daha az ödəmək üçün daha az istəyin: onu tətbiq edən modeldə daha kiçik max_tokens təyin edin.
Axın sizə çatana qədər də erkən bitə bilər, məsələn şəbəkə kəsilməsində və ya server yenilənərkən. O zaman son chunk-sız və data: [DONE]-suz dayanır. Həmin cavabı tamamlanmamış sayın və sorğunu yenidən göndərin.
Axını SDK olmadan oxumaq
Düzgün oxuyucu beş şey edir: axından əvvəl gələn xətaları öz xəta emalına göndərir, gövdəni sətirlərə bölür, şərh sətirlərini keçir, data: [DONE]-da dayanır və hər chunk-da error-u yoxlayır.
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 nümunəsi requests paketindən istifadə edir. JavaScript nümunəsi Node.js 18 və ya daha yeni versiyada işləyir.
Digər formatların axınları
Responses və Messages endpoint-ləri də axınla işləyir. Onların frame-lərində hadisənin adı olan event: sətri və onun JSON-u olan data: sətri var. Hər səhifə hadisələrini ardıcıllıqla siyahıya alır.
| Axında | Chat Completions | Responses | Messages |
|---|---|---|---|
| Frame-lər | data: sətirləri | event: və data: sətirləri | event: və data: sətirləri |
| Reasoning burada gəlir | delta.reasoning_content | response.reasoning_summary_text.delta | thinking_delta |
| Cavab mətni burada gəlir | delta.content | response.output_text.delta | text_delta |
| Usage burada gəlir | Son chunk | response.completed | message_delta |
| Axın bununla bitir | Son chunk, sonra data: [DONE] | response.completed | message_stop |