欢迎光临
我们一直在努力

2026-09-06-sse流式输出

AI 回答为什么一个字一个字蹦出来?流式输出 SSE 原理详解(附事件契约设计)

前言

用 AI 产品的都熟悉这个画面:提问之后,答案一个字一个字往外蹦,像有人在对面实时打字。

很多人以为这是前端做的"打字机动画"——先拿到完整答案,再一个字一个字显示。真这么做的话,用户盯着白屏等几十秒,看到的是假流畅。真正的流式输出,是后端生成一个词就推一个词,前端只是如实显示。

一、为什么必须流式:大模型是逐字生成的

底层事实:大模型生成文本,本质是"预测下一个词"——写完一个词,才基于前面的内容预测下一个。一篇 1000 字的回答,它真的是一个词一个词憋出来的,全程可能要几十秒。

如果等全部写完再返回,用户就要对着白屏干等几十秒。而流式输出把体验彻底改了:第一个词可能 1 秒就出来了,用户立刻开始读,读的速度跟不上生成的速度——等待感消失了。

总时间一点没省,省的是"感知等待"。这是用户体验设计最经典的一课:同等的总时长,反馈越及时,感觉越快。

二、SSE 是什么:一条不结束的 HTTP 响应

流式推送最常见的两个选型:WebSocket 和 SSE。我用了 SSE(Server-Sent Events,服务器单向推送)。

原理朴素得惊人:就是一条迟迟不结束的 HTTP 响应。浏览器发普通请求,服务器不一次性返回,而是保持连接,生成一段就往里写一段,写完再关。

大白话版:普通请求像去柜台取件,一次拿完走人;SSE 像订报纸,报社交完一份送一份,送到这期连载完。

三、推的不是文字,是事件

工程上最想强调的一点:流式推送的不能是一大坨纯文本,得是结构化的事件流。

AI 回答过程中发生的事不止"输出文字":它可能先在想、可能在调工具、然后才输出正文。我在平台里定义了一套事件契约:

start → thinking_block_delta(思考块,逐段)
→ tool_call_start / tool_call_end(工具调用,起止)
→ text_block_delta(正文块,逐段)
→ run_finished(收尾)

每类事件前端分开渲染:思考折叠成"正在思考…",工具调用显示成过程步骤,正文逐字上屏,出错单独提示。没有事件契约,前端只能把所有东西糊成一团文本。

工程细节:事件是增量的(这段多写了几个字),网络抖动可能丢包,所以服务端按块维护累计缓冲,每次推的是累计内容而不是碎片——前端拿到哪个渲染哪个,永远不缺字。

四、为什么不用 WebSocket

WebSocket 双向通道,聊天软件、多人游戏用它天经地义。但 AI 回答场景:信息流向是单向的——问题走普通请求发上去,回答只需要服务器往浏览器单向推。

SSE 拿住了这个特点:普通 HTTP,不需要协议升级,代理、网关、负载均衡天然友好;浏览器断线自动重连。WebSocket 要协议升级、自己管心跳重连、过某些代理还容易出问题。

选型口诀:单向推送用 SSE,真双向才上 WebSocket。 为用不上的"双向能力"多付复杂度,不值。

五、断了怎么办:回放兜底

长连接总会断:网络抖动、手机切后台、页面刷新。SSE 自带自动重连,但"断线期间生成的内容"怎么办?

我的做法是回放:每场回答的完整事件流都落了库。前端重连后按执行记录把已发生的过程拉回来,从断点接着显示。连接是易断的,记录是永久的。 用户刷新页面、换设备打开,整场回答的过程还能原样重现。

六、三个常见误区

  • “打字机效果是前端动画。” 假流式先等全文再逐字演,首字延迟一点没省。
  • “实时就得用 WebSocket。” 单向场景 SSE 更轻更稳,普通 HTTP 就够。
  • “流式输出没法留痕。” 事件流全程落库,断线回放、跨端重现都靠它。
  • 总结

    口诀带走:大模型逐字生成本来就该流式推;推的是结构化事件不是纯文本;单向推送用 SSE;断了靠落库回放兜底。

    你被"假流式"骗过吗?评论区聊聊。下一篇:提示词怎么写才不玄学——结构化提示词的四个槽位。

    赞(0)
    未经允许不得转载:171主机测评 » 2026-09-06-sse流式输出
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址