流式输出:让 AI 回答像打字机一样逐字蹦出来
ChatGPT 的答案是逐字蹦出来的,背后是 SSE 流式输出。本文讲清为什么不能一次返回、SSE 是什么、给出 Flask 生成器 + EventSource 最小可运行示例,以及前端增量拼接、代理缓冲等工程边界。

你用 ChatGPT 时,答案是一个字一个字蹦出来的,不是憋半天一次性弹出。这叫流式输出,背后大多是 SSE(Server-Sent Events)。它不改变答案本身,却极大改善了「等待感」——让用户知道「它在动」。
背景:为什么不能一次返回
LLM 是自回归逐 token 生成的,全部生成完再返回,用户要干等好几秒甚至更久,体验很差,还容易以为卡死了。流式把已生成的 token 立刻推给前端,边生成边显示。
SSE 是什么
SSE 是基于 HTTP 的单向推送:服务端用 text/event-stream 持续发送 data: ...\n\n 这样的数据块,浏览器用 EventSource 接收。相比 WebSocket,它更轻量,专做「服务器 → 客户端」的单向流,且天然走普通 HTTP、好穿代理。
一个最小可运行的例子
后端用生成器持续推送(Flask 风格):
from flask import Response
import time
def event_stream():
for token in generate_tokens(): # 逐 token 推送
yield f"data: {token}\n\n"
time.sleep(0.05)
@app.route("/chat")
def chat():
return Response(event_stream(), mimetype="text/event-stream")
前端用 EventSource 接收并拼接:
const es = new EventSource("/chat");
es.onmessage = (e) => {
output.textContent += e.data; // 逐字拼接到页面
};
取舍与边界
- 前端逻辑更复杂:要处理「增量拼接」与渲染,比一次性返回麻烦不少。
- 中途出错难处理:已经开始流了,报错只能中断或补一句,没法整体回滚。
- 代理/网关要支持分块:有些中间件会缓冲响应,把流式又攒成大块,要显式关闭缓冲。
- 不是所有场景都要流:内部批处理、离线评测可一次性返回,省事。
你能马上用起来的收获清单
- 任何面向用户的生成接口,默认上流式,体感提升立竿见影。
- 前端用
EventSource或fetch+ReadableStream消费分块。 - 检查你的反向代理(Nginx 等)是否缓冲了响应,必要时关掉。
- 给流式加「超时 / 中止」按钮,用户能随时打断。
- 批处理、评测类后台任务不必流式,保持简单。



