流式输出(Streaming)实战:让大模型「边想边说」
SSE 原理 · 体验优化 · 前端处理/中断 · 服务端注意点
核心结论:流式不改变「花多少钱」,但彻底改变「用户觉得多快」。把几百毫秒的沉默变成逐字呈现,是 AI 产品最值得做的一处体验优化。
一、原理:从「整段返回」到「逐字推送」
非流式: 提问 ──────等待──────► 整段文本
流式: 提问 ─►字├►字├►字├►…►完成(边生成边推)
底层通常用 SSE(Server-Sent Events),服务端保持连接,每产出一个片段就 data: ... 推一次,前端持续追加。
二、前端处理要点
- 用
fetch的ReadableStream或 SDK 流式接口读取分块; - 每收到一块就追加渲染,给用户「正在输出」的反馈;
- 用
AbortController支持用户中途停止; - 区分「出错」「正常结束」「被中断」三种终态。
三、服务端注意点
- 超时与心跳:长连接要防止被中间代理掐断,可加注释心跳;
- 并发:流式连接占用更久,需重新评估连接数与限流;
- 可观测:记录首字延迟(TTFT)与完整耗时,作为体验指标。
⚠ 权衡:若业务要求「必须返回合法 JSON 才能用」,纯流式会让组装变麻烦。可改为:非流式生成并校验,再通过流式展示,或流式结束后整体校验。
四、常见问题
流式输出是什么?
模型不是等全部生成完再一次性返回,而是每生成一个 token 就立刻推给前端,用户看到的是「逐字出现」的打字机效果。底层常用 SSE(Server-Sent Events)逐段推送。
为什么体验更好?
大模型首字往往要等几百毫秒到几秒,一次性返回会让用户以为卡死。流式把「等待」变成「渐进呈现」,显著降低感知延迟、提升留存。
前端怎么处理流?
用 fetch + ReadableStream 或 SDK 的流式接口,逐块读取并追加到界面。注意做好错误与完成态处理,以及用户主动中断(AbortController)。
流式会增加成本吗?
不会,计费按实际 token 数,与是否流式无关。代价是服务端连接时间更长,需要做好并发与超时管理。
什么时候不该用流式?
需要「先完整生成再校验格式」(如必须返回合法 JSON)的场景,流式反而增加组装复杂度,可先非流式生成再展示。
流式断流/乱码怎么排查?
检查代理是否缓冲了 SSE、字符编码是否一致、以及前端是否正确按块拼接解码。
移动端需要特殊处理吗?
逻辑一致,但要注意弱网下中断更频繁,做好自动重连与续传体验。