Vercel 的 AI SDK(ai 包)是 TypeScript 里调用大模型的事实标准之一:统一了各家模型的接口,还原生支持"工具调用"。本教程带你搭一个会查天气的 Agent——从定义工具、单步调用,到用 stepCountIs 跑多步循环,最后封装成 HTTP 接口并接上 React 聊天界面。
先搞懂:工具调用是怎么循环的?
用一句话理解:你给模型一组"函数说明书",模型自己决定调哪个、传什么参数;SDK 执行函数把结果喂回模型,模型再决定继续调还是直接回答。这个"调函数→喂结果→再思考"的循环,就是 Agent 的核心。AI SDK 用 tools 定义函数、用 stopWhen 控制循环上限。
| 环节 | 谁来做 |
|---|---|
| 选函数 + 填参数 | 大模型 |
| 执行函数 | 你的 execute 代码 |
| 判断是否继续 | SDK 循环,直到无工具调用或达上限 |
Step 1:安装依赖
npm install ai @ai-sdk/openai zod
# 若用 Next.js:npx create-next-app@latest my-app
generateText / streamText;聊天 UI 部分才需要 React 与 @ai-sdk/react。Step 2:用 tool() + Zod 定义工具
每个工具三件套:description(模型读它决定何时用)、parameters(Zod schema,既给模型也用于校验)、execute(真正干活的异步函数):
import { tool } from "ai";
import { z } from "zod";
const getWeather = tool({
description: "获取某城市的当前天气",
parameters: z.object({
city: z.string().describe("城市名,如 上海"),
}),
execute: async ({ city }) => {
// 这里接真实天气 API;示例返回固定结构
return { city, temperature: 22, condition: "晴" };
},
});
Step 3:单步工具调用(generateText)
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
const { text, toolCalls } = await generateText({
model: openai("gpt-4o"),
tools: { getWeather },
prompt: "上海现在天气怎么样?",
});
console.log(text, toolCalls);
先配置 OPENAI_API_KEY。在项目根目录 .env 写 OPENAI_API_KEY=sk-...,@ai-sdk/openai 会自动读取。模型名以你账号可用模型为准。
Step 4:多步 Agent 循环(streamText + stepCountIs)
当用户问题需要多个工具结果(如"上海和东京天气各怎样"),用 stopWhen: stepCountIs(N) 允许 SDK 自动跑多轮,直到模型产出纯文本:
import { streamText, stepCountIs } from "ai";
const result = streamText({
model: openai("gpt-4o"),
tools: { getWeather },
stopWhen: stepCountIs(5), // 最多 5 轮工具调用,防止死循环
prompt: "上海和东京的天气各是怎样?做个对比。",
});
for await (const part of result.textStream) {
process.stdout.write(part);
}
务必加 stopWhen: stepCountIs(N)。没有上限时,一个"犯迷糊"的模型可能反复调工具直到烧光额度。大多数 Agent 设 5,研究类可设 10。
Step 5:封装成 HTTP 接口(Next.js Route Handler)
// app/api/agent/route.ts
import { streamText, convertToModelMessages, stepCountIs } 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: convertToModelMessages(messages),
tools: { getWeather },
stopWhen: stepCountIs(5),
});
return result.toUIMessageStreamResponse();
}
公网接口要鉴权。本示例 Route Handler 任何人都能调用并消耗你的模型额度。上线前加用户登录校验 / rate limit,敏感工具(写数据库、发消息)务必加人工确认。
Step 6:前端聊天 UI(useChat)
"use client";
import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport } from "ai";
const { messages, input, handleSubmit, setInput } = useChat({
transport: new DefaultChatTransport({ api: "/api/agent" }),
});
// <form onSubmit={handleSubmit}>
// <input value={input} onChange={(e) => setInput(e.target.value)} />
// </form>
Step 7:模型路由与兜底(可选)
若走 Vercel AI Gateway,可在 providerOptions.gateway.models 里列备用模型,主模型报错时按顺序兜底:
const result = streamText({
model: openai("gpt-4o"),
prompt,
providerOptions: {
gateway: {
models: ["anthropic/claude-xxx", "google/gemini-xxx"],
},
},
});
常见问题速查
| 现象 | 原因 & 解决 |
|---|---|
| 401 / 无响应 | OPENAI_API_KEY 未配置或模型名不可用 |
| 工具不被调用 | description 不够清楚,或问题本不需要工具 |
| 无限循环烧钱 | 漏了 stopWhen: stepCountIs(N) |
| 前端收不到流 | Route Handler 没返回 toUIMessageStreamResponse |