---
title: "排查流式输出：从首字慢到断流"
description: "流式问题分两类：字来得慢，或者流到一半断。先用 curl 看原始帧，再分清代理缓冲、首字耗时与生成耗时，最后补上重连去重和超时降级。"
updated: 2026-11-13
canonical: https://docai.cc/learn/debug-streaming/
markdown_mirror: https://docai.cc/learn/debug-streaming.md
---
## 第一步：用 curl -N 看原始帧

关掉 curl 的缓冲，直接观察服务器发来的事件流：

```bash
curl -N -sS -X POST "$BASE_URL/chat/completions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"'"$MODEL"'","messages":[{"role":"user","content":"讲一段长一点的内容"}],"stream":true}'
```

重点看三件事：响应头是不是 `text/event-stream`；`data:` 行是不是一段段出现，而不是最后一次性涌出；结束处有没有结束标记。原始帧长什么样，与 [流式输出](/concepts/streaming/)的机制一致。

如果 curl 里就在最后一次性出现，问题在服务端或网络路径，不用怀疑你的客户端代码。

## 第二步：判断代理缓冲

curl 里逐段出现、应用里一次性出现，问题几乎肯定在中间层。依次检查反向代理、网关和 CDN 是否开了响应缓冲或压缩。

验证方法很简单：绕过代理直连源站再试一次。直连正常、过代理不正常，就改代理配置，不要在客户端代码里继续找。

有的服务会主动声明不要缓冲，但上层仍可能忽略这个声明。改完配置要用同一条 curl 复测，确认数据真的按段到达，而不是只看配置文件写了什么。

## 第三步：把首字与生成耗时分开

把一次请求拆成两段计时：

- 首字节耗时：从发出请求到收到第一个正文片段。
- 生成耗时：总耗时减去首字节耗时。

两段慢的原因不同。首字节慢，多半在排队、限流或输入过长，处理办法是缩短输入、退避后重试或换时段；生成慢，多半是输出太长或模型本身速度，处理办法是限制输出长度或换型号。

指标定义见[首字延迟](/concepts/ttft/)。不要用一次请求下结论，多测几次看分布，再决定优化哪一段。

## 第四步：断流后的重连与去重

先分清两种断流：连接被断开，和输出撞上最大 token 数被截断。后者不是网络问题，重连也补不回来，要做的是识别截断并提示用户。

多数接口不支持从断点续传，连接断开后只能整段重发。重发意味着输入再计一次费，而且新生成的文字不会和旧输出逐字一致。所以最稳的做法是丢弃已显示的部分、整段替换；如果必须保留旧内容，界面上要明确标出「正在重新生成」。

重连要限次数并退避。无限重连只会把一次故障放大成持续的费用和负载。

## 第五步：加超时与降级

流式至少要设两个超时：首字节超时和总超时。只设总超时，用户会长时间盯着空白；只设首字节超时，已经开始的流会永远不结束。

再加一条降级路径：重试一次仍失败，就改用非流式请求，或者缩短输出长度、把完整结果一次返回。界面上要能显示「已停止生成」，而不是一直转圈。

完整的实现见[流式输出与超时设置](/learn/streaming-and-timeouts/)；错误码怎么读见[读懂一次报错](/learn/read-an-error/)。

## 自测

1. 问：curl 里数据一段段出现，应用里却一次性收到，问题在哪？
   答：多半在中间层。反向代理、网关或 CDN 开了响应缓冲，把事件流攒到最后才转发。绕过代理直连源站验证，再改代理配置。

2. 问：首字节慢和生成慢，处理方式有什么不同？
   答：首字节慢通常在排队、限流或输入过长，要改输入、退避或换时段；生成慢通常是输出太长或模型速度，要缩短输出或换模型。

3. 问：断流后为什么不能无限重连？
   答：多数接口不支持断点续传，重发会重新计费并重新生成，内容还不保证一致。必须限制重试次数并退避，失败后降级。
