AI 流式响应
真实 SSE 流式端点:Route Handler 用 ReadableStream 逐 token 推送,前端 getReader() 边收边渲染;TTFT 才是用户感知的「快」,取消即省计费
真实 SSE 流式演练(可运行)
GET /api/ai/stream 返回 text/event-stream;前端 fetch + getReader() 逐 chunk 解码渲染,不再是客户端模拟
待开始
TTFT 首 token
—
总耗时
—
已收 token
0
点击「开始流式生成」,观察 token 逐个到达 —— 也可以半路点「取消」
打开 DevTools Network 面板看 /api/ai/stream:响应类型是 EventStream,chunk 随时间逐个到达,而不是一次性下载
为什么 AI 场景必须流式
决策要点,而非 API 背诵
- buffer 完再返回 = 白屏十秒级:LLM 完整响应以十秒计, 等全部生成完再一次返回,用户面对的是长时间白屏; 流式把等待切碎,TTFT(首 token 时间)才是用户感知的「快」
- SSE 与普通 JSON 的分工:一次性、结构化的请求-响应(表单、列表、工具决策) 用普通 JSON;持续生长、需要边到边渲染的产出(回答、步骤事件)用 SSE。 判断依据是「数据是否随时间持续产生」,不是「是不是 AI」
- SSE 与 fetch+ReadableStream 自定义协议的取舍:SSE 自带 EventSource(自动重连、事件类型),但只支持 GET、只能推文本事件; 本页的 fetch + getReader() 自定义协议更灵活(可 POST、任意二进制、自定义帧格式), 代价是半帧拼接、重连、错误恢复都要自己处理 —— 帧边界是协议层的责任,不是 fetch 的
- 取消 = 省钱:客户端 AbortController 断开后, 服务端 ReadableStream 的 cancel 回调触发 —— 真实场景必须同步停掉上游 LLM 调用, 每一个不再被阅读的 token 都是真金白银的推理成本
生产里不手写这个:Vercel AI SDK
手写版的价值是理解协议(帧边界、取消、背压);生产里用 SDK 拿到重试、协议演进与多 provider 适配
// Route Handler 侧(示意,ai@7;可运行版见 /ai-native/ai-sdk 专题):
import {
convertToModelMessages,
createUIMessageStreamResponse,
streamText,
toUIMessageStream,
type UIMessage,
} from "ai";
import { openai } from "@ai-sdk/openai";
export async function POST(req: Request) {
const { messages }: { messages: UIMessage[] } = await req.json();
const result = streamText({
model: openai("gpt-5"),
messages: await convertToModelMessages(messages),
});
// 帧格式、半帧拼接、取消传播、错误帧都由 SDK 的
// UI Message Stream 协议封装好
return createUIMessageStreamResponse({
stream: toUIMessageStream({ stream: result.stream }),
});
// 需要自定义事件时用 createUIMessageStream(见 Agent 长任务页专题)
}
// Client 侧(示意):useChat 接管传输与消息状态机,
// 替代本页 StreamPlayground 里的手写 getReader() 解码;
// 输入框是受控本地状态(@ai-sdk/react@4 起不再内置 input/handleSubmit)
const transport = new DefaultChatTransport({ api: "/api/chat" });
const { messages, sendMessage, status, stop } = useChat({ transport });手写仍合理的场景:教学(像本页这样把协议摊开看)、协议定制(要发的帧不是 AI SDK 的消息模型)、零依赖场景(不想为一个端点引入 SDK)。 其余情况,手写一套流式协议等于自己承担了它的全部边角案例。 本站已安装 ai@7 + @ai-sdk/react@4,上面对应的真实可运行实现见手写 SSE vs Vercel AI SDK专题(MockLanguageModelV3 + simulateReadableStream,无 API key 可跑)。
什么时候别用流式
流式也有成本:连接常驻、断线重连、部分产出的兜底处理
- 产出本身很快的场景:整体响应在几百毫秒内完成的接口, 流式只增加复杂度,普通 JSON 一次返回更简单可靠
- 需要完整校验才能展示的场景:JSON Schema 严格校验、 必须整体签名/对账的数据,边收边渲染会把「半个错误结果」先亮给用户
- SEO 内容:爬虫等不到流结束;被索引的正文仍应走 服务端渲染(见渲染策略专题的 Streaming SSR)