跳转到内容

使用指南

流式输出

让模型边生成边返回:各协议怎么开启流式、返回的数据长什么样、用量(usage)在哪里。

「流式输出」是指模型一边生成、一边把内容一小段一小段地发回来,而不是等全部写完再一次性返回。聊天界面里「字一个个蹦出来」的效果就是这样实现的。回答很长或模型需要思考很久时,流式能让用户更早看到内容,也能避免连接因为长时间没有数据而被中间网络断开。

流式和非流式的价格完全相同,只是返回方式不同。

四种协议都用 SSE(Server-Sent Events)格式返回流式数据:每条消息是一行 data: ...,消息之间用空行隔开。

协议 怎么开启 结束标志
OpenAI Chat Completions 请求体加 "stream": true 最后一行 data: [DONE]
OpenAI Responses 请求体加 "stream": true response.completed 事件
Anthropic Messages 请求体加 "stream": true message_stop 事件
Gemini 把地址里的 :generateContent 换成 :streamGenerateContent?alt=sse 连接关闭
终端窗口
# -N 让 curl 收到一段就打印一段,不做缓冲
curl -N https://noviahub.com/v1/chat/completions \
-H "Authorization: Bearer $NOVIAHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4-flash",
"stream": true,
"messages": [{"role": "user", "content": "写一首四行短诗"}]
}'

用 Chat Completions 流式调用时,NoviaHub 默认会在结束前多发一段只包含用量(usage)的数据:这一段的 choices 是空数组 [],usage 里是本次的 Token 数。即使你没有在请求里写 stream_options,也会收到这一段。

下面是在测试环境里抓到的一次完整返回(内容来自测试用的模拟上游,仅作格式示例):

data: {"id":"chatcmpl-mock123","object":"chat.completion.chunk","created":1790609866,"model":"deepseek-v4-flash","choices":[{"index":0,"delta":{"content":"Hello","role":"assistant"},"finish_reason":null}]}
data: {"id":"chatcmpl-mock123","object":"chat.completion.chunk","created":1790609866,"model":"deepseek-v4-flash","choices":[{"index":0,"delta":{"content":" from the mock upstream."},"finish_reason":null}]}
data: {"id":"chatcmpl-mock123","object":"chat.completion.chunk","created":1790609866,"model":"deepseek-v4-flash","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"id":"chatcmpl-mock123","object":"chat.completion.chunk","created":1790609866,"model":"deepseek-v4-flash","choices":[],"usage":{"prompt_tokens":12,"completion_tokens":7,"total_tokens":19}}
data: [DONE]
  • 如果你的程序遇到 choices 为空的数据会出错,要么在代码里先判断 choices 是否为空(如上面的 Python 示例),要么在请求里加上 "stream_options": {"include_usage": false},这时 NoviaHub 就不会发这段用量数据。
  • 无论你是否要这段用量,NoviaHub 都会按实际用量计费。

Anthropic Messages:用量在 message_delta

Section titled “Anthropic Messages:用量在 message_delta”

Anthropic 格式的流式返回依次是 message_start、content_block_start、若干 content_block_delta、content_block_stop、message_delta、message_stop。

以 message_delta 事件里的 usage 为准。 当模型需要经过协议转换(例如用 Anthropic 格式调用一个 GPT 或 DeepSeek 模型)时,message_start 里的 input_tokens 是 NoviaHub 在开始时的估算值,和最终数值可能不同。

Gemini 流式返回的每一段都是一个完整的 GenerateContentResponse 对象,每一段都带有 usageMetadata 字段。中间各段的数值不一定是最终结果(经过协议转换时,前面几段的输入 Token 是估算值、输出 Token 为 0),以最后一段的 usageMetadata 为准。

  • 以冒号开头的行:SSE 规定以 : 开头的行是注释。网关可以配置为在长时间等待时发送这类行(: PING)来保持连接。自己解析 SSE 时,遇到以 : 开头的行直接忽略即可;标准的 SSE 客户端库会自动处理。
  • 空闲超时:如果上游模型长时间没有发来任何数据,网关会结束这次流式响应。
  • 在使用日志里区分:使用日志的「耗时」列会标出「流」或「非流」。流式请求还会显示「首字」,即从发出请求到收到第一段内容用了多久。