Lumaktaw sa nilalaman
Pag‑stream

Pag‑stream

I-set ang stream sa true at dumarating ang reply bilang server-sent events habang isinusulat ito ng model: reasoning muna, saka ang sagot, saka ang huling chunk na may dahilan ng pagtatapos at usage. Gamitin ito tuwing may taong naghihintay sa text, at para sa mahahabang reply.

POST https://api.shannon-ai.com/v1/chat/completions

Ibinibigay sa iyo ng mga OpenAI SDK ang mga chunk nang isa-isa. Basahin ang bawat chunk ayon sa dala nito: isang piraso ng reasoning, isang piraso ng sagot, isang tool call, o ang wakas ng reply.

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

Paano binabalangkas ang stream

  • Ang reply ay may status na 200 at mga header na content-type: text/event-stream at cache-control: no-cache.
  • Ang bawat event ay isang linyang nagsisimula sa data: at sinusundan ng walang lamang linya. Ang text pagkatapos ng data: ay isang JSON chunk. Walang mga linyang event: o id:.
  • Ang linyang nagsisimula sa colon, gaya ng : ping, ay comment na nagpapanatiling bukas sa koneksyon. Laktawan ito.
  • Nagtatapos ang stream sa data: [DONE]. Ang stream na huminto nang wala nito ay hindi kumpleto.

Mga chunk ayon sa pagkakasunod

Ang bawat chunk ay isang chat.completion.chunk object:

JSON
{
  "id": "chatcmpl-5f0c1e7a9b3d4c62a8e1f07d2b46c9a3",
  "object": "chat.completion.chunk",
  "created": 1791625200,
  "model": "shannon-3",
  "choices": [
    {
      "index": 0,
      "delta": {
        "content": "Server-sent"
      },
      "finish_reason": null
    }
  ]
}

Pareho ang id, created at model na dala ng lahat ng chunk ng isang stream. Palaging isang entry ang laman ng choices. Hawak ng delta nito ang bago, at ang finish_reason ay null hanggang sa huling chunk.

Key sa delta Type Paglalarawan Ipinadala ng
role string Palaging assistant. Isang beses itong dumarating, sa simula ng stream. Mga hosted open-weight model, shannon-2-lite, shannon-2-pro
reasoning_content string Isang piraso ng reasoning ng model. Pagdugtungin ang mga piraso ayon sa pagkakasunod. Mga hosted open-weight model, pamilyang Shannon 3, shannon-1.6-pro, shannon-coder-1
content string Isang piraso ng sagot. Pagdugtungin ang mga piraso ayon sa pagkakasunod. Lahat ng model
tool_calls array Isang kumpletong tool call. Tingnan ang Mga delta ng tool call. Lahat ng model

Nauuna ang reasoning, sumusunod ang sagot, saka ang anumang tool call. Basahin ang chunk ayon sa mga key sa delta nito, hindi ayon sa lugar nito sa stream: ang isang delta ay maaaring may role kasama ng unang piraso ng text, at walang laman ang huli.

Ang buong stream kung paano ito naglalakbay. Para panatilihing maikli ang mga linya, inalis dito sa bawat chunk ang id, object, created at 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]

Mga reasoning delta

Ipinapadala ng model na nag-re-reason ang reasoning nito sa delta.reasoning_content bago ang sagot. Panatilihing hiwalay ang dalawang text: ipakita ang reasoning bilang hiwalay at natitiklop na bahagi, o huwag itong isama.

Hindi nagpapadala ng reasoning ang mga hosted open-weight model kapag ang reasoning_effort ay off, at wala rin kapag may response_format ang request.

Nag-re-reason din bago sumagot ang shannon-2-lite at shannon-2-pro. Sa endpoint na ito, nagpapadala sila ng mga comment line na : thinking habang ginagawa nila iyon, saka ang sagot.

Wala ang reasoning_content sa mga typed model ng OpenAI SDK. Sa Python, basahin ito gamit ang getattr(delta, "reasoning_content", None); sa JavaScript, gumagana nang direkta ang delta.reasoning_content.

Mga delta ng tool call

Dumarating nang buo ang tool call: isang chunk kada call, na ang delta ay may hawak ng call na may kumpletong arguments string. Binibilang ng index ang mga call ng reply mula 0. Gumagana nang walang pagbabago ang code na nagdurugtong ng arguments pira-piraso, dahil isang piraso ang dinurugtong nito.

delta
{
  "tool_calls": [
    {
      "index": 0,
      "id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
      "type": "function",
      "function": {
        "name": "get_weather",
        "arguments": "{\"city\":\"Paris\"}"
      }
    }
  ]
}

Pagkatapos ng mga call, ang huling chunk ay may finish_reason na tool_calls.

Kapag may tools ang request, ipinapadala ng shannon-1.6-lite, shannon-1.6-pro at shannon-coder-1 ang text ng sagot bilang isang delta sa dulo ng reply.

Ang huling chunk

Ang huling chunk bago ang data: [DONE] ay may walang lamang delta, ang finish_reason at ang usage ng request, lahat sa iisang chunk. Mayroon nito ang bawat stream; hindi mo kailangan ng 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
  }
}

Sa mga hosted open-weight model, ang usage ay may prompt_tokens_details.cached_tokens at completion_tokens_details.reasoning_tokens din.

Pagkatapos ng request na may web_search: true na may nakitang resulta ang search, dala rin ng huling chunk ang sources, at ang isang chunk bago nito ay may dalang mga marka ng citation bilang delta.annotations. Web search

finish_reason Paglalarawan Ipinadala ng
stop Natapos ng model ang sagot nito, o lumabas ang isang stop string. Lahat ng model
tool_calls May isa o higit pang tool call ang reply. Lahat ng model
length Naputol ang reply sa output limit. Pamilyang Shannon 3, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1

Inilalarawan kasama ng endpoint ang mga field ng usage. Chat Completions

Mga keep-alive line

Habang gumagana ang model at wala pang maipadala, may dalang mga comment line ang stream. Walang data ang mga ito. Kusa silang nilalaktawan ng SSE parser; ang code na nagbabasa ng raw na linya ay dapat lumaktaw sa bawat linyang nagsisimula sa colon.

Linya Ipinadala ng Kailan
: ping Pamilyang Shannon 3, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 Tuwing 15 segundo.
: keepalive Mga hosted open-weight model Tuwing 15 segundo habang gumagana ang model.
: thinking shannon-2-lite, shannon-2-pro Habang nag-re-reason ang model.

Mga error sa loob ng stream

Kapag nagsimula na ang stream, 200 ang status nito, kaya ang pagkabigo ay dumarating sa loob ng stream: isang chunk na may miyembrong error kung saan dapat naroon ang choices.

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]

Pagkatapos ng error chunk, sumusunod pa rin ang huling chunk, na may finish_reason at usage, at data: [DONE]. Suriin ang bawat chunk para sa error. Kung hindi, ang reply na nabigo sa kalagitnaan ay mukhang kumpleto.

Type Code Mensahe Kailan
api_error The model backend failed to answer. Please retry. Nabigo ang model, o walang naisulat. Ipadala muli ang request.
rate_limit_error Shannon routes are temporarily busy. Please retry. Abala ang model sa ngayon. Maghintay ng ilang segundo at ipadala muli ang request.
invalid_request_error context_length_exceeded Mas mahaba ang conversation kaysa sa context window ng model. Paikliin ito bago ipadala muli. Nag-iiba ang text ng mensahe.

Ipinapadala ng mga hosted open-weight model ang miyembrong error na may type at message lamang.

Itinataas ng mga OpenAI Python at JavaScript SDK ang error chunk bilang API error habang nag-i-iterate ka, kaya balutin ang loop sa iyong karaniwang error handling.

May sariling pahina ang mga status code, ang error body at kung ano ang dapat i-retry. Paghawak ng Error

Pagsasara ng koneksyon

Ang pagsasara ng koneksyon ay humihinto sa paghahatid, hindi sa request. Isinusulat ng model ang reply hanggang dulo at sinisingil ang request na parang binasa mo ang lahat. Para magbayad nang mas kaunti, humingi ng mas kaunti: magtakda ng mas mababang max_tokens sa model na nag-a-apply nito.

Maaari ring matapos nang maaga ang stream sa daan papunta sa iyo, halimbawa sa pagkaputol ng network o habang ina-update ang server. Hihinto ito nang walang huling chunk at walang data: [DONE]. Ituring na hindi kumpleto ang reply na iyon at ipadala muli ang request.

Pagbasa ng stream nang walang SDK

Limang bagay ang ginagawa ng tamang reader: ipinapadala nito sa error handling ang mga error na dumarating bago ang stream, hinahati ang body sa mga linya, nilalaktawan ang mga comment line, humihinto sa data: [DONE], at sinusuri ang bawat chunk para sa 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))

Gumagamit ang Python sample ng package na requests. Tumatakbo ang JavaScript sample sa Node.js 18 o mas bago.

Mga stream ng ibang format

Nag-i-stream din ang mga endpoint na Responses at Messages. Ang kanilang mga frame ay may event: line na may pangalan ng event at data: line na may JSON nito. Inililista ng bawat pahina ang mga event nito ayon sa pagkakasunod.

Sa stream Chat CompletionsResponsesMessages
Mga frame Mga linyang data:Mga linyang event: at data:Mga linyang event: at data:
Dumarating ang reasoning sa delta.reasoning_contentresponse.reasoning_summary_text.deltathinking_delta
Dumarating ang text ng sagot sa delta.contentresponse.output_text.deltatext_delta
Dumarating ang usage sa Ang huling chunkresponse.completedmessage_delta
Nagtatapos ang stream sa Ang huling chunk, saka data: [DONE]response.completedmessage_stop