Akış
stream değerini true yapın; yanıt, model yazarken server-sent events olarak gelir: önce akıl yürütme, sonra yanıt, sonra bitiş nedeni ve kullanım bilgisini içeren son bir chunk. Metni bir kişi beklerken ve uzun yanıtlarda kullanın.
POST https://api.shannon-ai.com/v1/chat/completions
OpenAI SDK'ları chunk'ları size tek tek verir. Her chunk'ı taşıdığına göre okuyun: bir akıl yürütme parçası, bir yanıt parçası, bir araç çağrısı ya da yanıtı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
}' Bir stream nasıl çerçevelenir
- Yanıtın durumu
200olur ve başlıklarıcontent-type: text/event-streamilecache-control: no-cacheolur. - Her olay
data:ile başlayan ve ardından boş bir satır gelen tek bir satırdır.data:sonrasındaki metin bir JSON chunk'tır.event:veyaid:satırları yoktur. : pinggibi iki nokta üst üste ile başlayan satır, bağlantıyı açık tutan bir yorumdur. Atlayın.- Stream
data: [DONE]ile biter. Onsuz duran bir stream eksiktir.
Sırayla chunk'lar
Her chunk bir chat.completion.chunk nesnesidir:
{
"id": "chatcmpl-5f0c1e7a9b3d4c62a8e1f07d2b46c9a3",
"object": "chat.completion.chunk",
"created": 1791625200,
"model": "shannon-3",
"choices": [
{
"index": 0,
"delta": {
"content": "Server-sent"
},
"finish_reason": null
}
]
} Bir stream'in tüm chunk'ları aynı id, created ve model değerlerini taşır. choices her zaman tek girdi içerir. delta yeni olanı içerir ve finish_reason son chunk'a kadar null olur.
| Delta'daki anahtar | Tür | Açıklama | Gönderen |
|---|---|---|---|
role | string | Her zaman assistant. Stream'in başında bir kez gelir. | Host edilen açık ağırlıklı modeller, shannon-2-lite, shannon-2-pro |
reasoning_content | string | Modelin akıl yürütmesinden bir parça. Parçaları sırayla birleştirin. | Host edilen açık ağırlıklı modeller, Shannon 3 ailesi, shannon-1.6-pro, shannon-coder-1 |
content | string | Yanıttan bir parça. Parçaları sırayla birleştirin. | Tüm modeller |
tool_calls | array | Eksiksiz bir araç çağrısı. Araç çağrısı delta'larına bakın. | Tüm modeller |
Önce akıl yürütme, sonra yanıt, sonra varsa araç çağrıları gelir. Bir chunk'ı stream içindeki yerine göre değil, delta içindeki anahtarlara göre okuyun: bir delta, ilk metin parçasıyla birlikte role içerebilir ve sonuncusu boştur.
Yolculuk ettiği haliyle bir stream'in tamamı. Satırları kısa tutmak için burada her chunk'tan id, object, created ve model çıkarılmıştır.
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] Akıl yürütme delta'ları
Akıl yürüten bir model, akıl yürütmesini yanıttan önce delta.reasoning_content içinde gönderir. İki metni ayrı tutun: akıl yürütmeyi ayrı, katlanabilir bir bölüm olarak gösterin ya da bırakın.
Host edilen açık ağırlıklı modeller, reasoning_effort değeri off olduğunda akıl yürütme göndermez; istekte bir response_format varsa da göndermez.
shannon-2-lite ve shannon-2-pro da yanıt vermeden önce akıl yürütür. Bu uç noktada akıl yürütürken : thinking yorum satırları, sonra yanıtı gönderirler.
reasoning_content, OpenAI SDK'larının tipli modellerinde yoktur. Python'da getattr(delta, "reasoning_content", None) ile okuyun; JavaScript'te delta.reasoning_content olduğu gibi çalışır.
Araç çağrısı delta'ları
Bir araç çağrısı bütün olarak gelir: çağrı başına bir chunk; delta alanı çağrıyı eksiksiz arguments dizesiyle içerir. index, yanıtın çağrılarını 0'dan başlayarak numaralandırır. arguments değerini parça parça birleştiren kod değişmeden çalışır, çünkü tek bir parçayı birleştirir.
{
"tool_calls": [
{
"index": 0,
"id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
} Çağrılardan sonra son chunk'ın finish_reason değeri tool_calls olur.
İstekte tools olduğunda shannon-1.6-lite, shannon-1.6-pro ve shannon-coder-1 yanıt metnini yanıtın sonunda tek bir delta olarak gönderir.
Son chunk
data: [DONE] öncesindeki son chunk'ta boş bir delta, finish_reason ve isteğin usage bilgisi aynı chunk içinde bulunur. Her stream'de vardır; stream_options gerekmez.
{
"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 edilen açık ağırlıklı modellerde usage ayrıca prompt_tokens_details.cached_tokens ve completion_tokens_details.reasoning_tokens içerir.
Araması bir şey bulmuş, web_search: true içeren bir istekten sonra son chunk ayrıca sources taşır, ondan önceki bir chunk ise alıntı işaretlerini delta.annotations olarak taşır. Yerleşik Web Arama
| finish_reason | Açıklama | Gönderen |
|---|---|---|
stop | Model yanıtını bitirdi ya da bir stop dizesi göründü. | Tüm modeller |
tool_calls | Yanıt bir veya daha fazla araç çağrısı içeriyor. | Tüm modeller |
length | Yanıt çıktı sınırında kesildi. | Shannon 3 ailesi, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 |
usage alanları uç nokta ile birlikte anlatılır. Chat Completions
Keep-alive satırları
Model çalışırken ve henüz gönderecek bir şeyi yokken stream yorum satırları taşır. Veri içermezler. Bir SSE ayrıştırıcısı onları kendiliğinden atlar; ham satırları okuyan kod, iki nokta üst üste ile başlayan her satırı atlamalıdır.
| Satır | Gönderen | Ne zaman |
|---|---|---|
: ping | Shannon 3 ailesi, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 | Her 15 saniyede bir. |
: keepalive | Host edilen açık ağırlıklı modeller | Model çalışırken her 15 saniyede bir. |
: thinking | shannon-2-lite, shannon-2-pro | Model akıl yürütürken. |
Bir stream içindeki hatalar
Bir stream başladıktan sonra durumu 200'dür; bu yüzden bir başarısızlık stream'in içinde, choices olması gereken yerde bir error üyesi olan bir chunk olarak gelir.
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] Hata chunk'ından sonra, finish_reason ve usage içeren son chunk ile data: [DONE] yine de gelir. Her chunk'ta error var mı diye bakın. Bu denetim olmadan yarıda başarısız olmuş bir yanıt tamamlanmış gibi görünür.
| Tür | Kod | Mesaj | Ne zaman |
|---|---|---|---|
api_error | The model backend failed to answer. Please retry. | Model başarısız oldu ya da hiçbir şey yazmadı. İsteği yeniden gönderin. | |
rate_limit_error | Shannon routes are temporarily busy. Please retry. | Model şu anda meşgul. Birkaç saniye bekleyin ve isteği yeniden gönderin. | |
invalid_request_error | context_length_exceeded | Konuşma modelin bağlam penceresinden uzun. Yeniden göndermeden önce kısaltın. Mesaj metni değişir. |
Host edilen açık ağırlıklı modeller error üyesini yalnızca type ve message ile gönderir.
OpenAI Python ve JavaScript SDK'ları, siz yineleme yaparken bir hata chunk'ını API hatası olarak fırlatır; bu yüzden döngüyü olağan hata yönetiminizle sarın.
Durum kodlarının, hata gövdesinin ve nelerin yeniden deneneceğinin kendi sayfası vardır. Hata yönetimi
Bağlantıyı kapatma
Bağlantıyı kapatmak teslimatı durdurur, isteği değil. Model yanıtı sonuna kadar yazar ve istek, hepsini okumuşsunuz gibi ücretlendirilir. Daha azını ödemek için daha azını isteyin: bunu uygulayan bir modelde daha düşük bir max_tokens ayarlayın.
Bir stream size gelirken de erken bitebilir, örneğin bir ağ kesintisinde ya da bir sunucu güncellenirken. O zaman son chunk'sız ve data: [DONE] olmadan durur. Bu yanıtı eksik sayın ve isteği yeniden gönderin.
Bir stream'i SDK olmadan okuma
Doğru bir okuyucu beş şey yapar: stream'den önce gelen hataları kendi hata yönetimine gönderir, gövdeyi satırlara böler, yorum satırlarını atlar, data: [DONE] satırında durur ve her chunk'ta error var mı diye bakar.
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 örneği requests paketini kullanır. JavaScript örneği Node.js 18 veya üzerinde çalışır.
Diğer biçimlerin stream'leri
Responses ve Messages uç noktaları da stream eder. Frame'leri, olayın adını taşıyan bir event: satırı ve JSON'unu taşıyan bir data: satırı içerir. Her sayfa olaylarını sırayla listeler.
| Stream'de | Chat Completions | Responses | Messages |
|---|---|---|---|
| Frame'ler | data: satırları | event: ve data: satırları | event: ve data: satırları |
| Akıl yürütme şurada gelir | delta.reasoning_content | response.reasoning_summary_text.delta | thinking_delta |
| Yanıt metni şurada gelir | delta.content | response.output_text.delta | text_delta |
| Kullanım bilgisi şurada gelir | Son chunk | response.completed | message_delta |
| Stream şununla biter | Son chunk, ardından data: [DONE] | response.completed | message_stop |