ወደ ይዘቱ እለፍ
ስትሪሚንግ

ስትሪሚንግ

stream ን ወደ true ያዘጋጁ እና ምላሹ ሞዴሉ ሲጽፈው እንደ server-sent events ይደርሳል፦ መጀመሪያ reasoning፣ ከዚያ መልሱ፣ ከዚያ የማጠናቀቂያ ምክንያቱ እና usage ያለው የመጨረሻ chunk። አንድ ሰው ጽሑፉን እየጠበቀ ሲሆን እና ለረጅም ምላሾች ይጠቀሙበት።

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

የOpenAI SDKs chunks ን አንድ በአንድ ይሰጡዎታል። እያንዳንዱን chunk በሚይዘው ያንብቡ፦ የreasoning ቁራጭ፣ የመልሱ ቁራጭ፣ የtool ጥሪ፣ ወይም የምላሹ መጨረሻ።

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

stream እንዴት እንደሚቀረጽ

  • ምላሹ status 200 እና content-type: text/event-stream እና cache-control: no-cache headers አለው።
  • እያንዳንዱ event በdata: የሚጀምር እና ባዶ መስመር የሚከተለው አንድ መስመር ነው። ከdata: በኋላ ያለው ጽሑፍ አንድ JSON chunk ነው። የevent: ወይም የid: መስመሮች የሉም።
  • በኮሎን የሚጀምር መስመር፣ ለምሳሌ : ping፣ ግንኙነቱን ክፍት የሚያደርግ comment ነው። ይዝለሉት።
  • stream የሚያበቃው በdata: [DONE] ነው። ያለ እሱ የሚቆም stream ያልተሟላ ነው።

Chunks በቅደም ተከተል

እያንዳንዱ chunk 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
    }
  ]
}

የአንድ stream ሁሉም chunks ተመሳሳይ id፣ created እና model ይይዛሉ። choices ሁልጊዜ አንድ ግቤት ይይዛል። delta አዲሱን ይይዛል፣ finish_reason ደግሞ እስከ መጨረሻው chunk null ነው።

በdelta ውስጥ ያለ ቁልፍ ዓይነት መግለጫ የሚልከው
role string ሁልጊዜ assistant። በstream መጀመሪያ አንድ ጊዜ ይደርሳል። የተስተናገዱ open-weight ሞዴሎች፣ shannon-2-lite፣ shannon-2-pro
reasoning_content string የሞዴሉ reasoning አንድ ቁራጭ። ቁርጥራጮቹን በቅደም ተከተል ያጣምሩ። የተስተናገዱ open-weight ሞዴሎች፣ የShannon 3 ቤተሰብ፣ shannon-1.6-pro፣ shannon-coder-1
content string የመልሱ አንድ ቁራጭ። ቁርጥራጮቹን በቅደም ተከተል ያጣምሩ። ሁሉም ሞዴሎች
tool_calls array አንድ ሙሉ የtool ጥሪ። የTool call deltas ን ይመልከቱ። ሁሉም ሞዴሎች

መጀመሪያ reasoning፣ ከዚያ መልሱ፣ ከዚያ ማንኛውም የtool ጥሪዎች ይመጣሉ። chunk ን በstream ውስጥ ባለበት ቦታ ሳይሆን በdelta ውስጥ ባሉት ቁልፎች ያንብቡ፦ delta role ን ከመጀመሪያው የጽሑፍ ቁራጭ ጋር ሊይዝ ይችላል፣ የመጨረሻው ደግሞ ባዶ ነው።

ሙሉ stream በሚጓዝበት መልኩ። መስመሮቹ አጭር እንዲሆኑ id፣ object፣ created እና model እዚህ ከእያንዳንዱ chunk ተትተዋል።

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]

Reasoning deltas

የሚያስብ ሞዴል reasoning ውን ከመልሱ በፊት በdelta.reasoning_content ይልካል። ሁለቱን ጽሑፎች ለይተው ያስቀምጡ፦ reasoning ን እንደ የተለየ ሊታጠፍ የሚችል ክፍል ያሳዩ፣ ወይም ይተዉት።

የተስተናገዱ open-weight ሞዴሎች reasoning_effort off ሲሆን reasoning አይልኩም፣ ጥያቄው response_format ሲኖረውም አይልኩም።

shannon-2-lite እና shannon-2-pro ከመመለሳቸው በፊት ያስባሉ። በዚህ endpoint ላይ ሲያስቡ : thinking comment መስመሮችን ይልካሉ፣ ከዚያ መልሱን።

reasoning_content በOpenAI SDKs typed ሞዴሎች ውስጥ የለም። በPython getattr(delta, "reasoning_content", None) ያንብቡ፤ በJavaScript delta.reasoning_content እንዳለ ይሰራል።

የTool call deltas

የtool ጥሪ ሙሉ ይደርሳል፦ ለእያንዳንዱ ጥሪ አንድ chunk፣ delta ጥሪውን ከሙሉ arguments string ጋር ይይዛል። index የምላሹን ጥሪዎች ከ0 ይቆጥራል። arguments ን ቁራጭ በቁራጭ የሚያጣምር ኮድ ሳይቀየር ይሰራል፣ ምክንያቱም አንድ ቁራጭ ያጣምራል።

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

ከጥሪዎቹ በኋላ የመጨረሻው chunk finish_reason tool_calls አለው።

ጥያቄው tools ሲይዝ shannon-1.6-lite፣ shannon-1.6-pro እና shannon-coder-1 የመልሱን ጽሑፍ በምላሹ መጨረሻ በአንድ delta ይልካሉ።

የመጨረሻው chunk

ከdata: [DONE] በፊት ያለው የመጨረሻው chunk ባዶ delta፣ finish_reason እና የጥያቄው usage አለው፣ ሁሉም በአንድ chunk ውስጥ። እያንዳንዱ stream አለው፤ 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
  }
}

በተስተናገዱ open-weight ሞዴሎች ላይ usage prompt_tokens_details.cached_tokens እና completion_tokens_details.reasoning_tokens ደግሞ አለው።

ፍለጋው አንድ ነገር ባገኘ web_search: true ባለው ጥያቄ በኋላ፣ የመጨረሻው chunk sources ደግሞ ይይዛል፣ ከእሱ በፊት ያለው አንድ chunk ደግሞ የጥቅስ ምልክቶችን እንደ delta.annotations ይይዛል። የተገናኘ ድር ፍለጋ

finish_reason መግለጫ የሚልከው
stop ሞዴሉ መልሱን ጨርሷል፣ ወይም stop string ታይቷል። ሁሉም ሞዴሎች
tool_calls ምላሹ አንድ ወይም ከዚያ በላይ የtool ጥሪዎች ይዟል። ሁሉም ሞዴሎች
length ምላሹ በውጤት ገደቡ ተቆርጧል። የShannon 3 ቤተሰብ፣ shannon-1.6-lite፣ shannon-1.6-pro፣ shannon-coder-1

የusage መስኮች ከendpoint ጋር ተብራርተዋል። Chat Completions

Keep-alive መስመሮች

ሞዴሉ እየሰራ ሳለ እና ገና የሚልከው ነገር ሳይኖረው stream comment መስመሮችን ይይዛል። ምንም data የላቸውም። SSE parser ራሱ ይዘለሉቸዋል፤ ጥሬ መስመሮችን የሚያነብ ኮድ በኮሎን የሚጀምሩትን መስመሮች ሁሉ መዝለል አለበት።

መስመር የሚልከው መቼ
: ping የShannon 3 ቤተሰብ፣ shannon-1.6-lite፣ shannon-1.6-pro፣ shannon-coder-1 በየ15 ሰከንዱ።
: keepalive የተስተናገዱ open-weight ሞዴሎች ሞዴሉ በሚሰራበት ጊዜ በየ15 ሰከንዱ።
: thinking shannon-2-lite, shannon-2-pro ሞዴሉ በሚያስብበት ጊዜ።

በstream ውስጥ ያሉ ስህተቶች

stream አንዴ ከጀመረ status 200 ነው፣ ስለዚህ ብልሽት በstream ውስጥ ይመጣል፦ choices በሚኖርበት ቦታ error አባል ያለው chunk።

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]

ከስህተቱ chunk በኋላ finish_reason እና usage ያለው የመጨረሻው chunk፣ እና data: [DONE] አሁንም ይከተላሉ። እያንዳንዱን chunk ለerror ይመርምሩ። ያለ ይህ ፍተሻ በግማሽ መንገድ የከሸፈ ምላሽ የተሟላ ይመስላል።

አይነት Code መልእክት መቼ
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 ውይይቱ ከሞዴሉ context window ይረዝማል። እንደገና ከመላክዎ በፊት ያሳጥሩት። የመልእክቱ ጽሑፍ ይለያያል።

የተስተናገዱ open-weight ሞዴሎች error አባልን በtype እና በmessage ብቻ ይልካሉ።

የOpenAI Python እና JavaScript SDKs በሚደግሙበት ጊዜ የስህተት chunk ን እንደ API ስህተት ያነሳሉ፣ ስለዚህ loop ን በተለመደው የስህተት አያያዝዎ ይጠቅልሉት።

የstatus ኮዶች፣ የስህተት body እና ምን እንደገና መላክ እንዳለበት የራሳቸው ገጽ አላቸው። ስህተት አስተዳደር

ግንኙነቱን መዝጋት

ግንኙነቱን መዝጋት ማድረሱን ያቆማል እንጂ ጥያቄውን አይደለም። ሞዴሉ ምላሹን እስከ መጨረሻው ይጽፋል እና ጥያቄው ሁሉንም እንዳነበቡ ሆኖ ይከፈላል። ያነሰ ለመክፈል ያነሰ ይጠይቁ፦ በሚተገብረው ሞዴል ላይ ዝቅተኛ max_tokens ያዘጋጁ።

stream ወደ እርስዎ በሚመጣበት መንገድ ላይም ቀድሞ ሊያበቃ ይችላል፣ ለምሳሌ በኔትወርክ መቋረጥ ወይም server በሚዘመንበት ጊዜ። ያኔ ያለ የመጨረሻው chunk እና ያለ data: [DONE] ይቆማል። እንዲህ ያለውን ምላሽ እንደ ያልተሟላ ይውሰዱት እና ጥያቄውን እንደገና ይላኩ።

ያለ SDK stream ማንበብ

ትክክለኛ አንባቢ አምስት ነገሮችን ያደርጋል፦ ከstream በፊት የሚደርሱ ስህተቶችን ወደ ስህተት አያያዙ ይልካል፣ body ን ወደ መስመሮች ይከፍላል፣ comment መስመሮችን ይዘላል፣ በdata: [DONE] ይቆማል፣ እና እያንዳንዱን chunk ለ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 ወይም ከዚያ በኋላ ይሰራል።

የሌሎች ፎርማቶች streams

የResponses እና የMessages endpoints እንዲሁ stream ያደርጋሉ። frames ቸው የevent ስም ያለው event: መስመር እና JSON ያለው data: መስመር ይይዛሉ። እያንዳንዱ ገጽ events ን በቅደም ተከተል ይዘረዝራል።

በstream ውስጥ Chat CompletionsResponsesMessages
Frames data: መስመሮችevent: እና data: መስመሮችevent: እና data: መስመሮች
Reasoning የሚደርሰው በ delta.reasoning_contentresponse.reasoning_summary_text.deltathinking_delta
የመልስ ጽሑፍ የሚደርሰው በ delta.contentresponse.output_text.deltatext_delta
Usage የሚደርሰው በ የመጨረሻው chunkresponse.completedmessage_delta
stream የሚያበቃው በ የመጨረሻው chunk፣ ከዚያ data: [DONE]response.completedmessage_stop