រំលងទៅមាតិកា
ស្ទ្រីម

ស្ទ្រីម

កំណត់ stream ជា true ហើយចម្លើយមកដល់ជា server-sent event ខណៈពេលម៉ូដែលសរសេរវា៖ reasoning មុន បន្ទាប់មកចម្លើយ បន្ទាប់មក chunk ចុងក្រោយដែលមាន finish reason និង usage។ សូមប្រើវាគ្រប់ពេលដែលមនុស្សកំពុងរង់ចាំអត្ថបទ និងសម្រាប់ចម្លើយវែង។

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

OpenAI SDK ផ្តល់ chunk ឱ្យអ្នកម្តងមួយ។ សូមអានរាល់ 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 ត្រូវបានចែកជា frame

  • ចម្លើយមាន status 200 និង header content-type: text/event-stream និង cache-control: no-cache។
  • រាល់ event គឺជាបន្ទាត់មួយដែលចាប់ផ្តើមដោយ data: ហើយតាមពីក្រោយដោយបន្ទាត់ទទេ។ អត្ថបទក្រោយ data: គឺជា JSON chunk មួយ។ គ្មានបន្ទាត់ event: ឬ id: ទេ។
  • បន្ទាត់ដែលចាប់ផ្តើមដោយសញ្ញាចុចពីរ ដូចជា : ping គឺជា comment ដែលរក្សាការតភ្ជាប់ឱ្យបើក។ សូមរំលងវា។
  • stream បញ្ចប់ដោយ data: [DONE]។ stream ដែលឈប់ដោយគ្មានវាគឺមិនពេញលេញ។

Chunk តាមលំដាប់

រាល់ chunk គឺជា object ប្រភេទ 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
    }
  ]
}

រាល់ chunk នៃ stream មួយមាន id, created និង model ដូចគ្នា។ choices តែងតែមានធាតុមួយ។ delta របស់វាមានអ្វីដែលថ្មី ហើយ finish_reason គឺ null រហូតដល់ chunk ចុងក្រោយ។

Key ក្នុង 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 delta។ គ្រប់ម៉ូដែល

Reasoning មកមុន បន្ទាប់មកចម្លើយ បន្ទាប់មកការហៅ tool ណាមួយ។ សូមអាន chunk តាម key ក្នុង delta របស់វា មិនមែនតាមទីតាំងរបស់វាក្នុង stream ទេ៖ 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 delta

ម៉ូដែលដែលវែកញែកផ្ញើ reasoning របស់វាក្នុង delta.reasoning_content មុនចម្លើយ។ សូមរក្សាអត្ថបទទាំងពីរដាច់ពីគ្នា៖ បង្ហាញ reasoning ជាផ្នែកដាច់ដោយឡែកដែលអាចបត់បាន ឬទុកវាចោល។

ម៉ូដែល open-weight ដែលបង្ហោះមិនផ្ញើ reasoning នៅពេល reasoning_effort គឺ off ហើយក៏មិនផ្ញើនៅពេល request មាន response_format ដែរ។

shannon-2-lite និង shannon-2-pro ក៏វែកញែកមុនពេលឆ្លើយដែរ។ លើ endpoint នេះពួកវាផ្ញើបន្ទាត់ comment : thinking ខណៈពេលពួកវាវែកញែក ហើយបន្ទាប់មកជាចម្លើយ។

reasoning_content មិនមានក្នុង typed model របស់ OpenAI SDK ទេ។ ក្នុង Python សូមអានវាដោយ getattr(delta, "reasoning_content", None)៖ ក្នុង JavaScript delta.reasoning_content ដំណើរការដូចដែលវាជា។

Tool call delta

ការហៅ tool មកដល់ទាំងមូល៖ មួយ chunk ក្នុងមួយការហៅ ដែល delta របស់វាមានការហៅជាមួយ string arguments ពេញលេញ។ 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។

នៅពេល request មាន tools shannon-1.6-lite, shannon-1.6-pro និង shannon-coder-1 ផ្ញើអត្ថបទចម្លើយជា delta មួយនៅចុងចម្លើយ។

Chunk ចុងក្រោយ

chunk ចុងក្រោយមុន data: [DONE] មាន delta ទទេ finish_reason និង usage នៃ request ទាំងអស់ក្នុង 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 ដែរ។

បន្ទាប់ពី request ដែលមាន web_search: true ហើយការស្វែងរករបស់វារកឃើញអ្វីមួយ chunk ចុងក្រោយក៏មាន sources ដែរ ហើយ chunk មួយមុននោះផ្ទុកសញ្ញាដកស្រង់ជា delta.annotations។ ស្វែងរកវេបក្នុងស្រាប់

finish_reason ការពិពណ៌នា ផ្ញើដោយ
stop ម៉ូដែលបានបញ្ចប់ចម្លើយរបស់វា ឬ string stop បានលេចឡើង។ គ្រប់ម៉ូដែល
tool_calls ចម្លើយមានការហៅ tool មួយ ឬច្រើន។ គ្រប់ម៉ូដែល
length ចម្លើយត្រូវបានកាត់នៅដែនកំណត់ output។ ក្រុម Shannon 3, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1

field នៃ usage ត្រូវបានពិពណ៌នាជាមួយ endpoint។ Chat Completions

បន្ទាត់ keep-alive

ខណៈពេលម៉ូដែលធ្វើការ ហើយមិនទាន់មានអ្វីត្រូវផ្ញើ stream មានបន្ទាត់ comment។ ពួកវាមិនមានទិន្នន័យទេ។ 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៖ chunk ដែលមាន member error នៅកន្លែងដែល 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]

បន្ទាប់ពី error chunk chunk ចុងក្រោយ ដែលមាន finish_reason និង usage និង data: [DONE] នៅតែតាមក្រោយ។ សូមពិនិត្យរាល់ chunk រក error។ បើគ្មានការពិនិត្យនោះ ចម្លើយដែលបរាជ័យពាក់កណ្តាលផ្លូវមើលទៅពេញលេញ។

ប្រភេទ កូដ សារ ពេលណា
api_error The model backend failed to answer. Please retry. ម៉ូដែលបរាជ័យ ឬមិនបានសរសេរអ្វីទេ។ សូមផ្ញើ request ម្តងទៀត។
rate_limit_error Shannon routes are temporarily busy. Please retry. ម៉ូដែលរវល់ក្នុងពេលនេះ។ សូមរង់ចាំពីរបីវិនាទី ហើយផ្ញើ request ម្តងទៀត។
invalid_request_error context_length_exceeded ការសន្ទនាវែងជាង context window របស់ម៉ូដែល។ សូមបង្រួមវាមុនពេលអ្នកផ្ញើម្តងទៀត។ អត្ថបទនៃសារប្រែប្រួល។

ម៉ូដែល open-weight ដែលបង្ហោះផ្ញើ member error ដែលមានតែ type និង message ប៉ុណ្ណោះ។

OpenAI Python និង JavaScript SDK បោះ error chunk ជា API error ខណៈពេលអ្នក iterate ដូច្នេះសូមរុំ loop ក្នុងការគ្រប់គ្រង error ធម្មតារបស់អ្នក។

កូដ status ខ្លឹមសារ error និងអ្វីដែលត្រូវព្យាយាមម្តងទៀតមានទំព័រផ្ទាល់ខ្លួន។ ការគ្រប់គ្រងកំហុស

ការបិទការតភ្ជាប់

ការបិទការតភ្ជាប់បញ្ឈប់ការបញ្ជូន មិនមែន request ទេ។ ម៉ូដែលសរសេរចម្លើយដល់ចុង ហើយ request ត្រូវបានគិតថ្លៃដូចជាអ្នកបានអានទាំងអស់។ ដើម្បីបង់តិចជាង សូមសុំតិចជាង៖ កំណត់ max_tokens ទាបជាងលើម៉ូដែលដែលអនុវត្តវា។

stream ក៏អាចបញ្ចប់មុនពេលលើផ្លូវមករកអ្នក ឧទាហរណ៍នៅពេលបណ្តាញដាច់ ឬខណៈពេល server កំពុងត្រូវបានធ្វើបច្ចុប្បន្នភាព។ ពេលនោះវាឈប់ដោយគ្មាន chunk ចុងក្រោយ និងគ្មាន data: [DONE]។ សូមចាត់ទុកចម្លើយនោះថាមិនពេញលេញ ហើយផ្ញើ request ម្តងទៀត។

ការអាន stream ដោយគ្មាន SDK

អ្នកអានត្រឹមត្រូវធ្វើប្រាំយ៉ាង៖ វាបញ្ជូន error ដែលមកដល់មុន stream ទៅការគ្រប់គ្រង error របស់វា បំបែកខ្លឹមសារជាបន្ទាត់ រំលងបន្ទាត់ 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 ឬក្រោយនេះ។

Stream នៃទ្រង់ទ្រាយផ្សេងទៀត

endpoint Responses និង Messages ក៏ stream ដែរ។ frame របស់ពួកវាមានបន្ទាត់ event: ដែលមានឈ្មោះ event និងបន្ទាត់ data: ដែលមាន JSON របស់វា។ ទំព័រនីមួយៗរាយ event របស់វាតាមលំដាប់។

ក្នុង stream Chat CompletionsResponsesMessages
Frame បន្ទាត់ data:បន្ទាត់ event: និង data:បន្ទាត់ event: និង data:
Reasoning មកដល់ក្នុង delta.reasoning_contentresponse.reasoning_summary_text.deltathinking_delta
អត្ថបទចម្លើយមកដល់ក្នុង delta.contentresponse.output_text.deltatext_delta
Usage មកដល់ក្នុង chunk ចុងក្រោយresponse.completedmessage_delta
stream បញ្ចប់ដោយ chunk ចុងក្រោយ បន្ទាប់មក data: [DONE]response.completedmessage_stop