SSE 流式返回不稳定问题彻底解决
在私有化大模型项目里,想要实现类似 ChatGPT 逐字输出的流式效果,绝大多数人都会选择 SSE 方案。前后端框架集成看起来简单,但真正部署到公网环境后,各类隐性问题会陆续暴露:前端经常莫名断连、模型生成到一半数据流中断、部分网络环境下完全收不到推送内容。过去一段时间,我在三个不同的项目中都碰到同类反馈,最开始误以为是代码逻辑缺陷,反复调试后端逻辑,耗费大量时间后才发现,大部分故障根源集中在反向代理与长连接保活机制上。
最开始调试的时候,我仅仅完成基础接口封装,测试在内网环境一切正常,本地浏览器访问能够稳定接收流式消息。一旦部署到带有 Nginx 反向代理的生产环境,问题立刻显现。查阅资料时能搜到大量零散配置片段,但很多教程只粘贴配置,没有解释背后原理,照搬之后依旧无法根治断连问题。
第一个容易忽略的关键点是 Nginx 缓冲策略。默认情况下 Nginx 会缓存响应内容,积攒到一定大小才会转发给前端。SSE 依靠持续小块数据传输,缓冲开启之后,流式输出会被阻塞,直观感受就是长时间空白,等到生成结束一次性返回全部文本。不少人只关闭主体缓冲,遗漏相关附属参数,问题依旧存在。除了关闭 proxy_buffering,同时需要禁用缓存,并且妥善处理长连接头部,避免 Nginx 主动判定空闲连接并强制切断。
仅仅调整代理配置依旧不够。大模型推理存在不确定性,遇到长文本生成时,两次消息推送间隔可能达到数秒。在没有任何数据传输的间隙,部分网关、防火墙会判定通道闲置,主动断开 TCP 连接。单纯依靠业务数据流无法维持通道,我采用的解决方式是增加定时心跳包,持续向前端推送无意义占位消息,保持链路活跃。这里需要注意心跳频率不能过高,不然会产生大量无效网络包,3~5 秒一次是相对均衡的选择。
后端代码层面也要做好异常捕获。模型推理发生异常、内存波动触发报错时,如果没有异常捕获逻辑,服务会直接终止响应,前端不会收到正常关闭信号。前端代码缺少重连逻辑,就会卡死在页面。因此前端必须监听连接错误事件,断开之后进行延时重试;更进一步,可以记录已经接收的文本偏移量,重连后通知后端接续生成,不用从头重新请求,极大优化用户体验。
这套调整方案落地之后,我在宽带、移动网络、公司内网多种环境持续测试,基本解决随机断流问题。但也需要客观说明方案边界:SSE 基于 HTTP1.1,在极端复杂多层代理环境下依旧存在局限性,如果未来需要超高并发、双向持续通信,Websocket 会是备选。对于绝大多数中小企业私有化大模型 web 应用,优化后的 SSE 实现方案,足够平衡开发成本、兼容性与使用体验。