Salti al la enhavo
Fluigo

Fluigo

Agordu stream al true kaj la respondo alvenas kiel server-sent events dum la modelo skribas ĝin: unue rezonado, poste la respondo, poste lasta peco kun la kialo de fino kaj la usage. Uzu ĝin kiam ajn homo atendas la tekston, kaj por longaj respondoj.

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

La SDK de OpenAI donas al vi la pecojn unu post la alia. Legu ĉiun pecon laŭ tio, kion ĝi portas: peceton de rezonado, peceton de la respondo, vokon de ilo, aŭ la finon de la respondo.

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

Kiel fluo estas enkadrigita

  • La respondo havas staton 200 kaj la kapojn content-type: text/event-stream kaj cache-control: no-cache.
  • Ĉiu evento estas unu linio, kiu komenciĝas per data: kaj estas sekvata de malplena linio. La teksto post data: estas unu JSON-peco. Ne ekzistas linioj event: aŭ id:.
  • Linio, kiu komenciĝas per dupunkto, kiel : ping, estas komento, kiu tenas la konekton malfermita. Preterpasu ĝin.
  • La fluo finiĝas per data: [DONE]. Fluo, kiu haltas sen ĝi, estas nekompleta.

Pecoj laŭorde

Ĉiu peco estas objekto 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
    }
  ]
}

Ĉiuj pecoj de unu fluo portas la samajn id, created kaj model. choices ĉiam enhavas unu eron. Ĝia delta enhavas tion, kio estas nova, kaj finish_reason estas null ĝis la lasta peco.

Ŝlosilo en delta Tipo Priskribo Sendita de
role string Ĉiam assistant. Ĝi alvenas unufoje, ĉe la komenco de la fluo. Gastigitaj malfermpezaj modeloj, shannon-2-lite, shannon-2-pro
reasoning_content string Peceto de la rezonado de la modelo. Kunigu la pecetojn laŭorde. Gastigitaj malfermpezaj modeloj, familio Shannon 3, shannon-1.6-pro, shannon-coder-1
content string Peceto de la respondo. Kunigu la pecetojn laŭorde. Ĉiuj modeloj
tool_calls array Unu kompleta voko de ilo. Vidu Deltoj de vokoj de iloj. Ĉiuj modeloj

Rezonado venas unue, poste la respondo, poste eventualaj vokoj de iloj. Legu pecon laŭ la ŝlosiloj en ĝia delta, ne laŭ ĝia loko en la fluo: delta povas enhavi role kune kun la unua peceto de teksto, kaj la lasta estas malplena.

Tuta fluo tia, kia ĝi vojaĝas. Por teni la liniojn mallongaj, id, object, created kaj model estas lasitaj ekster ĉiu peco ĉi tie.

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]

Deltoj de rezonado

Modelo, kiu rezonas, sendas sian rezonadon en delta.reasoning_content antaŭ la respondo. Tenu la du tekstojn apartaj: montru la rezonadon kiel apartan, faldeblan parton, aŭ lasu ĝin ekster.

La gastigitaj malfermpezaj modeloj sendas neniun rezonadon kiam reasoning_effort estas off, kaj neniun kiam la peto havas response_format.

shannon-2-lite kaj shannon-2-pro ankaŭ rezonas antaŭ ol respondi. Ĉe ĉi tiu endpoint ili sendas komentliniojn : thinking dum ili faras tion, kaj poste la respondon.

reasoning_content ne estas en la tipitaj modeloj de la SDK de OpenAI. En Python legu ĝin per getattr(delta, "reasoning_content", None); en JavaScript delta.reasoning_content funkcias tia, kia ĝi estas.

Deltoj de vokoj de iloj

Voko de ilo alvenas tuta: unu peco por voko, kies delta enhavas la vokon kun la kompleta ĉeno arguments. index numeras la vokojn de la respondo ekde 0. Kodo, kiu kunigas arguments peceton post peceto, funkcias senŝanĝe, ĉar ĝi kunigas unu peceton.

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

Post la vokoj, la lasta peco havas finish_reason tool_calls.

Kiam la peto havas tools, shannon-1.6-lite, shannon-1.6-pro kaj shannon-coder-1 sendas la tekston de la respondo kiel unu delta ĉe la fino de la respondo.

La lasta peco

La lasta peco antaŭ data: [DONE] havas malplenan delta, la finish_reason kaj la usage de la peto, ĉio en la sama peco. Ĉiu fluo havas ĝin; vi ne bezonas 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
  }
}

Ĉe la gastigitaj malfermpezaj modeloj usage havas ankaŭ prompt_tokens_details.cached_tokens kaj completion_tokens_details.reasoning_tokens.

Post peto kun web_search: true, kies serĉo trovis ion, la lasta peco portas ankaŭ sources, kaj unu peco antaŭ ĝi portas la citmarkojn kiel delta.annotations. Retserĉo

finish_reason Priskribo Sendita de
stop La modelo finis sian respondon, aŭ aperis ĉeno stop. Ĉiuj modeloj
tool_calls La respondo enhavas unu aŭ plurajn vokojn de iloj. Ĉiuj modeloj
length La respondo estis detranĉita ĉe la eliga limo. Familio Shannon 3, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1

La kampoj de usage estas priskribitaj ĉe la endpoint. Chat Completions

Linioj keep-alive

Dum la modelo laboras kaj ankoraŭ havas nenion por sendi, la fluo portas komentliniojn. Ili enhavas neniujn datumojn. Analizilo de SSE preterpasas ilin mem; kodo, kiu legas krudajn liniojn, devas preterpasi ĉiun linion, kiu komenciĝas per dupunkto.

Linio Sendita de Kiam
: ping Familio Shannon 3, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 Ĉiujn 15 sekundojn.
: keepalive Gastigitaj malfermpezaj modeloj Ĉiujn 15 sekundojn dum la modelo laboras.
: thinking shannon-2-lite, shannon-2-pro Dum la modelo rezonas.

Eraroj en fluo

Post kiam fluo komenciĝis, ĝia stato estas 200, do malsukceso alvenas ene de la fluo: peco kun membro error tie, kie estus 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]

Post la erara peco ankoraŭ sekvas la lasta peco, kun finish_reason kaj usage, kaj data: [DONE]. Kontrolu ĉiun pecon pri error. Sen tiu kontrolo respondo, kiu malsukcesis meze, aspektas kompleta.

Tipo Kodo Mesaĝo Kiam
api_error The model backend failed to answer. Please retry. La modelo malsukcesis, aŭ skribis nenion. Resendu la peton.
rate_limit_error Shannon routes are temporarily busy. Please retry. La modelo estas okupata en ĉi tiu momento. Atendu kelkajn sekundojn kaj resendu la peton.
invalid_request_error context_length_exceeded La konversacio estas pli longa ol la kunteksta fenestro de la modelo. Mallongigu ĝin antaŭ ol resendi. La teksto de la mesaĝo varias.

La gastigitaj malfermpezaj modeloj sendas la membron error nur kun type kaj message.

La SDK de OpenAI por Python kaj JavaScript ĵetas eraran pecon kiel API-eraron dum vi iteracias, do envolvu la ciklon en via kutima traktado de eraroj.

Statokodoj, la erarkorpo kaj kion reprovi havas propran paĝon. Erarotraktado

Fermo de la konekto

Fermi la konekton haltigas la liveron, ne la peton. La modelo skribas la respondon ĝis ĝia fino kaj la peto estas kalkulata kvazaŭ vi legus ĝin tutan. Por pagi malpli, petu malpli: agordu pli malaltan max_tokens ĉe modelo, kiu aplikas ĝin.

Fluo povas ankaŭ finiĝi frue survoje al vi, ekzemple pro rompo de reto aŭ dum servilo estas ĝisdatigata. Ĝi tiam haltas sen la lasta peco kaj sen data: [DONE]. Traktu tiun respondon kiel nekompletan kaj resendu la peton.

Legado de fluo sen SDK

Ĝusta legilo faras kvin aferojn: ĝi sendas erarojn, kiuj alvenas antaŭ la fluo, al sia traktado de eraroj, dividas la korpon en liniojn, preterpasas komentliniojn, haltas ĉe data: [DONE], kaj kontrolas ĉiun pecon pri 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))

La ekzemplo de Python uzas la pakaĵon requests. La ekzemplo de JavaScript funkcias en Node.js 18 aŭ pli nova.

Fluoj de la aliaj formatoj

La endpoints Responses kaj Messages ankaŭ fluas. Iliaj kadroj portas linion event: kun la nomo de la evento kaj linion data: kun ĝia JSON. Ĉiu paĝo listigas siajn eventojn laŭorde.

En la fluo Chat CompletionsResponsesMessages
Kadroj Linioj data:Linioj event: kaj data:Linioj event: kaj data:
Rezonado alvenas en delta.reasoning_contentresponse.reasoning_summary_text.deltathinking_delta
Teksto de la respondo alvenas en delta.contentresponse.output_text.deltatext_delta
Usage alvenas en La lasta pecoresponse.completedmessage_delta
La fluo finiĝas per La lasta peco, poste data: [DONE]response.completedmessage_stop