流式输出
按协议读取 SSE 增量,正确处理完成事件、工具参数、错误与连接中断。
流式输出的工作方式
在支持流式的文本模型上设置 stream: true,服务端使用 Server-Sent Events(SSE)逐步返回结果。SSE 是以空行分隔的事件,不是一份完整 JSON。一个网络数据块可能只包含半个事件,也可能包含多个事件;不能把每次网络读取直接交给 JSON 解析器。
流式不会减少模型需要生成的内容或保证降低费用,也不替代超时和并发控制。本文示例仅展示格式与处理方法,不提供实际延迟数据。
三种端点的事件差异
| 端点 | 主要增量位置 | 结束信号 | 当前注意事项 |
|---|---|---|---|
POST /v1/chat/completions | choices[].delta.content | data: [DONE],同时检查 finish_reason | 工具参数和推理文本有各自字段,不应并入最终文本 |
POST /v1/responses | response.output_text.delta 事件的 delta | response.completed | 当前桥接主要转换文本,不完整保留工具或推理事件 |
POST /v1/messages | content_block_delta 的 delta.text | message_stop | 区分文本、Thinking 与工具内容块;工具流为基础兼容实现 |
成功建立 SSE 后,响应 Content-Type 为 text/event-stream。建立前的鉴权、参数或上游连接错误仍可能返回普通 JSON 和非 2xx HTTP 状态。请先判断 HTTP 状态及内容类型,再选择解析器。
完整调用示例
curl -N 关闭客户端输出缓冲。Python 示例依赖 openai 包,关闭自动重试,并显式判断是否见到选择项的结束原因。环境变量 GFW_API_KEY 必须提前设置。
curl --no-buffer --fail-with-body --silent --show-error \
--max-time 120 \
https://api.gfw.net/v1/chat/completions \
-H "Authorization: Bearer ${GFW_API_KEY:?请先设置 GFW_API_KEY}" \
-H 'Content-Type: application/json' \
-H 'Accept: text/event-stream' \
--data '{
"model": "deepseek-v4-pro",
"messages": [{"role": "user", "content": "用三句话说明连接池的作用。"}],
"max_tokens": 512,
"stream": true
}'示例只处理文本。工具场景要额外收集 delta.tool_calls,推理场景要单独处理模型提供的推理字段。用量事件可能没有 choices,客户端必须允许空数组;也不要假设每次流式调用都能得到完整 usage。
事件与响应示意
下面为 Chat Completions SSE 结构示意,事件顺序与文本仅用于说明:
data: {"id":"chatcmpl_example","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl_example","choices":[{"index":0,"delta":{"content":"连接池"},"finish_reason":null}]}
data: {"id":"chatcmpl_example","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]
Responses 的文本事件结构示意:
event: response.output_text.delta
data: {"type":"response.output_text.delta","delta":"连接池"}
Anthropic Messages 的文本事件结构示意:
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"连接池"}}
解析命名事件时同时保留 event 名称和 JSON 内 type。不要将 message_stop、response.completed 与 Chat 的 [DONE] 混为一种统一的字符串终止符。
中断、错误与应用状态
流开始后 HTTP 状态已固定,后续异常可能表现为流内 error、连接断开,或缺失预期内容。HTTP 200 和收到结束事件都不足以证明答案完整;Chat 转发在部分异常结束后仍会补发 [DONE],Responses 桥接也可能发出最终标签。因此必须结合异常、内容、结束原因和应用校验判断。
推荐保存 receiving、completed、failed 等应用状态:收到增量时只追加到临时结果,完成并通过校验后再提交业务结果。连接中断时保留已经收到的文本,但标为不完整。重新发起请求可能重复生成与计费,不应自动把新流追加到旧流。
工具参数必须按调用索引收集完整 JSON 后再解析和执行。针对 Anthropic 工具流,当前桥接存在非完整原生事件兼容边界,复杂工具流程优先使用非流式返回。
接入注意与相关文档
保持 SDK 的连接读取超时,并为业务操作设置总时限。中间反向代理若启用了响应缓冲,界面可能直到结束才收到文本;排查时比较直接 cURL 输出与应用读取结果,不要据此推断模型没有流式能力。
用量和账单以 用量与调用日志 及 计费与充值 为准。相关文档:OpenAI 兼容 API、Responses API、Anthropic 兼容 API、工具调用、错误码与重试。