OpenAI API 流式输出中断怎么排查?
简答:OpenAI API 流式输出中断时,先关闭业务代码,用 curl -N 直接观察 SSE:如果原始流也中断,重点查网络、代理、超时或服务状态;如果原始流正常,再查 SDK、SSE 解析和前端转发。Responses API 主要按事件类型判断是否收到 response.completed,Chat Completions 则按 data 事件和结束标记判断,不能把“没有新文本”直接当成服务端失败。
定义:OpenAI API 流式输出是通过 HTTP Server-Sent Events(SSE)逐步返回模型结果的方式;所谓“中断”,是客户端在收到完整结束信号前停止接收、解析或显示后续事件。
先做最小复现:用原始 SSE 判断问题在哪一层
本文为第三方 AI API 接入指南,内容按 OpenAI 当前公开 API 文档核对到 2026-11-03。先不要从前端、业务队列或复杂 SDK 开始排查,直接对同一个端点发起最小请求。
| 现象 | 优先怀疑 | 下一步 |
|---|---|---|
| curl -N 也只收到半段 | 网络、代理、网关空闲超时、服务端错误或模型输出未正常结束 | 保存 HTTP 状态、最后事件、请求 ID,并检查服务状态与用量数据 |
| curl -N 完整,但 SDK 中断 | SDK 迭代、异常处理、超时设置或连接关闭逻辑 | 打印每个事件或 chunk,确认是否收到结束信号 |
| 服务端收到完整流,浏览器显示半段 | 服务端转发、响应缓冲、ReadableStream 读取或前端 AbortController | 对比服务端日志与浏览器 Network 面板的最后一段数据 |
| 一直没有首个事件 | 首字节等待、请求排队、模型响应时间、连接或代理问题 | 分别记录请求发出时间、首字节时间和最后事件时间 |
Responses API 的流式请求使用 stream: true,通过 SSE 返回事件;Chat Completions 也可以使用 stream: true,但返回的是逐块传输的 data-only SSE。具体事件和字段应以当前 API Reference 为准:流式响应指南。
Responses API 的最小 HTTP 检查命令如下。将 YOUR_MODEL 换成当前项目确实可用的模型,不要直接照抄文档示例中的模型名:
curl -N --http1.1 https://api.openai.com/v1/responses -H "Content-Type: application/json" -H "Authorization: Bearer $OPENAI_API_KEY" -d '{"model":"YOUR_MODEL","input":"Reply with three short words.","stream":true}'
成功判定不是“终端打印过文字”,而是同时满足:HTTP 请求成功、持续收到 SSE 数据、能够识别文本增量,并在 Responses API 中看到 response.completed;若出现 error 事件或连接在完成事件前关闭,应记录为未完成。事件定义可查 Responses 流式事件参考。
按症状区分:首字节超时、传输中断还是解析失败
1. 长时间没有任何输出
如果请求已经建立但迟迟没有首个事件,先记录首字节时间(TTFB)和总请求时间。不要只看前端“加载中”状态;OpenAI 的排查文档建议结合模型、项目、服务层级和时间范围查看请求时间、首个 token 时间及错误率。可从 API 错误与延迟排查文档开始。
检查顺序是:确认请求确实发出;确认端点、模型和 Key 没有被兼容层改写;再检查客户端、反向代理和负载均衡器的连接及空闲超时。若服务端监控中没有对应请求,而客户端已经报超时,优先查请求是否在代理或本地网络阶段被拦截。
2. 已经输出一部分,随后连接关闭
保存最后一次收到的事件类型、事件序号、时间戳和响应 ID。对 Responses API,收到 response.output_text.delta 只代表收到增量,不代表响应完成;正常完成应继续等待 response.output_text.done 或 response.completed。出现 error 事件、HTTP 错误或连接关闭,则分别记录错误事件或传输异常。
如果使用 Chat Completions,应检查每个 chunk 的 choices 是否为空、delta 是否只有角色或其他非文本字段。不要假定每个 chunk 都包含文本,也不要只用“最后一个文本块为空”判断成功;Chat Completions 的流式 chunk 结构以 Chat Completions 流式事件参考为准。
3. 原始流正常,但应用内容少了一截
这通常应优先检查解析器和业务转发,而不是先重试 API。重点确认:是否按 SSE 的事件边界读取;是否允许一个网络数据块包含半个事件或多个事件;是否错误地把非文本事件丢弃;是否在收到空内容时提前退出;是否在客户端组件卸载时触发了取消。
浏览器 fetch、Node.js 服务端转发和 Python SDK 的读取逻辑不同。排查时先把每个原始事件写入脱敏日志,再单独测试“读取—解析—拼接”这一步。日志不要记录 API Key、完整 Authorization 头或用户隐私输入。
Responses API 与 Chat Completions:结束信号不要混用
| 项目 | Responses API | Chat Completions |
|---|---|---|
| 开启方式 | 请求体设置 stream: true | 请求体设置 stream: true |
| 主要读取对象 | 按事件的 type 处理,例如文本增量事件 | 按 chunk 读取 choices[].delta |
| 正常结束判断 | 优先等待 response.completed,并结合文本完成事件 | 按当前接口返回的结束事件或结束标记判断,不要只看最后一段文本 |
| 发生错误时 | 检查 error 事件及响应状态 | 检查 HTTP 状态、响应体和 SDK 异常 |
| 适用边界 | 事件类型更多,适合按语义事件处理 | 已有兼容实现较多,但不同服务的字段兼容性需要单独核实 |
OpenAI 当前流式指南说明,Responses API 使用有明确类型的语义事件;Chat Completions 则返回 data-only SSE,流式内容位于 chunk 的 delta 字段。不要把某个兼容接口的结束标记、字段名或事件顺序,未经核验地套到另一个接口上。
如果你使用的是 OpenAI-compatible Base URL,中转层可能改变模型名、错误体、事件格式或结束行为。本文的命令和事件判断只适用于能按对应 API 文档返回数据的接口;兼容实现的差异需以服务商 API Reference 和实际响应为准。
代理、网关和前端转发:重点查缓冲与空闲超时
当直连测试完整、经过你的服务后中断时,按以下顺序做对比:
- 服务端直连上游:在后端记录上游 HTTP 状态、首字节时间、最后事件时间、总耗时和最后事件类型。
- 服务端转发给客户端:比较上游最后事件与下游最后事件,确认是否在转发层提前结束、聚合或丢弃数据。
- 浏览器读取:查看 Network 面板的响应是否仍在增长,并检查是否调用了
AbortController.abort()、路由切换或组件卸载。 - 代理和负载均衡:核对响应缓冲、连接保持和空闲超时配置。具体配置项随 Nginx、CDN、云负载均衡器和部署方式不同,不能把某个平台的配置名直接当作通用规则。
如果代理在一段时间没有收到数据就关闭连接,应分别提高适用的客户端、网关和上游超时,或确认上游是否能持续产生事件。不要仅靠“增加超时时间”掩盖解析错误;先用 curl -N确认原始流是否持续到正常结束。
OpenAI 的排查建议指出,若客户端出现错误但服务健康数据中没有对应请求,问题更可能发生在上游网络、代理或客户端超时阶段;遇到持续性问题时,应保留请求时间、时区、模型、端点和请求 ID。参考:Troubleshooting API Errors and Latency。
断线后怎么重试:先判断是否可以安全重放
流式请求断开后,已经输出的文字可能已经展示给用户,但应用未必知道服务端是否完成。因此,普通重试不等于断点续传,也不能保证不会重复生成或重复执行工具调用。
- 如果在收到正常完成事件前断开,将本次结果标记为未完成,不要把缺少 usage 或缺少最后事件当作零用量。
- 重试前保存原始请求的模型、输入摘要、请求时间、响应 ID、最后事件类型和已输出文本长度。
- 只有在操作具备幂等边界、不会重复产生副作用时,才自动重试;涉及写入、扣费、发消息或工具调用时,先查询结果或要求用户确认。
- 遇到 429、503 或明确的临时连接错误,遵循响应中的
Retry-After(如果存在),设置最大尝试次数和总截止时间,并加入随机抖动。 - 遇到 Key、权限、模型不存在、请求格式或额度错误,不要无限重试,应先修正配置。
OpenAI 的错误码文档将连接异常、超时、限流、认证错误、资源不存在和服务端错误区分处理;429 排查还应关注 Retry-After,避免连续发送相同请求扩大限流影响。参考 OpenAI API 错误码文档 和 429 错误排查文档。
一张排查清单:提交问题前先收集这些信息
- 请求信息:接口类型、端点、模型、是否使用兼容 Base URL、请求开始时间和时区。
- 连接信息:HTTP 状态、首字节时间、最后事件时间、总耗时、是否经过 CDN、网关或负载均衡器。
- 流信息:最后一个事件类型、事件序号或 chunk 摘要、是否收到正常结束信号、是否出现错误事件。
- 客户端信息:SDK 名称与版本、运行环境、超时配置、是否主动取消、是否发生页面切换。
- 安全边界:只提交脱敏后的请求 ID、错误代码和必要日志,绝不要提交 API Key、Authorization 头或完整敏感输入。
如果问题只发生在单个项目、单个模型或某一时间段,先按项目和模型过滤监控数据;不要把多个模型、项目或服务层级混在一起比较。OpenAI 的延迟排查资料建议同时关注请求时间、首个 token 时间、错误率和输出 token 等指标。
常见问题
OpenAI API 流式输出只返回半段,是模型问题吗?
不一定。先用 curl -N 直接请求同一个端点。如果原始 SSE 也在完成事件前断开,再查网络、代理、超时、服务状态和错误响应;如果原始流完整,优先查 SDK、SSE 解析、服务端转发或前端取消。
OpenAI API 流式输出一直没有内容,应该先改超时时间吗?
不要先盲目改超时。先记录请求是否发出、HTTP 状态、首字节时间和代理链路;同时确认模型、Key、端点和请求格式。若监控中没有对应请求,问题更可能在客户端、代理或网络阶段。
Responses API 收到 response.output_text.delta 后就能认为成功吗?
不能。delta 只是文本增量事件,仍需等待文本完成或 response.completed 等正常结束信号。若连接在完成事件前关闭,应按未完成处理,并保存最后事件和响应 ID。
Chat Completions 和 Responses API 的流式解析可以共用吗?
不能直接共用。Responses API 按事件类型处理,Chat Completions 主要从 chunk 的 choices[].delta 读取增量;两者的事件结构和结束判断应分别依据对应 API Reference 核对。
流式中断后自动重试会不会重复计费或重复执行?
存在重复处理风险。断线后客户端不一定知道服务端是否已经完成,因此重试前应判断操作是否可安全重放,给有副作用的请求设置幂等边界,并限制重试次数和总时长。不能把普通重试称为断点续传。
相关阅读
- 先看 OpenAI API timeout 超时怎么分层排查
- 遇到 429 时按限流与 Retry-After 排查
- 确认 API Key 和认证链路是否正常
- 兼容接口先核对 Base URL、/v1 和模型名
- 模型或端点异常时检查 404 model not found
参考资料
- Streaming API responses | OpenAI API
- Responses streaming events | OpenAI API Reference
- Chat Completions streaming events | OpenAI API Reference
- Troubleshooting API Errors and Latency | OpenAI Help Center
- Error codes | OpenAI API
- Troubleshooting API rate limits and 429 errors | OpenAI Help Center
- Create a model response | OpenAI API Reference