从 vercel/ai README 看 TypeScript AI Agent 的工具链结构
在 README 的 Agent 示例里,一个 Agent 被写成 ToolLoopAgent,工具里可以调 openai.tools.localShell,在前端则通过 useChat 和消息 parts 渲染工具调用。这种从模型调用、工具执行到 UI 状态同步的链路,正是 TypeScript AI 应用工具链最容易被低估的部分。官方 README 没有展开内部实现,但它公开的 API 表面已经能说明一些选型问题。
官方明确给出的定位与运行时
AI SDK 被描述为 provider-agnostic 的 TypeScript toolkit,用于构建 AI-powered applications 和 agents,支持 Next.js、React、Svelte、Vue、Angular 等 UI 框架,以及 Node.js 运行时。安装要求写的是 Node.js 22+ 和 npm(或其他包管理器),安装命令是 npm install ai。对 coding agents 用户,README 还建议运行 npx skills add vercel/ai 把 AI SDK skill 加入仓库。
这些是事实层面的硬信息:最低 Node.js 版本、包名、skill 安装入口。选型时可以先对齐运行时基线,再判断前端框架支持是否覆盖现有工程。
统一 Provider 抽象:网关与直连两条路
README 的 Unified Provider Architecture 部分给出了两种接入方式。
默认方式走 Vercel AI Gateway,代码只传模型字符串:
const result = await generateText({
model: 'anthropic/claude-opus-4.6', // 或 'openai/gpt-5.4'、'google/gemini-3-flash'
prompt: 'Hello!',
});
另一种是安装 provider SDK 包,再直接调用:
import { anthropic } from '@ai-sdk/anthropic';
const result = await generateText({
model: anthropic('claude-opus-4-6'),
prompt: 'Hello!',
});
README 明确列出的 provider 包括 OpenAI、Anthropic、Google,并指向更多 provider 文档。这里有一个值得注意的细节:网关示例里的模型串是 anthropic/claude-opus-4.6,而直连 SDK 示例里是 anthropic('claude-opus-4-6')。两者写法不同,README 没有解释差异来源。实际接入时,模型标识、默认网关行为和直连 SDK 的参数映射需要单独验证,不能默认两条路径完全等价。
从工程角度看,这种「默认网关 + 直连逃生舱」的结构对选型有直接影响。如果团队已经在用某一家 provider 的独家能力,直连 SDK 的抽象层是否够薄、是否会把 provider 特有参数吃掉,是需要看源码或文档确认的。反过来,如果希望一套代码快速切模型,网关的字符串路由方式降低了接入成本,但也引入了对网关可用性和配置的依赖。
结构化输出与 Agent 循环
在结构化数据部分,README 展示的是 generateText 配合 Output.object 和 zod schema:
import { generateText, Output } from 'ai';
import { z } from 'zod';
const { output } = await generateText({
model: 'openai/gpt-5.4',
output: Output.object({
schema: z.object({...}),
}),
prompt: 'Generate a lasagna recipe.',
});
这说明 AI SDK 把结构化输出做进了统一调用入口,而不是要求开发者自己拼 provider 的 JSON mode 或 function calling。对需要稳定数据结构的应用,这是一个明确的 API 面。
Agent 部分则出现了 ToolLoopAgent:
import { ToolLoopAgent } from 'ai';
const sandboxAgent = new ToolLoopAgent({
model: 'openai/gpt-5.4',
system: 'You are an agent with access to a shell environment.',
tools: {
shell: openai.tools.localShell({
execute: async ({ action }) => {
const [cmd, ...args] = action.command;
const sandbox = await getSandbox(); // Vercel Sandbox
const command = await sandbox.runCommand({ cmd, args });
return { output: await command.stdout() };
},
}),
},
});
README 没有说明 ToolLoopAgent 内部如何驱动工具循环、如何决定继续调用还是停止、错误和重试如何处理。它只展示了定义方式、工具注册方式,以及工具执行函数可以返回结果。从选型角度,这意味着「Agent 循环控制权」是必须进一步查文档或源码的点:循环次数、终止条件、并行工具调用、人工确认、超时与取消,都会影响生产可用性。
UI 集成:框架无关的 hooks 与消息 parts
README 的 UI Integration 部分明确说,AI SDK UI 模块提供一组 hooks,用于构建 chatbot 和 generative UI。这些 hooks 是 framework agnostic,可以用在 Next.js、React、Svelte、Vue。使用时要安装对应框架包,例如 npm install @ai-sdk/react。
一个端到端的 image generation agent 示例展示了前后端分工:
Agent 文件导出 ToolLoopAgent,工具是 openai.tools.imageGeneration({ partialImages: 3 }),并用 InferAgentUIMessage 导出消息类型。
Next.js App Router 的 route 里,用 createAgentUIStreamResponse({ agent, messages }) 把 agent 接到 UI。
前端组件用 UIToolInvocation 接收工具调用,根据 invocation.state 的 input-available、output-available 渲染不同 UI。页面用 useChat(),遍历 message.parts,按 part.type 区分文本和 tool-generateImage。
这段示例的工程信息量在于:AI SDK 没有把 UI 状态藏在内部,而是把消息拆成 parts,工具调用作为一类 part 暴露给前端。类型上通过 InferAgentUIMessage 从 agent 定义推导消息类型。这意味着前后端共享同一套 TypeScript 类型,工具名到 UI 渲染分支是对齐的:tool-generateImage 对应 openai.tools.imageGeneration。
但 README 同样没有说明:parts 的完整类型集合、流式增量如何合并、工具调用中间状态如何持久化、多轮工具调用如何排序。这些是 UI 集成中容易出问题的地方,需要结合 API Reference 和实际运行验证。
选型时值得验证的边界
如果把 AI SDK 放进 TypeScript AI Agent 工具链的候选名单,README 能支撑的结论是有限的但具体的:
- 它明确支持 Node.js 22+,安装包是
ai。 - 它提供统一 Provider 抽象,默认走 Vercel AI Gateway,也可直连
@ai-sdk/openai、@ai-sdk/anthropic、@ai-sdk/google。 - 它包含
generateText、Output.object、ToolLoopAgent等公开 API。 - 它的 UI hooks 框架无关,但需要按框架安装
@ai-sdk/react等包。 - 示例覆盖了 Next.js App Router 的 route、
createAgentUIStreamResponse、useChat和工具调用渲染。
需要进一步验证的则包括:Provider 直连与网关的行为差异、模型串映射规则、Agent 循环的终止和错误策略、工具执行的安全边界、UI parts 的流式协议、以及与现有状态管理、鉴权、计费、可观测性系统的集成方式。
对使用 TypeScript 构建 AI 应用的团队来说,一个可行的做法是先用一个最小工具调用链做验证:定义 ToolLoopAgent,注册一个幂等工具,通过 createAgentUIStreamResponse 接到前端,再用 useChat 渲染 parts。在进入生产前,把上述边界项逐条对照文档和源码确认,而不是只根据 README 的示例判断完整能力。