कंटेंट पर जाएँ
स्ट्रीमिंग

स्ट्रीमिंग

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}")

स्ट्रीम का फ़्रेम कैसे बनता है

  • उत्तर का स्टेटस 200 है और हेडर content-type: text/event-stream और cache-control: no-cache हैं।
  • हर इवेंट data: से शुरू होने वाली एक पंक्ति है, जिसके बाद एक खाली पंक्ति आती है। data: के बाद का टेक्स्ट एक JSON चंक है। event: या id: पंक्तियाँ नहीं होतीं।
  • कोलन से शुरू होने वाली पंक्ति, जैसे : ping, एक कमेंट है जो कनेक्शन खुला रखती है। उसे छोड़ दें।
  • स्ट्रीम data: [DONE] पर खत्म होती है। जो स्ट्रीम उसके बिना रुक जाए वह अधूरी है।

क्रम से चंक

हर चंक एक chat.completion.chunk ऑब्जेक्ट है:

JSON
{
  "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 एक पूरी टूल कॉल। Tool call deltas देखें। सभी मॉडल

पहले रीज़निंग आती है, फिर उत्तर, फिर कोई भी टूल कॉल। चंक को स्ट्रीम में उसकी जगह से नहीं, उसके delta की कुंजियों से पढ़ें: delta में role टेक्स्ट के पहले टुकड़े के साथ हो सकता है, और आख़िरी खाली होता है।

पूरी स्ट्रीम जैसी वह यात्रा करती है। पंक्तियाँ छोटी रखने के लिए यहाँ हर चंक से id, object, created और model हटा दिए गए हैं।

200 text/event-stream
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 भी उत्तर से पहले रीज़निंग करते हैं। इस endpoint पर वे रीज़निंग के दौरान : thinking कमेंट पंक्तियाँ भेजते हैं, और फिर उत्तर।

reasoning_content OpenAI SDK के टाइप्ड मॉडल में नहीं है। Python में उसे getattr(delta, "reasoning_content", None) से पढ़ें; JavaScript में delta.reasoning_content जैसा है वैसा काम करता है।

टूल कॉल डेल्टा

टूल कॉल पूरी आती है: हर कॉल के लिए एक चंक, जिसके delta में पूरी arguments स्ट्रिंग के साथ कॉल होती है। index उत्तर की कॉल को 0 से क्रमांकित करता है। जो कोड arguments को टुकड़ा-टुकड़ा जोड़ता है वह बिना बदलाव काम करता है, क्योंकि वह एक ही टुकड़ा जोड़ता है।

delta
{
  "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 की ज़रूरत नहीं है।

JSON
{
  "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 के रूप में रखता है। इनबिल्ट Web Search

finish_reason विवरण कौन भेजता है
stop मॉडल ने अपना उत्तर पूरा किया, या कोई stop स्ट्रिंग आ गई। सभी मॉडल
tool_calls उत्तर में एक या अधिक टूल कॉल हैं। सभी मॉडल
length उत्तर आउटपुट सीमा पर काट दिया गया। Shannon 3 परिवार, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1

usage के फ़ील्ड endpoint के साथ वर्णित हैं। Chat Completions

Keep-alive पंक्तियाँ

जब मॉडल काम कर रहा हो और भेजने को अभी कुछ न हो, तब स्ट्रीम कमेंट पंक्तियाँ देती है। इनमें कोई डेटा नहीं होता। 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 सदस्य होता है।

200 text/event-stream
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 बातचीत मॉडल की कॉन्टेक्स्ट विंडो से लंबी है। फिर भेजने से पहले उसे छोटा करें। संदेश का टेक्स्ट बदलता रहता है।

होस्टेड ओपन-वेट मॉडल error सदस्य केवल type और message के साथ भेजते हैं।

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))

Python नमूना requests पैकेज इस्तेमाल करता है। JavaScript नमूना Node.js 18 या बाद के संस्करण पर चलता है।

दूसरे फ़ॉर्मेट की स्ट्रीम

Responses और Messages endpoints भी स्ट्रीम करते हैं। उनके फ़्रेम में इवेंट के नाम वाली event: पंक्ति और उसके JSON वाली data: पंक्ति होती है। हर पेज अपने इवेंट क्रम से सूचीबद्ध करता है।

स्ट्रीम में Chat CompletionsResponsesMessages
फ़्रेम data: पंक्तियाँevent: और data: पंक्तियाँevent: और data: पंक्तियाँ
रीज़निंग यहाँ आती है delta.reasoning_contentresponse.reasoning_summary_text.deltathinking_delta
उत्तर का टेक्स्ट यहाँ आता है delta.contentresponse.output_text.deltatext_delta
Usage यहाँ आता है आख़िरी चंकresponse.completedmessage_delta
स्ट्रीम इस पर खत्म होती है आख़िरी चंक, फिर data: [DONE]response.completedmessage_stop