Skip to content
Vercel AI SDK 架构分析:AI 应用开发抽象层设计
概述
Vercel AI SDK 是一个 provider-agnostic 的 TypeScript 开源工具包,用于构建 AI 应用和 Agent。它支持 Next.js、React、Svelte、Vue、Angular 等 UI 框架,也支持 Node.js 运行时。
安装核心包:
bash
npm install ai当前 SDK 文档要求 Node.js 22 及以上版本。
基本概念
模型接入的多样性与抽象层目标
不同模型提供方提供的 API 形态各不相同。即使都叫 chat completion,它们也会在以下方面产生差异:
- 接口路径、认证方式和请求头不同
- 消息结构不同,例如 system 消息的表示方式不同
- 流式输出的 chunk 格式不同
- 工具调用的声明格式和返回格式不同
- 嵌入模型的输入输出格式不同
如果应用直接调用某个 Provider 的 SDK,那么每接入一个模型提供方,都要重新实现一层调用逻辑。Vercel AI SDK 的目标是把这些差异收敛到一组稳定的 TypeScript 接口后面,让上层应用代码不直接依赖具体厂商。
ts
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
const result = await generateText({
model: openai('gpt-4o'),
prompt: '用一句话解释 AsyncIterable',
});
console.log(result.text);这段代码中,只有 model 来自某个 Provider 包。其余的调用方式、返回结构、错误处理,都与具体厂商无关。
模型对象
在 Vercel AI SDK 中,一个模型不是一个字符串,也不是一个 HTTP 配置,而是一个按照统一接口构造出来的“模型对象”。
这个模型对象携带了以下信息:
- 它属于哪个 Provider
- 它对应哪个模型 id
- 它支持哪些能力,例如文本生成、流式生成、工具调用、结构化输出
上层核心函数只依赖这个模型对象,不依赖具体的 Provider 包实现。
核心入口
SDK 把生成类任务抽象成几个核心入口:
generateText:一次性生成文本streamText:流式生成文本generateObject:生成符合 JSON Schema 的结构化对象- 嵌入向量:把文本转换为向量
这些入口分别对应不同的模型能力。Provider 包负责把统一调用映射到厂商 API。
ts
import { generateObject } from 'ai';
import { z } from 'zod';
const result = await generateObject({
model: openai('gpt-4o'),
schema: z.object({
title: z.string(),
points: z.array(z.string()),
}),
prompt: '给出三个关于 AsyncIterable 的要点',
});
console.log(result.object);generateObject 将“要求模型返回 JSON”这一过程抽象出来。模型是否支持结构化输出,由 Provider 和模型本身决定。
统一消息结构
对话类模型通常接收一个消息列表。Vercel AI SDK 对消息结构做了统一:
ts
const messages = [
{ role: 'system', content: '你是一个有帮助的助手。' },
{ role: 'user', content: '北京今天多少度?' },
];
const result = await generateText({
model: openai('gpt-4o'),
messages,
});当模型请求调用工具时,消息中会携带工具调用信息;工具执行后,执行结果会作为新的消息继续参与对话。SDK 的 Provider 适配层会把这些内部消息结构转换成各厂商的 API 格式。
工作原理
Provider 适配层
适配器模式
Provider 包的核心职责是适配。每个 Provider 包都导出一个模型工厂函数,例如:
ts
import { openai } from '@ai-sdk/openai';
const model = openai('gpt-4o');openai('gpt-4o') 返回的是一个可以被 generateText、streamText 接受的模型对象。这个对象内部封装了:
- Provider 的 API 地址
- 认证方式
- 模型 id
- 消息格式转换
- 流式响应解析
- 工具调用格式转换
应用层不直接看到这些细节。
通过模型字符串接入
除了直接安装 Provider 包,Vercel AI SDK 也支持通过 Vercel AI Gateway 使用模型字符串。例如:
ts
const result = await generateText({
model: 'anthropic/claude-opus-4.6',
prompt: '你好',
});这种接入方式把“模型选择”变成了一个字符串配置,适合需要动态路由模型或统一计费的场景。
OpenAI Compatible Provider
对于使用 OpenAI 兼容协议的服务,SDK 提供了 @ai-sdk/openai-compatible 包。
bash
npm install @ai-sdk/openai-compatible它允许通过配置 baseURL 和 headers,接入任意兼容 OpenAI Chat Completions 协议的 API:
ts
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
const provider = createOpenAICompatible({
name: 'my-provider',
baseURL: 'https://api.example.com/v1',
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
},
});
const model = provider('my-model');以 Clarifai 为例,官方文档使用 CLARIFAI_PAT 作为认证凭据。通过 OpenAI Compatible 包,这类服务也能统一接入 AI SDK 的调用流程。
流式输出标准化
AsyncIterable 作为服务端抽象
streamText 返回的结果中带有一个 textStream 属性。它是一个 AsyncIterable<string>,可以逐段读取生成文本:
ts
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
const result = streamText({
model: openai('gpt-4o'),
prompt: '数到五',
});
for await (const chunk of result.textStream) {
process.stdout.write(chunk);
}AsyncIterable 是 ES2018 引入的异步迭代协议。SDK 用它屏蔽了不同 Provider 的流式传输差异。无论 Provider 底层返回的是 SSE、WebSocket 还是普通分批 JSON,上层读取方式都是一致的。
Data Stream Protocol
当流式响应需要从服务端传到浏览器端时,Vercel AI SDK 使用 Data Stream Protocol。这个协议描述的是“AI SDK 服务端到 UI 客户端”的流。
协议的基本形式是:服务器发送一系列形如 {type}:{data} 的消息,type 和 data 是具体字段。不同类型的数据可以表示:
- 文本增量
- 消息状态变化
- 工具调用信息
- 结束原因
- 使用量等元数据
在服务端,streamText 的结果可以直接转换为这种协议响应:
ts
return result.toDataStreamResponse();在客户端,useChat 会解析这种协议,并把流式数据还原成 messages 状态。
工具调用抽象
工具声明
在 AI SDK 中,工具通过 tool 函数声明。一个工具通常包含:
description:描述工具的作用,帮助模型决定何时调用inputSchema:声明工具参数结构execute:真正执行工具的逻辑
ts
import { tool } from 'ai';
import { z } from 'zod';
const weatherTool = tool({
description: '获取指定城市的天气',
inputSchema: z.object({
city: z.string(),
}),
execute: async ({ city }) => {
return {
city,
temperature: 24,
condition: '晴',
};
},
});execute 的参数类型会根据 inputSchema 自动推断。
工具调用循环
把工具传给 streamText 后,SDK 会处理完整的工具调用循环:
- 模型根据用户消息决定是否调用工具
- 如果模型返回工具调用,SDK 根据工具名找到对应工具
- SDK 校验参数
- SDK 调用
execute - 工具执行结果作为新消息回传给模型
- 模型根据工具结果继续生成文本或继续调用工具
ts
const result = streamText({
model: openai('gpt-4o'),
messages,
tools: {
weather: weatherTool,
},
});这个循环也被称为 Agent Loop。SDK 的抽象点在于:应用层只需要声明工具和实现 execute,不需要手动拼接工具调用回传消息。
不提供 execute 的情况
工具可以只声明 description 和 inputSchema,不提供 execute。此时 SDK 不会自动执行工具,而是把模型产生的工具调用信息暴露给调用方,由调用方自己决定如何处理。
这种设计让 SDK 既能服务“自动 Agent”场景,也能服务“人机协作”场景。
包结构与模块边界
从包结构上看,Vercel AI SDK 可以分成几层:
text
ai
├── 核心 API:generateText、streamText、generateObject、tool
├── @ai-sdk/provider
│ └── 模型接口与 Provider 契约
├── @ai-sdk/openai
├── @ai-sdk/anthropic
├── @ai-sdk/google
├── @ai-sdk/openai-compatible
└── @ai-sdk/react核心包 ai 不直接依赖任何具体 Provider 包。它依赖的是 @ai-sdk/provider 中定义的接口契约。
依赖方向是:
- 应用代码依赖
ai核心包 ai核心包依赖@ai-sdk/provider的接口- Provider 包实现
@ai-sdk/provider的接口 @ai-sdk/react依赖ai核心包ai核心包不反向依赖@ai-sdk/react
这种模块边界的意义在于:
- 新增 Provider 时不需要修改核心包
- 第三方可以按照同一套接口实现自己的 Provider 包
- React 版本和核心版本可以独立演进
- 应用只安装自己需要的 Provider 包,不需要把所有厂商 SDK 都打进去
基本用法
安装
根据使用场景,还需要安装对应的 Provider 包:
bash
npm install @ai-sdk/openai或 React 集成包:
bash
npm install @ai-sdk/reactNext.js 集成
在 Next.js App Router 中,最常用的接入方式是 Route Handler。
ts
// app/api/chat/route.ts
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,
});
return result.toDataStreamResponse();
}这个 Route Handler 接收客户端发来的 messages,调用 streamText,再以 Data Stream Protocol 把结果返回给客户端。
前端组件使用 useChat 时,默认会请求 /api/chat:
tsx
const { messages, input, handleInputChange, handleSubmit } = useChat();也可以显式指定 API 路径:
tsx
const { messages } = useChat({ api: '/api/chat' });Next.js 集成中,Route Handler 是主要传输层。Server Action 也可以调用 AI SDK 的核心函数,但流式响应通常仍然通过 Route Handler 或流式 Response 传输。
React Hooks
Vercel AI SDK 的核心包与 UI 框架解耦。React 相关能力被放在 @ai-sdk/react 中。
useChat
useChat 是一个 React Hook,用于管理聊天消息状态和流式响应:
tsx
'use client';
import { useChat } from '@ai-sdk/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat();
return (
<div>
{messages.map((m) => (
<div key={m.id}>
<strong>{m.role}</strong>: {m.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
<button type="submit">发送</button>
</form>
</div>
);
}useChat 的默认行为是向 /api/chat 发送 POST 请求,请求体包含 messages。
useChat 不关心具体模型提供方。它只关心服务端返回的 Data Stream Protocol。只要服务端返回的是标准流式协议,前端就能把流式文字、工具调用过程、结束原因等内容还原成消息状态。
useCompletion
如果应用只需要“给一段提示词,流式生成完成文本”,可以使用 useCompletion。它与 useChat 的区别是:它不维护多轮对话消息列表,而是针对单次 prompt 的 completion 场景。
示例
下面的综合示例展示流式聊天和工具调用如何组合。
服务端 Route Handler
ts
// app/api/chat/route.ts
import { streamText, tool } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
const weatherTool = tool({
description: '获取指定城市的天气',
inputSchema: z.object({
city: z.string().describe('城市名称,例如 北京'),
}),
execute: async ({ city }) => {
return {
city,
temperature: 24,
unit: 'C',
condition: '晴',
};
},
});
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai('gpt-4o'),
messages,
tools: {
weather: weatherTool,
},
});
return result.toDataStreamResponse();
}当用户问“北京今天多少度”时,模型可以返回一个工具调用,SDK 自动执行 weather 工具,并把工具结果继续交给模型。最终生成的回答会通过 Data Stream Protocol 返回给前端。
客户端组件
tsx
'use client';
import { useChat } from '@ai-sdk/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat();
return (
<div>
{messages.map((m) => (
<div key={m.id}>
<strong>{m.role}</strong>: {m.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={handleInputChange}
placeholder="问天气..."
/>
<button type="submit">发送</button>
</form>
</div>
);
}如果只渲染 m.content,工具调用过程不会直接显示出来。useChat 返回的消息中除了文本,还会包含结构化的工具调用信息。渲染时可以按 m.role 区分文本和工具消息,也可以在 UI 中单独展示“正在查询天气”的状态。
注意点
Langflow 文档中也有 LanguageModel,但那是 Langflow 组件的一种输出类型,用于把语言模型连接到 Agent 组件,与 Vercel AI SDK 的模型抽象不是同一回事。
Data Stream Protocol 的设计归功于 Vercel 的 AI SDK 文档。社区有非官方的 Python 实现,但它不是 Vercel 官方 Python 包。
限制
- 需要理解 SDK 本身的概念,不只是某个厂商的 API
- 排查问题时要区分是 SDK 层的问题还是 Provider 层的问题
- 某些厂商最新特性可能先出现在原生 SDK 中,抽象层需要一定时间才能跟进
- OpenAI Compatible 等通用适配器只能覆盖兼容协议,无法覆盖所有厂商私有扩展
如果项目只需要接入一个固定模型,并且不需要工具循环、不需要流式 UI、不需要切换 Provider,那么直接使用该厂商的原生 SDK 是更直接的选择。
应用
如果项目需要支持多个模型提供方,需要把 AI 能力嵌入到不同前端框架中,或者需要构建带工具调用循环的 Agent,那么 Vercel AI SDK 的抽象层能够减少重复工作,并让核心逻辑保持框架无关。
具体而言,以下场景适合使用 Vercel AI SDK:
- 多模型接入:应用层通过统一接口切换不同模型,不需要修改核心逻辑
- 流式聊天界面:
useChat与 Data Stream Protocol 配合,前端可以还原多轮对话状态 - 工具调用与 Agent:
tool声明与自动执行循环,让 Agent 逻辑集中在工具实现上 - 跨框架复用:同一套核心 API 可以嵌入 React、Vue、Svelte 等不同 UI 框架
