स्ट्रिमिङ
stream लाई true सेट गर्नुहोस् र मोडलले लेख्दै गर्दा जवाफ सर्भर-सेन्ट इभेन्टका रूपमा आउँछ: पहिले रिजनिङ, त्यसपछि उत्तर, त्यसपछि समाप्ति कारण र usage सहितको अन्तिम चङ्क। कुनै व्यक्तिले टेक्स्टको प्रतीक्षा गरिरहेको बेला र लामा जवाफहरूका लागि यसलाई प्रयोग गर्नुहोस्।
POST https://api.shannon-ai.com/v1/chat/completions
OpenAI SDK हरूले तपाईंलाई चङ्कहरू एक-एक गरी दिन्छन्। हरेक चङ्कलाई त्यसले के बोक्छ त्यसैअनुसार पढ्नुहोस्: रिजनिङको टुक्रा, उत्तरको टुक्रा, टुल कल, वा जवाफको अन्त्य।
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
}' स्ट्रिमको फ्रेमिङ कसरी हुन्छ
- जवाफको स्टेटस
200हुन्छ र हेडरहरूcontent-type: text/event-streamरcache-control: no-cacheहुन्छन्। - हरेक इभेन्ट
data:बाट सुरु हुने एउटा लाइन हो र त्यसपछि खाली लाइन आउँछ।data:पछिको टेक्स्ट एउटा JSON चङ्क हो।event:वाid:लाइनहरू हुँदैनन्। : pingजस्तो कोलनबाट सुरु हुने लाइन कनेक्सन खुला राख्ने कमेन्ट हो। यसलाई छोड्नुहोस्।- स्ट्रिम
data: [DONE]मा सकिन्छ। त्यसबिना रोकिने स्ट्रिम अपूर्ण हो।
क्रमैसँग चङ्कहरू
हरेक चङ्क 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
}
]
} एउटा स्ट्रिमका सबै चङ्कले उही id, created र model बोक्छन्। choices मा सधैं एउटा प्रविष्टि हुन्छ। यसको delta मा नयाँ कुरा हुन्छ, र अन्तिम चङ्कसम्म finish_reason null हुन्छ।
| delta मा कुञ्जी | प्रकार | विवरण | पठाउने |
|---|---|---|---|
role | string | सधैं assistant। यो स्ट्रिमको सुरुमा एक पटक आउँछ। | होस्ट गरिएका ओपन-वेट मोडलहरू, shannon-2-lite, shannon-2-pro |
reasoning_content | string | मोडलको रिजनिङको एक टुक्रा। टुक्राहरू क्रमैसँग जोड्नुहोस्। | होस्ट गरिएका ओपन-वेट मोडलहरू, Shannon 3 परिवार, shannon-1.6-pro, shannon-coder-1 |
content | string | उत्तरको एक टुक्रा। टुक्राहरू क्रमैसँग जोड्नुहोस्। | सबै मोडलहरू |
tool_calls | array | एउटा पूरा टुल कल। टुल कल डेल्टाहरू हेर्नुहोस्। | सबै मोडलहरू |
पहिले रिजनिङ आउँछ, त्यसपछि उत्तर, त्यसपछि कुनै टुल कल। चङ्कलाई स्ट्रिममा यसको स्थानले होइन, यसको delta का कुञ्जीहरूले पढ्नुहोस्: delta मा पहिलो टेक्स्ट टुक्रासँगै role हुन सक्छ, र अन्तिम खाली हुन्छ।
पूरै स्ट्रिम जसरी यात्रा गर्छ। लाइनहरू छोटो राख्न यहाँ हरेक चङ्कबाट id, object, created र model छोडिएका छन्।
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] रिजनिङ डेल्टाहरू
रिजनिङ गर्ने मोडलले उत्तर अघि आफ्नो रिजनिङ delta.reasoning_content मा पठाउँछ। दुई टेक्स्टलाई अलग राख्नुहोस्: रिजनिङ छुट्टै, पट्ट्याउन मिल्ने भागका रूपमा देखाउनुहोस्, वा छोड्नुहोस्।
reasoning_effort off हुँदा होस्ट गरिएका ओपन-वेट मोडलहरूले रिजनिङ पठाउँदैनन्, र अनुरोधमा response_format हुँदा पनि पठाउँदैनन्।
shannon-2-lite र shannon-2-pro ले पनि जवाफ दिनु अघि रिजनिङ गर्छन्। यो इन्डपोइन्टमा तिनले रिजनिङ गर्दा : thinking कमेन्ट लाइनहरू पठाउँछन्, त्यसपछि उत्तर।
reasoning_content OpenAI SDK का टाइप गरिएका मोडलमा छैन। Python मा getattr(delta, "reasoning_content", None) ले पढ्नुहोस्; JavaScript मा delta.reasoning_content जस्ताको तस्तै काम गर्छ।
टुल कल डेल्टाहरू
टुल कल पूरै आउँछ: प्रति कल एउटा चङ्क, जसको delta मा पूरा arguments स्ट्रिङसहितको कल हुन्छ। index ले जवाफका कलहरू 0 देखि गन्छ। arguments टुक्रा-टुक्रा जोड्ने कोड बिना परिवर्तन काम गर्छ, किनकि यसले एउटै टुक्रा जोड्छ।
{
"tool_calls": [
{
"index": 0,
"id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
} कलहरू पछि, अन्तिम चङ्कमा finish_reason tool_calls हुन्छ।
अनुरोधमा tools हुँदा shannon-1.6-lite, shannon-1.6-pro र shannon-coder-1 ले उत्तर टेक्स्ट जवाफको अन्त्यमा एउटै डेल्टामा पठाउँछन्।
अन्तिम चङ्क
data: [DONE] अघिको अन्तिम चङ्कमा खाली delta, finish_reason र अनुरोधको usage हुन्छन्, सबै उही चङ्कमा। हरेक स्ट्रिममा यो हुन्छ; तपाईंलाई 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
}
} होस्ट गरिएका ओपन-वेट मोडलहरूमा usage मा prompt_tokens_details.cached_tokens र completion_tokens_details.reasoning_tokens पनि हुन्छन्।
खोजले केही भेटेको web_search: true भएको अनुरोधपछि अन्तिम चङ्कमा sources पनि हुन्छ, र त्यस अघिको एउटा चङ्कले उद्धरणका चिनोहरू delta.annotations का रूपमा बोक्छ। निर्मित वेब खोज
| finish_reason | विवरण | पठाउने |
|---|---|---|
stop | मोडलले आफ्नो उत्तर पूरा गर्यो, वा stop स्ट्रिङ देखियो। | सबै मोडलहरू |
tool_calls | जवाफमा एक वा बढी टुल कल छन्। | सबै मोडलहरू |
length | जवाफ आउटपुट सीमामा काटियो। | Shannon 3 परिवार, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 |
usage का फिल्डहरू इन्डपोइन्टसँगै वर्णन गरिएका छन्। Chat Completions
कीप-अलाइभ लाइनहरू
मोडलले काम गरिरहँदा र पठाउन केही नहुँदा स्ट्रिमले कमेन्ट लाइनहरू बोक्छ। तिनमा डेटा हुँदैन। SSE पार्सरले तिनलाई आफैं छोड्छ; कच्चा लाइन पढ्ने कोडले कोलनबाट सुरु हुने हरेक लाइन छोड्नुपर्छ।
| लाइन | पठाउने | कहिले |
|---|---|---|
: ping | Shannon 3 परिवार, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 | हरेक 15 सेकेन्डमा। |
: keepalive | होस्ट गरिएका ओपन-वेट मोडलहरू | मोडलले काम गरिरहँदा हरेक 15 सेकेन्डमा। |
: thinking | shannon-2-lite, shannon-2-pro | मोडलले रिजनिङ गरिरहँदा। |
स्ट्रिमभित्रका त्रुटिहरू
स्ट्रिम सुरु भएपछि यसको स्टेटस 200 हुन्छ, त्यसैले असफलता स्ट्रिमभित्र आउँछ: choices हुने ठाउँमा error सदस्य भएको चङ्क।
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] त्रुटि चङ्कपछि finish_reason र usage सहितको अन्तिम चङ्क, र data: [DONE] तैपनि पछ्याउँछन्। हरेक चङ्कमा error जाँच्नुहोस्। त्यो जाँच बिना बीचमै असफल भएको जवाफ पूरा जस्तो देखिन्छ।
| प्रकार | कोड | सन्देश | कहिले |
|---|---|---|---|
api_error | The model backend failed to answer. Please retry. | मोडल असफल भयो, वा केही लेखेन। अनुरोध फेरि पठाउनुहोस्। | |
rate_limit_error | Shannon routes are temporarily busy. Please retry. | मोडल यस क्षण व्यस्त छ। केही सेकेन्ड पर्खनुहोस् र अनुरोध फेरि पठाउनुहोस्। | |
invalid_request_error | context_length_exceeded | कुराकानी मोडलको कन्टेक्स्ट विन्डोभन्दा लामो छ। फेरि पठाउनु अघि यसलाई छोट्याउनुहोस्। सन्देशको टेक्स्ट फरक पर्छ। |
होस्ट गरिएका ओपन-वेट मोडलहरूले type र message मात्र भएको error सदस्य पठाउँछन्।
OpenAI Python र JavaScript SDK हरूले तपाईंले इटरेट गर्दा त्रुटि चङ्कलाई API त्रुटिका रूपमा उठाउँछन्, त्यसैले लुपलाई आफ्नो सामान्य त्रुटि ह्यान्डलिङमा बेर्नुहोस्।
स्टेटस कोड, त्रुटि बडी र के फेरि प्रयास गर्ने भन्ने कुराको आफ्नै पेज छ। त्रुटि व्यवस्थापन
कनेक्सन बन्द गर्ने
कनेक्सन बन्द गर्दा डेलिभरी रोकिन्छ, अनुरोध रोकिँदैन। मोडलले जवाफ अन्त्यसम्म लेख्छ र अनुरोधमा तपाईंले सबै पढेजस्तै शुल्क लाग्छ। कम तिर्न कम माग्नुहोस्: यसलाई लागू गर्ने मोडलमा सानो max_tokens सेट गर्नुहोस्।
स्ट्रिम तपाईंकहाँ आउने बाटोमा, उदाहरणका लागि नेटवर्क टुट्दा वा सर्भर अपडेट हुँदा, चाँडै सकिन पनि सक्छ। त्यसपछि यो अन्तिम चङ्क र data: [DONE] बिना रोकिन्छ। त्यस्तो जवाफलाई अपूर्ण मान्नुहोस् र अनुरोध फेरि पठाउनुहोस्।
SDK बिना स्ट्रिम पढ्ने
सही रिडरले पाँच काम गर्छ: स्ट्रिम अघि आउने त्रुटिहरूलाई आफ्नो त्रुटि ह्यान्डलिङमा पठाउँछ, बडीलाई लाइनमा बाँड्छ, कमेन्ट लाइनहरू छोड्छ, data: [DONE] मा रोकिन्छ, र हरेक चङ्कमा 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); Python नमूनाले requests प्याकेज प्रयोग गर्छ। JavaScript नमूना Node.js 18 वा पछिल्लोमा चल्छ।
अन्य ढाँचाका स्ट्रिमहरू
Responses र Messages इन्डपोइन्टहरू पनि स्ट्रिम हुन्छन्। तिनका फ्रेममा इभेन्टको नाम भएको event: लाइन र त्यसको JSON भएको data: लाइन हुन्छ। हरेक पेजले आफ्ना इभेन्टहरू क्रमैसँग सूचीबद्ध गर्छ।
| स्ट्रिममा | Chat Completions | Responses | Messages |
|---|---|---|---|
| फ्रेमहरू | data: लाइनहरू | event: र data: लाइनहरू | event: र data: लाइनहरू |
| रिजनिङ यसमा आउँछ | delta.reasoning_content | response.reasoning_summary_text.delta | thinking_delta |
| उत्तर टेक्स्ट यसमा आउँछ | delta.content | response.output_text.delta | text_delta |
| Usage यसमा आउँछ | अन्तिम चङ्क | response.completed | message_delta |
| स्ट्रिम यसमा सकिन्छ | अन्तिम चङ्क, त्यसपछि data: [DONE] | response.completed | message_stop |