LLM 流式接口在返回 HTTP 200 后中途报错或断流
排查“状态码明明是 200 OK,但生成到一半中断、报 JSON 解析错误或卡死”的运行期故障。
观察收到 HTTP 200 响应头之后的原始 SSE 数据流或日志,中断前发生了什么?
curl -i -N http://127.0.0.1:11434/v1/chat/completions -H "Content-Type: application/json" -d '{"model":"qwen2.5:7b","stream":true,"messages":[{"role":"user","content":"Hello"}]}'「LLM 流式接口在返回 HTTP 200 后中途报错或断流」的全部 1 步终端探测命令与分支判据
无需逐层点击交互,以下列出本故障决策树每一层的宿主机只读探测命令、预期基线提示与输出流向。
观察收到 HTTP 200 响应头之后的原始 SSE 数据流或日志,中断前发生了什么?
curl -i -N http://127.0.0.1:11434/v1/chat/completions -H "Content-Type: application/json" -d '{"model":"qwen2.5:7b","stream":true,"messages":[{"role":"user","content":"Hello"}]}'- • 流式数据帧中途收到了 {"error": ...} 或 type: "error" 事件
→ sol-sse-midstream-error-handler - • 在长 Prompt 预填充或深度推理思考期间卡住,并在固定 60 秒断开
→ sol-proxy-buffering-timeout - • 正常收到 [DONE] 结束符,但下游解析生成的 JSON 时报语法错误
→ sol-finish-reason-length
「LLM 流式接口在返回 HTTP 200 后中途报错或断流」包含的 3 类根因、修复代码与验收命令
修复方案:在每个 SSE 数据帧中检测 error 字段,不能只检查 HTTP 状态码
sol-sse-midstream-error-handler流式接口一旦发送了 HTTP 200 响应头,后续生成过程中若发生后端过载、显存不足或上下文超限,服务端已无法修改 HTTP 状态码,只能往 SSE 流内写入 error 事件。
- 在消费每个 `data:` JSON 帧时,先判断是否存在 `event.error` 或 `event.type === "error"`。
- 捕获到流内错误后立即中止拼接,丢弃半截残缺文本并执行带退避策略的重试。
const payload = JSON.parse(rawDataLine);
if (payload.error || payload.type === 'error') {
throw new Error(`Mid-stream error after HTTP 200: ${payload.error?.message || JSON.stringify(payload)}`);
}[边界说明]这是 Claude 官方文档与 OpenAI 兼容流式协议明确强调的生产级边界条件。
node sse-stream-guard.mjs修复方案:关闭反向代理缓冲并延长长上下文/推理模型读取超时
sol-proxy-buffering-timeout本地模型处理万字长 Prompt 预填充(Time-to-First-Token)可能耗时 20–90 秒期间无数据帧返回,触发 Nginx 或网关默认 60 秒空闲超时切断。
- 在 Nginx 或反向代理配置中设置 proxy_buffering off 与 proxy_read_timeout 300s。
- 客户端侧将首字等待超时(TTFT Timeout)与分块空闲超时区分设置。
# Nginx location block for LLM SSE endpoints
location /v1/ {
proxy_pass http://127.0.0.1:11434/v1/;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
chunked_transfer_encoding on;
}[边界说明]若经由云端代理转发,还需注意云厂商网关默认的 100 秒无字节传输限制。
nginx -t && sudo systemctl reload nginx修复方案:解析结构化 JSON 前先校验 finish_reason 是否为 length 截断
sol-finish-reason-length模型输出达到了 max_tokens(或 num_predict)上限,导致 JSON 字符串在闭合括号前被截断,但流本身正常发送了 [DONE]。
- 在执行 JSON.parse 前,强制检查最后一个 Chunk 的 finish_reason 是否为 "stop"。
- 若使用带 <think> 标签的推理模型,需预留至少 2048 max_tokens 并在解析前剥离思考块。
if (lastChunk.choices?.[0]?.finish_reason === 'length') {
throw new Error('Output truncated by max_tokens limit before JSON closed');
}[边界说明]即使开启了 json_object 模式,一旦触及 max_tokens 上限依然会产生未闭合的残缺 JSON。
echo "Verified finish_reason guard"LLM API 在 HTTP 200 后流式报错:错误发生条件与恢复边界
为什么简单的状态码列表不足以覆盖运行中的失败:深入解析 HTTP 200 响应头发出后的 SSE 流内错误帧、反向代理超时切断与 JSON 截断恢复策略。
Node.js 22.13+ 流式客户端 · 适用于 Claude API、OpenAI 兼容接口及本地 Ollama / vLLM
Node.js 22.13+ · Anthropic Messages SSE · OpenAI Chat Completions SSE
同时适用于本地与云端流式 API — 配套抗中断 SSE 解析器代码,可在本地零成本验证流内异常捕获与超时取消逻辑。