直接答案
流式请求在 HTTP 200 后仍可能失败;必须验证事件序列、结束标记和客户端取消状态,不能把部分文本当作完成。
这篇内容解决什么问题
解决 SSE 流式响应中断、premature EOF、stream closed 和输出停在一半。
先确认症状与影响范围
请求先返回 200 并产生部分 Token,随后出现 stream disconnected、premature EOF、连接关闭或没有正常结束事件。业务若直接保存部分内容,可能误把不完整答案当成成功。
非流式请求稳定而流式失败,问题集中在 SSE 消费、代理缓冲、idle timeout 或长连接生命周期。
- 保存最后一个完整事件类型、是否收到结束信号以及连接持续时间。
- 比较同一最小请求的 stream=false 与 stream=true。
- 确认客户端主动取消、用户断开和服务端关闭能被区分。
常见原因与责任边界
SSE 跨越模型、网关、代理和客户端解析器。每层都可能缓冲、改写、超时或截断事件,因此只检查最终文本不够。
- 代理缓冲响应,或 read/idle timeout 小于事件间隔。
- 客户端没有持续消费流,产生背压或错误地关闭 AbortSignal。
- 网关未正确转发
text/event-stream、空行分隔或结束事件。 - 网络切换、连接重置或上游生成异常导致提前 EOF。
按层执行最小诊断
先用 curl -N 观察原始事件边界,再用 SDK 消费同一请求。原始流完整而 SDK 失败,重点检查解析与取消逻辑;两者都失败则检查代理和网关日志。
诊断时使用无敏感内容的短提示。不要把完整流式业务输出写入公共日志。
- 01非流式基线确认相同模型和输入在非流式模式稳定完成。
- 02观察原始 SSE检查 Content-Type、事件空行、数据帧和结束信号。
- 03检查代理确认禁用不当缓冲,并对齐 read/idle timeout。
- 04检查消费者确认 for-await/迭代循环持续读取并正确处理取消。
curl -N -sS --max-time 120 'https://<your-api-host>/v1/chat/completions' -H "Authorization: Bearer ${API_KEY:?set API_KEY first}" -H 'Content-Type: application/json' --data '{"model":"<YOUR_MODEL_ID>","stream":true,"messages":[{"role":"user","content":"reply with three short words"}]}'针对根因完成修复
修复代理的 SSE 转发、缓冲和空闲时限,并让客户端完整消费事件。是否重连取决于接口是否提供可恢复游标;没有恢复语义时,自动重发可能重复计费或重复工具动作。
- 01保持事件流转发正确 Content-Type,不合并或缓存整个响应。
- 02对齐时限让代理 idle timeout 覆盖合理事件间隔并保留总 deadline。
- 03处理取消区分用户取消、客户端超时和服务端异常结束。
- 04标记不完整缺少正常结束时丢弃或显式标记部分输出。
started = false
completed = false
for event in stream:
started = true
validate_and_append(event)
if event_is_terminal(event): completed = true
if not completed:
mark_result_incomplete()
do_not_execute_follow_up_actions()验证修复而不是只看一次成功
连续运行短流、长流、主动取消和代理空闲边界测试。每次都应明确完成、取消或失败,不能留下状态未知的部分结果。
- 响应 Content-Type 和事件分隔符合目标协议。
- 短流与长流都收到正常结束信号。
- 取消后连接释放,部分输出不会触发后续动作。
安全边界与升级证据
流式日志容易意外记录完整提示和模型输出。生产日志只保留事件计数、耗时、结束原因和 request ID;工具调用参数按敏感数据处理。
- 不把完整事件数据写入 access log。
- 不在没有幂等保证时自动重放整个流。
- 不对截断输出执行发布、支付或写库动作。
官方来源与核验范围
本文以协议规范和客户端官方文档为事实依据。错误文案、重试头和配置字段可能随服务或客户端版本变化;执行前请核对来源,并对日志与请求样例脱敏。
查看技术核验方法