流式输出是什么
流式输出指模型边生成边返回:请求里带 stream 为真,服务端改用以 text/event-stream 为类型的响应,按行推送增量片段,每行以 data: 开头,最后用 data: [DONE] 收尾。它的核心价值是首字延迟:用户几乎立刻看到文字开始出现,长回答的体感差异非常明显。代价是解析逻辑更复杂,错误处理、用量统计与超时控制都要重新设计。
基本信息
| 开启方式 | 请求体里把 stream 设为真 |
|---|---|
| 响应类型 | text/event-stream,逐行推送 |
| 每行格式 | data: 加一段 JSON,结束时推送 data: [DONE] |
| 增量位置 | choices 数组里的增量字段携带内容片段 |
| 首字延迟 | 显著低于非流式,但总耗时基本相同 |
| 注意事项 | 用量统计、错误处理与超时策略需要单独设计 |
流式返回的字段读法
| 字段 | 含义 | 注意 |
|---|---|---|
| data 行 | 单个增量片段 | 以 data: 前缀,多为一行一条 |
| 结束标记 | 推送结束信号 | 不要把它当成正常内容解析 |
| 增量内容 | 本片段的文字或工具调用参数 | 首条可能只带角色,内容为空 |
| 结束原因 | 说明为何停止生成 | 输出长度耗尽与自然结束要区分处理 |
| 用量字段 | token 用量统计 | 部分接口在流式下需显式请求才返回 |
典型使用场景
- 对话产品:边生成边显示,降低用户等待焦虑
- 长文生成:总结、报告类内容逐段呈现,可提前阅读
- 语音合成:文本片段到手就能送进合成链路,缩短整体时延
- 前端体验优化:先渲染骨架再逐字填充,页面不出现长时间空白
- 多步任务:把中间进度实时透出,让用户知道系统仍在工作
- 长回答的取消操作:用户中途放弃时可直接断开连接,省下剩余生成费用
流式请求与增量解析
流式请求与增量解析
curl -N -s https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" -d '{"model":"gpt-4o","stream":true,"messages":[{"role":"user","content":"写一段产品介绍"}]}' # 关掉缓冲立即输出
# 每行以 data: 开头,解析后取增量内容拼接,直到收到结束标记
# 客户端要处理断流:网络中断时应能重连或降级为非流式请求
# 流式下错误可能在开始推送之后才出现,前端需预留错误展示位Python 侧逐块消费
Python 侧逐块消费
stream = client.chat.completions.create(
model="gpt-4o", stream=True,
messages=[{"role": "user", "content": "写一段产品介绍"}],
)
for chunk in stream: # SDK 已把 SSE 解析成对象
piece = chunk.choices[0].delta.content
if piece: # 首条增量可能为空
print(piece, end="", flush=True)
# 循环结束后再取用量或结束原因,避免中途字段缺失导致报错流式相关参数与调优
| 手段 | 作用 | 注意 |
|---|---|---|
| 开启流式 | 请求体里打开逐块推送 | 网关与代理的响应缓冲要同步关闭 |
| 按行批量输出 | 部分接口支持一次推多行 | 兼容模式下未必支持,需实测 |
| 读超时 | 按总生成时长放宽 | 用首字节超时会导致长回答被误杀 |
| 心跳保活 | 长时间无输出时维持连接 | 中间设备的空闲超时会直接断流 |
| 断点续传 | 已输出内容保留,续写剩余部分 | 需服务端配合,简单重试会产生重复段落 |
流式和后端的缓冲设置容易打架:反向代理与网关若不关闭响应缓冲,前端会一次性收到全部内容,看起来像没生效。
流式返回的用量统计在部分接口上默认不返回:需要成本核算时,请按官方文档显式开启或在非流式路径上单独统计。
流式下的重试要格外小心:已经推送给用户的内容无法撤回,重试后会出现重复段落,需在服务端做去重或从断点继续。