在构建 AI 应用时,前后端的通信机制是核心。Vercel AI SDK 提供了强大的流式传输能力,但你是否真正了解底层发生了什么?
本文将带你深入解读 Stream Protocol,重点介绍 Vercel AI SDK 默认使用的 Data Stream Protocol。理解这些协议不仅能帮你更好地调试应用,还能让你在非 Next.js 环境(如 Python/Go 后端)中实现兼容的接口。
什么是 Stream Protocol?
Vercel AI SDK 的 UI 组件(如 useChat 和 useCompletion)支持两种主要的流式协议:
- Text Stream Protocol(文本流协议) :最简单的形式,仅传输纯文本块。
- Data Stream Protocol(数据流协议) :SDK 的默认且功能最强大的协议。它基于 Server-Sent Events (SSE) 标准,能够传输文本、工具调用(Tool Calls)、推理步骤(Reasoning)、元数据以及自定义数据。
1. Text Stream Protocol (文本流协议)
这是最基础的模式,适用于只需要生成简单文本的场景。
- 格式:纯文本块(Plain Text Chunks)。
- 拼接:前端收到每个块后直接拼接到之前的文本后面。
- 限制:不支持工具调用、不支持复杂的元数据。
后端代码示例 (Next.js App Router):
TypeScript
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai('gpt-4o'),
messages,
});
// 注意这里调用的是 toTextStreamResponse()
return result.toTextStreamResponse();
}
2. Data Stream Protocol (数据流协议) - 核心重点
这是我们今天的主角。当你使用 useChat 时,默认就是走的这个协议。它使用 SSE (Server-Sent Events) 格式,每一行数据都以 data: 开头,后跟一个 JSON 对象。
为什么选择 Data Stream?
- 标准化:基于 SSE,自带自动重连和缓存处理机制。
- 多功能:可以在同一个流中混合发送文本、工具调用结果、错误信息和自定义数据。
- 结构化:每一帧都有明确的类型 (
type)。
协议帧详解 (Protocol Parts)
一个典型的数据流由以下几种帧组成:
A. 消息开始与元数据
表示一条新消息的开始。
JSON
data: {"type":"start", "messageId":"msg_123"}
B. 文本生成 (Text Parts)
文本不再是简单的字符串,而是分为“开始”、“增量”和“结束”,并且带有 id,这使得前端可以精确控制文本块。
- 开始:
data: {"type":"text-start", "id":"text_1"} - 增量:
data: {"type":"text-delta", "id":"text_1", "delta":"你好"} - 结束:
data: {"type":"text-end", "id":"text_1"}
C. 推理/思考过程 (Reasoning Parts) 🌟
对于像 o1/r1 这样具有思维链的模型,SDK 支持流式传输推理过程。
- 开始:
data: {"type":"reasoning-start", "id":"reason_1"} - 增量:
data: {"type":"reasoning-delta", "id":"reason_1", "delta":"正在分析用户意图..."} - 结束:
data: {"type":"reasoning-end", "id":"reason_1"}
D. 工具调用 (Tool Parts)
这是 Data Stream 最强大的地方。它将工具的调用过程拆解得非常细致:
- 输入流开始:
data: {"type":"tool-input-start", "toolCallId":"call_01", "toolName":"getWeather"} - 输入参数增量:
data: {"type":"tool-input-delta", "toolCallId":"call_01", "inputTextDelta":"{"city": "Bei"} - 输入参数完成:
data: {"type":"tool-input-available", "toolCallId":"call_01", "toolName":"getWeather", "input":{"city":"Beijing"}} - 工具执行结果:
data: {"type":"tool-output-available", "toolCallId":"call_01", "output":{"temp": 25}}
E. 流程控制 (Step & Finish)
当你在后端进行多次 LLM 交互(例如多步工具调用)时,这些帧非常重要。
- 步骤开始:
data: {"type":"start-step"} - 步骤结束:
data: {"type":"finish-step"}(表示一次 LLM 调用或工具执行的结束) - 消息结束:
data: {"type":"finish"} - 流结束标志:
data: [DONE](SSE 标准结束符)
3. 实战代码示例
后端实现 (Next.js)
在后端,使用 streamText 并调用 toDataStreamResponse() (v6 版本默认行为,或显式调用 toUIMessageStreamResponse 如果需要转换格式)。
TypeScript
// app/api/chat/route.ts
import { streamText, convertToCoreMessages } from 'ai';
import { z } from 'zod';
import { openai } from '@ai-sdk/openai';
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai('gpt-4-turbo'),
messages: convertToCoreMessages(messages),
tools: {
getWeather: {
description: '获取天气信息',
parameters: z.object({ city: z.string() }),
execute: async ({ city }) => ({ temperature: 22, condition: 'Sunny' }),
},
},
});
// 返回 Data Stream 响应
return result.toDataStreamResponse();
}
前端实现 (React/Next.js)
在前端,useChat 会自动解析上述复杂的 JSON 帧,你只需要关注 UI 渲染。
TypeScript
// app/page.tsx
'use client';
import { useChat } from '@ai-sdk/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat();
return (
<div className="flex flex-col p-4">
{messages.map(m => (
<div key={m.id} className="mb-4">
<div className="font-bold">{m.role === 'user' ? 'User' : 'AI'}</div>
{/* 渲染消息内容 */}
{m.parts ? (
/* v6+ 版本支持 parts 数组渲染,处理多模态和工具调用 UI */
m.parts.map((part, i) => {
if (part.type === 'text') return <span key={i}>{part.text}</span>;
if (part.type === 'tool-invocation') return <pre key={i}>调用工具: {part.toolInvocation.toolName}</pre>;
return null;
})
) : (
<div>{m.content}</div>
)}
</div>
))}
<form onSubmit={handleSubmit}>
<input
className="border p-2 w-full mt-4"
value={input}
onChange={handleInputChange}
placeholder="问问天气..."
/>
</form>
</div>
);
}
总结
理解 Vercel AI SDK 的 Data Stream Protocol 对开发复杂的 AI Agent 至关重要。它通过 SSE 传输结构化的 JSON 数据,完美解决了流式文本、工具调用状态和推理过程的同步问题。
如果你正在尝试用 Python (FastAPI) 或 Go 编写后端来对接 Vercel 的前端 SDK,请务必严格遵守上述 data: {"type": "..."} 的 SSE 格式!
希望这篇教程对你有帮助!记得点赞收藏哦!