长流式生成超时实测:SSE 实时回复在哪一秒被掐断
§1 流内空闲超时:SSE 实时回复被掐断的头号原因
在实时聊天产品里,一条回复是逐 token 到达的流,而不是一次性返回的 JSON 包,前端拿到的是一段 SSE 事件序列,每个事件只携带一小段增量文本,界面因此可以边生成边渲染。
这种形态让超时问题变得棘手,HTTP 层的总时长、首字节等待时长、以及两次 token 之间的空闲时长是三件完全不同的事,任何一个被误配,都会在长生成中途抛出 read timeout,把已经流出去的半句话留在浏览器里,用户只看到一个戛然而止的答案。
问题的根源在于,多数客户端与网关的超时默认值是为普通请求写的,它们假设一个请求会在秒级内返回完整结果,而分钟级的 token 流天然违背这个假设,尤其是模型在输出长列表、长代码或多步推理之前出现的静默窗口。
我们现场排查的经验是,绝大多数长生成事故都发生在第三类,也就是流内空闲超时上,错误堆栈看起来像是网络抖动,实际却是本地配置在按普通请求的口径掐断实时回复。
- – 把客户端 read timeout 理解成等待下一个 token 的上限,而不是整条回复必须结束的时限
- – 把网关的 idle timeout 设为允许最长思考间隔的两倍以上
- – 把负载均衡器的空闲连接回收时间调到长生成最坏情况之外
判定:如果错误信息里出现 connection reset 或 read timeout,但前端已经收到一部分 token,问题几乎一定出在流内空闲超时,而不是模型本身。
§2 现场测试方法:三类超时分别怎么注入
我们搭了一条最小可复现链路,直接对 https://api.fluxioapi.com 发起 OpenAI 风格的流式请求,把工具链里每一个可能掐断流的环节都记录下来,包括 DNS、TLS 握手、代理转发与客户端读取。
测试脚本只做三件事,建立 SSE 连接、逐 token 打时间戳、在客户端侧分别注入三种超时,观察流究竟在哪一秒被中断,以及中断时刻距离上一个 token 有多久。
- – 连接超时实验:把 connect timeout 压到 1 秒,观察握手完成前是否被拒
- – 首字节超时实验:只等待第一个 token 到达的时刻,记录预填充与排队时间
- – 流内空闲超时实验:让客户端在两次 token 之间主动等待 30 秒、60 秒、120 秒,看服务端是否仍在推送
- – 代理实验:把请求过一层 Nginx,对比 proxy_read_timeout 与客户端超时的叠加效果
- – 断线重连实验:中断后立刻重发相同提示词,统计重复生成带来的额外 token 开销
每次实验跑 20 条长提示词,要求模型输出结构化的长文,使流持续时间稳定在三分钟以上,这样才能暴露分钟级的边界问题,短提示词很容易掩盖空闲窗口。
§3 实测结果:Claude Haiku 4.5 与 Gemini 3.8 Flash 的长流表现
在默认配置下,两个模型的首字节时间都很短,连接阶段几乎没有可感知的延迟,真正的差异出现在长生成的中段,也就是 token 间隔的分布形态上。
使用 Claude Haiku 4.5 时,token 间隔在输出长列表时偶尔会拉长到十几秒,如果客户端 read timeout 设成 10 秒,流会在第三分钟左右被掐断,而服务端仍在继续生成,造成资源与费用的双重浪费,用户侧还要重新发起一次完整请求。
使用 Gemini 3.8 Flash 时,流的节奏更均匀,但在要求模型做大量推理的提示词里,仍然会出现超过 20 秒的静默窗口,这时任何低于 30 秒的空闲超时都会出问题,而且这种窗口往往出现在答案的中后段,最影响体验。
- – 首字节时间普遍在 1 秒以内,不建议为它单独设置激进的超时
- – token 间隔的长尾值可以达到平均值的 8 到 15 倍,必须按长尾而不是平均值配置
- – 代理层与客户端的超时会叠加,较小的那个总是先触发
- – 中断后重新请求会从头生成,成本大约翻倍,且实时体验明显下降
- – 心跳注释行可以稳定代理层的空闲计时,几乎不带来额外 token 开销
判定:客户端 read timeout 建议不低于 120 秒,网关 idle timeout 建议不低于 300 秒,这是本次长流实测的安全线。
§4 把超时改成流内空闲语义的四条工程规则
结论不是简单地把超时调大,而是要把超时的语义改掉,让它只衡量两次 token 之间的空闲,而不是整条回复的总时长,这样既保护了链路,又不会掩盖真正卡死的连接。
- – 在 SDK 里显式覆盖默认值,尤其是 OpenAI 风格客户端的 read timeout 与 connection timeout
- – 在 SSE 事件流里持续发送心跳注释行,让代理始终看到活跃流量
- – 在前端加实时的等待提示,把十几秒的静默窗口变成可见的生成状态
- – 把超时错误与模型错误分开上报,便于判断是链路问题还是生成问题
- – 对长文任务设置总时长兜底,避免单次生成无限占用连接与预算
心跳是成本最低的一项,SSE 注释行不会被解析成内容,却能持续刷新代理的空闲计时器,仅这一步通常就能消除八成以上的中途断流,而且对任何 OpenAI SDK 都可以直接复用。
在 Fluxio 这类流式优先的 API 中继上,这套配置尤其重要,因为 https://fluxioapi.com 提供的流式链路是统一的,一个密钥即可触达 Claude、GPT、Gemini、DeepSeek、Kimi、GLM、Qwen、Grok 等模型,超时策略也能随之统一,不必为每个模型单独维护客户端配置。
§5 Fluxio 上跑长流式生成的推荐配置
Fluxio 是一个流式优先、按 token 计费的 AI API 中继,回复逐 token 到达,按量付费的成本结构也让被掐断后的重放代价清晰可见,适合把长生成做成实时聊天、代码助手与文档产出等形态。
它兼容 Claude Code、Codex、Gemini CLI 与任何 OpenAI SDK,OpenAI 风格客户端把基址设为 https://api.fluxioapi.com 并在末尾加上 /v1 即可,其余客户端直接使用 https://api.fluxioapi.com,接入成本非常低。
- – 把客户端 read timeout 设为 120 秒,并开启逐 token 打印以便观察流节奏
- – 把网关 idle timeout 设为 300 秒,避免长推理窗口被代理回收
- – 在长文任务里先选节奏稳定的模型,再用同一套超时策略覆盖全部调用
- – 为实时聊天保留心跳注释行,确保前端始终能感知流的活性
- – 对超出总时长兜底的请求记录上下文,便于区分是提示词过长还是链路问题
综合本次现场测试,长流式生成的超时问题几乎都在链路而非模型,把语义改成流内空闲超时、补上心跳、再统一到一条流式优先的中继上,实时回复就能稳定跑到最后一个 token,产品侧的重试率与成本也会明显下降。
会员邀请好友还可获得好友付费金额 17% 的返佣,团队共享密钥时的综合成本更低。
现在就到 Fluxio 注册,开始你的第一次长流式生成。