导航
Vercel AI SDK 是一个专为开发者设计的 TypeScript 工具包,旨在简化 AI 功能(尤其是大语言模型 LLM)与前端应用的集成。它通过统一的 API 和模块化设计,帮助开发者快速构建流式对话、内容生成等 AI 驱动的前端应用。
在 web 架构与 AI 合作层面,提供统一的 API 抽象,简化了模型接入和 UI 集成的成本,也让构建复杂 AI 应用变得更加可维护和可控。同时,其事件模型与 AG-UI 协议高度契合,在 2.0 底座中,可通过编写适配器,实现运行态聊天模式下前后端的数据传输。
ReadableStream<UIMessageChunk> 格式返回。支持 HTTP/SSE、WebSocket 等不同通信方式,提供极高灵活性。
WebSocket 的双向通信效率,也可通过自定义 ChatTransport 适配 WebSocket,将其消息转成 SSE 风格的 UIMessageChunk 流提升兼容性。parts 组成(文本、思考、工具调用、文件、数据分片等)。文件:packages/ai/src/ui/ui-messages.tstext-start/text-delta/text-end、tool-*、data-* 等。前端通过该流块更新当前正在构建的 UIMessage。文件:packages/ai/src/ui-message-stream/ui-message-chunks.tsReadableStream<UIMessageChunk>。允许自定义 HTTP/SSE、WebSocket 或其他协议。文件:packages/ai/src/ui/chat-transport.tsparseJsonEventStream 把 SSE 解析为 UIMessageChunk 流。文件:packages/ai/src/ui/http-chat-transport.ts, packages/ai/src/ui/default-chat-transport.tsChatTransport 与 ChatState。文件:packages/ai/src/ui/chat.tsmessages/status/error 与 push/replace 等方法;不同框架提供不同实现(Vue/React/Svelte)。文件:packages/ai/src/ui/chat.tsUIMessageChunk 流转为 UIMessage 的增量更新过程(维护 active parts、解析工具入参增量 JSON、验证数据分片等)。文件:packages/ai/src/ui/process-ui-message-stream.ts核心定义:
export interface UIMessage<
METADATA = unknown,
DATA_PARTS extends UIDataTypes = UIDataTypes,
TOOLS extends UITools = UITools,
> {
id: string;
role: 'system' | 'user' | 'assistant';
metadata?: METADATA;
parts: Array<UIMessagePart<DATA_PARTS, TOOLS>>;
}
常见的 Part 类型:
text(可流式,state: streaming/done)reasoning(可流式)tool-<name>(工具调用,分 Input/Output/Error 阶段)file、source-url、source-documentdata-<NAME>(自定义数据分片;前后端约定 type 前缀为 data-,可定义 schema 验证)step-start(步骤边界)工具调用(ToolUIPart)具备严格的状态机:
export type ToolUIPart<TOOLS extends UITools = UITools> = ValueOf<{
[NAME in keyof TOOLS & string]: {
type: `tool-${NAME}`;
toolCallId: string;
} & (
| { state: 'input-streaming'; input: DeepPartial<TOOLS[NAME]['input']> | undefined; }
| { state: 'input-available'; input: TOOLS[NAME]['input']; callProviderMetadata?: ProviderMetadata; }
| { state: 'output-available'; input: TOOLS[NAME]['input']; output: TOOLS[NAME]['output']; }
| { state: 'output-error'; input: TOOLS[NAME]['input']; errorText: string; }
);
}>;
后端经由 SSE(或自定义协议)向前端持续推送 UIMessageChunk。前端将其解析并映射到 UIMessage:
export type UIMessageChunk =
| { type: 'text-start' | 'text-delta' | 'text-end'; id: string; ... }
| { type: 'reasoning-start' | 'reasoning-delta' | 'reasoning-end'; id: string; ... }
| { type: 'tool-input-start' | 'tool-input-delta' | 'tool-input-available'; ... }
| { type: 'tool-output-available' | 'tool-output-error'; ... }
| { type: 'file' | 'source-url' | 'source-document'; ... }
| DataUIMessageChunk
| { type: 'start-step' | 'finish-step' }
| { type: 'start' | 'finish' | 'abort' | 'message-metadata'; ... };
说明:
text-start 开始、text-delta 持续增量、text-end 结束;每个 id 代表一个活跃文本 part。reasoning-* 与文本一致,独立的活跃缓冲。tool-input-start(含 toolName、toolCallId),随后 tool-input-delta(入参增量 JSON 片段,前端合并/解析),当入参就绪发 tool-input-available;工具执行完成/错误分别发 tool-output-available/tool-output-error。data-<NAME> 可携带结构化 data(可选 id 支持覆盖/更新),支持 transient(仅事件回调,不入 messages)。start-step/finish-step 用于阶段切换,start/finish 用于消息级开始/结束、元数据更新。职责:
StreamingUIMessageState:包含当前响应消息实体、活跃文本/思考 part 映射、工具调用增量缓冲。chunk.type 执行“就地更新”:累积文本/思考 delta、累积/解析工具入参 JSON 片段、落盘工具输出、插入/覆盖 data- 分片等。onToolCall(入参就绪)、onData(每个 data- 分片),支持自定义 schema 验证。关键实现:
export function processUIMessageStream<UI_MESSAGE extends UIMessage>({ stream, ...callbacks }): ReadableStream<InferUIMessageChunk<UI_MESSAGE>> {
return stream.pipeThrough(new TransformStream({
async transform(chunk, controller) {
await runUpdateMessageJob(async ({ state, write }) => {
// 维护 activeTextParts / activeReasoningParts
// 解析 tool-input-delta 为部分 JSON 并合并
// 根据 toolCallId 定位/更新 tool part
// 处理 data-* 分片(可 transient)
// 更新 message.metadata / 写入触发渲染
});
controller.enqueue(chunk as InferUIMessageChunk<UI_MESSAGE>);
}
}));
}
注意点:
tool-input-delta 使用 parsePartialJson 合并半成品 JSON;到 tool-input-available 才认为入参完整,可触发 onToolCall。data-* 若带 id,则以 type+id 作为键进行覆盖更新;若 transient: true,则不入 messages 仅走 onData。AbstractChat 负责:
ChatState(messages/status/error)ChatTransport.sendMessages/reconnectToStreamprocessUIMessageStream,序列化 UI 更新(SerialJobExecutor)stop() 中止当前流,addToolResult() 注入本地工具执行结果onError、onToolCall、onData、onFinish核心流程(发送):
sendMessage -> 规范化 user message -> makeRequest()
makeRequest():
1) 设置状态 submitted
2) 创建 activeResponse(state + AbortController)
3) transport.sendMessages() 取回 ReadableStream<UIMessageChunk>
4) consumeStream(processUIMessageStream(...)) 序列化应用增量
5) onFinish + 状态 ready;异常转 error
状态含义:
submitted:请求已发出等待首个流块streaming:持续接收增量并更新 UIready:完成一轮生成,可再次发送error:错误状态(可 clearError 恢复)接口:
export interface ChatTransport<UI_MESSAGE extends UIMessage> {
sendMessages(options): Promise<ReadableStream<UIMessageChunk>>;
reconnectToStream(options): Promise<ReadableStream<UIMessageChunk> | null>;
}
默认 HTTP/SSE 实现:
return parseJsonEventStream({ stream, schema: uiMessageChunkSchema })
.pipeThrough(new TransformStream({ transform(chunk, c) { c.enqueue(chunk.value) } }))
HttpChatTransport 负责组装请求、并留有 prepareSendMessagesRequest/prepareReconnectToStreamRequest 钩子自定义 body/headers/credentials 等。DefaultChatTransport 只关心如何把 HTTP body 转成 UIMessageChunk 流(SSE->JSON 行->Zod 校验)。ChatTransport,将 WS 消息转为 UIMessageChunk 并返回 ReadableStream<UIMessageChunk> 即可。