流式传输
SSE(主流方式)
OpenAI 与 Anthropic 协议都用 text/event-stream,但事件格式不同。
OpenAI 格式
请求体加 "stream": true:
data: {"choices":[{"delta":{"content":"你"},"index":0}]}
data: {"choices":[{"delta":{"content":"好"},"index":0}]}
data: [DONE]
- 只用
data:行 - 结束标记是
data: [DONE]
Anthropic 格式
event: message_start
data: {"type":"message_start","message":{...}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"你"}}
event: message_stop
data: {"type":"message_stop"}
- 必须同时解析
event:行,只读data:会分不清事件类型
:::danger 最常踩的坑
把 Anthropic 的流当 OpenAI 解析 → delta.text 取不到(它在
delta.text,不在 delta.content),表现为"流式没输出但请求成功"。
:::
客户端要点
| 项 | 说明 |
|---|---|
| 缓冲区 | 不要按行缓冲,SSE 事件以空行分隔 |
| 断线 | 流中断后已产生的 token 仍计费 |
| 超时 | 长输出要设较大的读超时,别用默认 30s |
| 代理 | Nginx 必须关 proxy_buffering,否则流被攒成一坨 |
Nginx 关键配置:
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
Cloudflare 有自己的 100 秒响应限制,长流式会话需要注意。
WebSocket
另有两条 WebSocket 通道:
| 路径 | 用途 |
|---|---|
GET /v1/realtime | OpenAI Realtime 协议 |
GET /v1/responses | Responses API 事件协议 |
WebSocket 在 token 鉴权之后才做渠道选择,每个事件单独走限流。
示例:Python 流式
from openai import OpenAI
client = OpenAI(api_key="***", base_url="https://187api.com/v1")
for chunk in client.chat.completions.create(
model="MiniMax-M2.5",
messages=[{"role": "user", "content": "写一段 100 字的介绍"}],
stream=True,
):
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)