说明:本次输入未提供 DeepSeek 官方文档正文或官方新闻稿,因此下文不涉及该接口的具体路径、参数名、默认超时数值等官方细节。凡涉及此类内容,均需以官方文档为准。以下为通用的流式接入工程分析。
一、中断往往发生在中间层
流式输出通常走 SSE(Server-Sent Events),即一个长生命周期的 HTTP 响应,服务端持续写入数据块。问题在于链路上的反向代理、负载均衡、API 网关、CDN 普遍配置了空闲超时:当模型出现较长的首 token 延迟或输出中途停顿,连接上没有任何字节流动,中间层会判定连接空闲并主动关闭。客户端看到的现象是收到部分内容后连接结束,或长时间无数据直至超时。
需要先区分两类故障。其一是空闲超时导致的被动断链,特征是固定时长后断开。其二是代理缓冲(buffering)导致数据被积压不转发,客户端看起来“没有数据”,但连接本身还在。两者的排查方向完全不同。
二、服务端转发层:心跳与关闭缓冲
如果在自己的后端转发 SSE,最直接的手段是周期性发送注释行,即以冒号开头的行,例如“: keepalive”。按 SSE 规范注释行会被客户端忽略,但能让链路上每一跳都观察到字节流量,从而重置空闲计时。心跳间隔应小于链路中最短的那一跳空闲超时。
同时要注意几点:转发时必须禁用中间层缓冲,设置正确的响应头(Content-Type 为 text/event-stream、Cache-Control 为 no-cache、Connection 为 keep-alive),并在每次写入后及时 flush,避免应用框架把数据攒在缓冲区里。
三、Nginx 侧的两个关键项
proxy_read_timeout 定义的是两次读操作之间的最大间隔,而不是整个请求的总时长,默认值通常偏短,流式场景需要按实际停顿预期调大,或与心跳配合使用。proxy_buffering 需要关闭,否则响应可能被缓冲后集中下发,破坏流式体验;proxy_cache 同理应关闭。此外可用上游返回的 X-Accel-Buffering: no 由服务端响应头控制缓冲行为,避免只依赖网关配置。
四、Node.js 与 Python 客户端的读超时
Node.js 原生 http 模块的 socket 空闲处理、以及基于 undici 的 fetch,都有各自的超时维度。流式场景的常见坑在于“两个数据块之间的超时”这一项:它会被误认为整体超时而不被注意,但恰恰是它在中途停顿时触发。具体参数名与默认行为需按 Node.js 及 undici 的具体版本文档确认。
Python 的 requests 使用 timeout=(connect, read) 元组,其中 read 同样是两次读之间的间隔;httpx 的 read timeout 语义类似。如需禁用读超时,应使用对应客户端支持的 None 配置;不要将读超时设为 0,并应以具体客户端版本文档为准。禁用读超时会丧失对对端故障的检测能力,应配合应用层心跳判断。
五、重连与降级逻辑
检测到中断后,通常采用指数退避重连并限制最大重试次数,同时向调用方透出降级结果。断点续传依赖服务端支持,例如 SSE 的 Last-Event-ID 机制;若服务端没有按事件 ID 保存生成状态,客户端无法从中断处继续,只能整段重发,此时需要评估重复计费与幂等问题。工程上较常见的折中是:把已接收的分片落盘或落库,重连后发起新请求继续生成,由应用层拼接结果。
六、验证方法
可用 curl -N 分别直连上游与经代理访问,对比两者行为差异;抓包确认心跳是否按预期发出;把链路各跳的空闲超时值列成表,取其中最小值以下作为心跳间隔。若断开时间点稳定,基本可判定为空闲超时;若数据延迟到达但连接未断,则应优先排查缓冲配置。