ai对话平台流式响应输出怎么实现?

流式响应输出

用户发送问题后,AI 回答非一次性全部输出,而是生成一段输出一段;后端调用大模型时需设置stream=true,模型服务边生成边推送数据块,后端持续读取并实时转发给前端,前端实时渲染。

  1. 实现技术

主流实现流式输出有 3 种方式:HTTP 分块传输编码、SSE、WebSocket。项目选用SSE实现流式输出,SSE 提供了一种简单的、实时的服务器推送数据给客户端的方法。SSE建立在HTTP协议之上,无需复杂协议升级,无专门服务器支持,实现与维护成本低;专为服务器向客户端单向数据流设计,适配 AI 平台回答输出场景;相比 WebSocket 开销更小,无需处理双向消息逻辑;连接意外中断时,内置自动重连机制,提供更稳定的体验。

  1. 实现方案

前端主流方案:fetch + ReadableStream,优势在于:首先他是完全可控的,可精细控制 POST 请求、headers 与数据处理,灵活性很高;然后他的与各大模型官方 API 的标准完全对齐;可分块接收数据,实现打字机效果。

原生EventSource 也可以实现:简单、自带重连、浏览器原生支持,但是存在局限,它仅支持 GET 方法不支持自定义 Request Headers (这是由 HTML5 规范定义的标准行为),因此无法直接携带 Token 进行鉴权,也不适合提交复杂的 POST 业务参数。并且readablestream提供了对字节级流的精细化控制,适合做文本增量解析。同时,底层网络传输和streams api返回的数据是原始的二进制(uint8array),必须解码成字符串之后才能进行后续处理,fetch readablestream 返回的是二进制块,这里就要用textdecoder将uint8array解码为js字符串,才能用jsonprase或者是data:前缀,流式输出的过程中,用textdecoder(utf-8,{stream:true})对字节流进行增量解码,保证跨chunk的字符能够被正确还原。所以项目流式输出的方案是更灵活的 Fetch API + ReadableStream +textdecoder。
核心流程: 用 fetch 发送 POST 请求到后端 API;ReadableStream 接收服务端返回的流式数据;分块读取和处理数据,解码拼接实现实时展示;渲染优化:使用buffer 缓冲配合 RAF request Animation Frame批量刷新,减少冗余 DOM 操作。这里为什么要进行一个渲染优化呢,如果每次收到数据块chunk直接操作DOM.innerHTML会引发频繁重排(reflow)和重绘(repaint),导致页面卡顿。
优化方案 :我这里是设置了一个缓冲区, 累积若干 chunk 或等待短时间(16ms),再更新 DOM;利用requestAnimationFrame 控制渲染频率(让他和浏览器60fps屏幕刷新频率一致),与浏览器渲染周期同步,避免掉帧,无内容时自动停止渲染,页面不可见时暂停执行。

  1. 流式中断处理与异常重试机制

在流式渲染中,网络波动或者后端异常,会导致readablestream/SSE中断,不处理的话,用户会看到对话突然停止,用户体验差。

流式中断处理通常分为四步:

捕获异常和超时,判断流是不是中断了;缓存已经接收的文本,记录最后渲染的位置;根据最大重试次数尝试重连或者续流;恢复之后按照原有分批渲染逻辑输出,同时保证滚动和用户感知。

  • 中断检测

判断异常是人为还是异常中断

异常捕获,在fetch、readerread时捕获异常

超时检测,使用心跳保活机制, 每 30 秒向服务器发送一次心跳请求,防止长连接超时;心跳请求设置 5 秒超时,不阻塞主流程。服务端每隔几秒向流连接发送空数据,在ReadableStream中加入心跳逻辑,每 5s 推送一个空心跳 chunk,前端过滤心跳 chunk,有数据即代表连接活跃,避免长时间静默断开。

  • 缓存已经接收的数据-断点续传

通过receiveChunks数组存储已接收消息片段;前端重试时,保证同一点的重试请求服务端只处理一次,避免重复生成内容(幂等性保证)。

  • 重连、恢复机制

实现了带重试的fetch请求,支持网络错误和特定的http状态码429、500、502、504。

429:用户发送请求太多、被限流(并发请求太多、被服务商暂时拒绝,单位时间调用次数超了);500:AI 服务器内部出错(临时服务故障、AI 服务 / 网关负载过高挂掉、后端服务重启中);502:网管坏了、代理服务器挂了(ai服务商网管或负载均衡挂了、后端服务重启中、网络链路抖动);503:服务暂不可用(ai模型正在扩容、重启、维护,服务其过载);504:网关超时(AI 服务未返回、服务负载高、处理慢、网络链路延迟大)。遇到以上几个状态码时会自动重试,重试的过程是采用指数退避策略:每次重试延迟时间指数增长,添加随机抖动因子(0.8-1.2)避免多个请求同时重试,达最大重试次数后向用户返回错误。

相关推荐
一个public的class2 小时前
前后端 + Nginx + Gateway + K8s 全链路架构图解
前端·后端·nginx·kubernetes·gateway
张忠琳2 小时前
【openclaw】OpenClaw Tasks 模块超深度架构分析
ai·架构·openclaw
胡志辉的博客2 小时前
网络七层到底怎么落到一次前端请求上:从浏览器到网卡,再到远端服务器
服务器·前端·网络
小比特_蓝光2 小时前
从环境变量到进程地址空间:Linux系统学习笔记
前端·chrome
亿元程序员2 小时前
海外这个新游好玩?手把手带你实战一个!
前端
FIT2CLOUD飞致云2 小时前
学习笔记丨基于MaxKB实现JumpServer堡垒机自动化巡检
人工智能·ai·开源·智能体·maxkb
Roselind_Yi2 小时前
云计算实验实操|Hadoop伪分布式部署+MapReduce编程实践(超详细图文版)
大数据·hadoop·经验分享·笔记·分布式·数据挖掘·云计算
M ? A2 小时前
Vue slot 插槽转 React:VuReact 怎么处理?
前端·javascript·vue.js·经验分享·react.js·面试·vureact
a1117762 小时前
演唱会3D选座网页(HTML 开源)
前端·3d·html