流式输出(SSE)在中转站上的六种异常,以及每一类的定位方法
为什么流式是「照妖镜」
中转站在非流式模式下只需要把上游的响应体整段转发,实现简单、不容易出错。而流式模式下,它必须逐块解析上游的 SSE、再逐块重新封装。任何格式理解上的偏差都会立刻暴露在输出里。
所以:评估一家中转站的技术实现水平,看非流式不如看流式。
异常一:输出出现重复 token
表现:同一段文字里个别字词重复出现,如「我们可以我们可以用一个」。
成因:增量计算错误。上游某些实现返回的是累计文本而不是增量 delta,网关如果按「差量」处理,就会把已输出过的内容再输出一次;反之则会丢字。
定位方法:
- 用同一个 prompt 分别走流式和非流式,比对最终文本是否一致;
- 非流式正确、流式重复 → 确认是网关的分块处理问题;
- 换一个上游模型测试 → 若只有某个模型出问题,说明是「该上游的格式适配」没做对。
结论:这是网关实现缺陷,不是模型问题。同一家站的其他模型可能正常,可以只避开出问题的那个。
异常二:中文或 emoji 被切坏(出现乱码或问号)
表现:输出里出现 ?、�(替换字符),或中文被拆成两半。
成因:字节边界与字符边界不对齐。SSE 的分块是按字节来的,一个 UTF-8 汉字占 3 字节、emoji 占 4 字节,完全可能被切在两个 chunk 之间。如果网关在拼接时用了按字节切分的逻辑(或者在中途做了 substr),就会切断多字节字符。
定位方法:
- 让模型输出一段中文 + emoji + 代码块的混合内容;
- 观察是否只在特定位置出现乱码(切坏的地方通常是固定的几个位置,因为分块策略是确定的);
- 用
curl --no-buffer直接看原始 SSE 流,确认是网关输出就已损坏,还是你的客户端解析有问题。
结论:网关的多字节处理 bug。这类问题属于低级实现错误,出现它说明该站的流式适配没有认真测试过。
异常三:缺少结束标记或缺少 [DONE]
表现:客户端一直等待,不结束;或客户端报「流意外结束」。
成因:两种 —— 网关只转发了 data: 行而丢掉了 data: [DONE];或上游用了不同的事件结束方式(Anthropic 是 message_stop 事件),网关没有把它转换成客户端的 [DONE]。
定位方法:curl -N 抓原始流,看最后一个 chunk 是什么。以 OpenAI 协议为例,正常流必须以 data: [DONE] 结束。
结论:协议转换不完整。如果你的客户端依赖结束标记来做后续处理(比如自动保存),这个问题会直接破坏功能。
异常四:首字延迟(TTFT)远高于非流式的平均延迟
表现:流式反而比非流式更慢,第一个字要等很久。
成因:网关可能在做请求缓冲(先收完上游响应再转发),或者在做前置的鉴权 / 计费 / 路由查询且这些查询很慢。
定位方法:
- 分别测流式与非流式的首字时间;
- 流式首字 ≈ 非流式总耗时 → 基本可以确定它在缓冲,说明「流式」只是接口形态,没有真正流式转发。
结论:这属于功能性缺失。对交互式场景(编程补全、对话)影响很大。可以用本站监测页的延迟数据配合判断,但注意本站测的是首页可达性,不等于生成首字延迟。
异常五:中途静默中断
表现:输出到一半停止,没有报错,连接关闭。
成因:常见三种:
- 上游超时(网关的连接超时设置比上游的生成时间短);
- 网关有单请求时长上限,到点断开;
- 长输出触发了网关的缓冲区限制。
定位方法:
- 用「要求输出 3000 字以上」的长任务测试;
- 记录断开时已经输出了多久 —— 如果是固定时长(如恰好 60s),基本可以确定是网关的超时配置;
- 检查你的客户端自己的读超时(很多 HTTP 客户端默认 30s)。
结论:先排除自己的客户端超时,再看是不是网关的时长上限。长输出场景(生成报告、批量代码)对这项敏感。
异常六:声明支持流式,实际返回非流式格式
表现:请求里带了 "stream": true,返回的却是一个完整的 JSON 对象。
成因:网关忽略了这个参数,或者它只是把它透传给了一个不支持流式的上游。
定位方法:看响应的 Content-Type —— 流式应为 text/event-stream,非流式是 application/json。再配合超时行为判断。
结论:属于参数静默丢弃,是最需要警惕的一类 —— 它不报错,只让表现变差,容易长期不被发现。
一份 5 分钟的流式体检
按顺序做,一次覆盖上面六类:
# 1) 抓原始流,看格式与结束标记
curl -N -s https://<base_url>/v1/chat/completions \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"model":"<model>","stream":true,
"messages":[{"role":"user",
"content":"输出一段包含中文、emoji 😀 和一段 python 代码的示例,不少于 800 字"}]}'
看四件事:
- 每个 chunk 是否是合法的
data: {...}; - 是否以
data: [DONE]结束; - 中文与 emoji 是否完整;
- 输出长度与连续性(有无重复或跳跃)。
再和非流式跑一遍同一个 prompt,比最终文本是否一致。
小结
流式的六类异常里,只有一类(异常四的部分情况)可能与上游有关,其余基本都是网关实现问题。所以:如果一家站的流式表现有问题,直接判定它的实现水平不足,不必再花时间找原因。
反过来说,流式表现良好是一个相当强的正面信号 —— 它说明这家站至少认真测试过自己的协议转换层。
这篇文章对你有帮助吗?如果你在实际使用中发现了文中没提到的情况,欢迎 提交纠错或补充,我们会核验后更新到正文里。
相关文章
顺着看下去:本站收录的部分中转站
本文没有指向特定模型系列,下面是本站收录站点中综合评分靠前的几家,供你顺着看下去。排序依据是评分与可用率,不构成推荐。