Fluxio
← Volver al blog

WebSockets 与 SSE:逐步搭建 AI 聊天流式响应

Corrientes de modelosZH

§1 第一步:按 AI 聊天的消息方向选择协议

先画出一次对话:用户提交问题,后端调用模型,页面持续追加答案。不要仅因产品标注“实时”,就直接选择 WebSockets。建议先用 SSE 实现文字聊天,再根据双向交互需求决定是否升级。

SSE 提供服务器到浏览器的单向事件流,WebSocket 则允许连接两端发送和接收数据。判断重点不是能否逐词显示,而是生成过程中,客户端是否也需要持续上传数据。([developer.mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events))

  • – 对于提交一次问题、持续接收答案的文字聊天,优先评估 SSE。
  • – 对于持续上传音频、同时接收响应的交互,优先评估 WebSockets。
  • – 对于偶尔发送停止指令的产品,先评估独立请求,不必立即更换整个传输方案。

§2 第二步:拆开模型上游与浏览器下游

建议采用浏览器、业务后端、模型接口三层结构,把密钥留在后端。分别设计模型到后端、后端到浏览器两段连接,不要把上游接口的传输方式直接当作前端协议要求。

如果需要统一接入多个模型,可以考虑 Fluxio。根据提供的产品信息,它是流式优先、按词元付费的 AI API 中转服务,通过一个密钥连接多个模型,并逐词元返回答案。本文建议把它放在后端上游,浏览器仍连接自己的业务接口。

先选一个模型完成链路验证,再扩展模型切换。建议后端统一输出请求编号、文本增量、完成状态和错误信息,让界面逻辑不依赖具体模型的返回结构。

§3 第三步:用流式请求接收 SSE 文本

原生 EventSource 适合订阅事件,但不能直接提交 POST 请求。需要发送对话正文时,可以使用 fetch 提交请求,再增量读取响应体。注意,fetch 是请求接口,SSE 是事件格式,两者不是互斥选项。([web.dev](https://web.dev/articles/eventsource-basics?hl=en&utm_source=openai))

让后端返回 text/event-stream,并以空行分隔事件。客户端应先增量解码文本,再按事件边界解析;不要把一次网络读取当成一条完整消息。SSE 使用 UTF-8 编码,也允许一个事件包含多行数据。([developer.mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events))

  • – 检查响应状态,再进入流式读取循环,避免把鉴权失败当作正常答案。
  • – 保留未完成的事件片段,等待后续数据到达后继续解析。
  • – 把文本追加、业务错误和正常完成设计成不同处理分支。

§4 第四步:用 WebSocket 承载持续双向交互

如果决定采用 WebSocket,建议先定义应用层消息格式,再编写连接代码。为开始生成、文本增量、取消任务和任务完成分别设置消息类型,并携带请求编号,避免多个回答串到同一个聊天气泡。

不要假设持续连接会自动解决消费速度问题。浏览器传统 WebSocket 接口没有自动背压机制,消息到达速度超过处理速度时,可能造成内存堆积或页面失去响应。([developer.mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket))

因此,建议限制待处理队列,合并短时间内的文本更新,并为慢客户端设置明确的处理策略。先把这些规则写进协议约定,再考虑同一连接复用多个会话。

§5 第五步:实现取消生成与断线恢复

使用 fetch 时,可以通过 AbortController 取消请求。不过,前端中止读取不应被当作上游推理已经停止的证明;实现时应让后端感知断开,并向上游传递取消信号。([developer.mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch))

原生 EventSource 支持自动重连,事件编号可通过 Last-Event-ID 帮助服务器识别恢复位置。但恢复连接不等于恢复答案,服务端仍需实现事件保留与补发。([html.spec.whatwg.org](https://html.spec.whatwg.org/dev/server-sent-events.html?utm_source=openai))

建议为每次生成分配独立编号,并明确选择“重放已有事件”还是“重新生成”。使用 fetch 读取事件流时,应自行设计重试策略;不要在断线后无条件重发问题,避免把重复生成混入原答案。

§6 第六步:用同一套聊天测试验证选型

最后,用相同输入分别验证两种方案,不要仅比较连接建立速度。建议记录首段文本出现时间、完整回答耗时、取消反馈时间,以及慢客户端下的内存变化。

  • – 测试弱网断开后,页面是否明确提示中断并避免重复追加。
  • – 测试用户连续提问时,旧请求是否被取消或正确隔离。
  • – 测试部署链路是否及时转发增量,而不是等答案结束才集中显示。

建议先把 SSE 文字聊天链路做好,再为确实需要持续双向通信的功能引入 WebSockets。选用 Fluxio 作为模型上游时,也应保留自己的鉴权、取消与恢复逻辑,让模型接入和实时交互各自承担清晰职责。

欢迎注册 Fluxio。

Crear una cuenta de Fluxio →

Más artículos de Corrientes