编程 Vercel AI SDK + eve 深度实战:当 TypeScript 成为 AI Agent 开发的一等公民——从统一模型层到文件系统优先框架、从多步工具调用到生产级 Agent 部署的完全指南(2026)

2026-06-20 12:23:02 +0800 CST views 10

Vercel AI SDK + eve 深度实战:当 TypeScript 成为 AI Agent 开发的一等公民——从统一模型层到文件系统优先框架、从多步工具调用到生产级 Agent 部署的完全指南(2026)

引言:为什么 Vercel AI SDK 是 2026 年最值得关注的 AI 开发工具栈

2026 年,AI Agent 开发已经从实验阶段进入了工程化阶段。但一个尴尬的现实是:大多数开发者仍然在手动处理模型差异、自行拼接流式输出、手工编写工具调用逻辑。OpenAI 的 API 和 Anthropic 的 API 不仅参数格式不同,连流式响应的结构都不一样。每换一个模型提供商,你的代码就要改一遍。

Vercel AI SDK 正是为了解决这个问题而生的。它提供了一个统一的 TypeScript API 层,让你用同一套代码调用不同的大模型——从 OpenAI、Anthropic、Google 到各种开源模型。更重要的是,它在 2026 年的 Vercel Ship 大会上,配合开源的 eve 框架一起,形成了从底层 SDK 到上层 Agent 框架的完整工具链。

本文将从以下角度进行深度分析:

  1. AI SDK Core 的核心架构:generateText / streamText / tool calling 的统一抽象
  2. Tool Calling 深度实战:从简单工具到多步 Agent 循环
  3. Structured Output:类型安全的结构化数据生成
  4. AI SDK UI:与 React/Next.js 的无缝集成
  5. eve 框架:文件系统优先的 Durable Agent 开发框架
  6. Mastra 生态:从 Gatsby 团队带来的全栈 AI Agent 框架
  7. 生产级实践:从可观测性到成本控制、从安全审批到部署策略

一、AI SDK Core:统一模型层的架构设计

1.1 核心设计理念

Vercel AI SDK 的核心设计哲学可以总结为三个词:统一、类型安全、可组合

统一意味着你只需要学习一套 API。不管底层是 OpenAI 还是 Anthropic,代码结构不变:

import { generateText } from "ai";

// 使用 Anthropic
const result1 = await generateText({
  model: "anthropic/claude-sonnet-4.5",
  prompt: "解释什么是闭包",
});

// 使用 OpenAI——只需要改 model 字符串
const result2 = await generateText({
  model: "openai/gpt-4o",
  prompt: "解释什么是闭包",
});

类型安全意味着所有输入输出都有 TypeScript 类型推断。你的工具参数、结构化输出、消息历史——全部是强类型的。

可组合意味着 SDK 的各个功能模块可以像乐高积木一样组合。generateText 可以和 tool calling 组合,streamText 可以和 structured output 组合,形成强大的复合能力。

1.2 两大核心函数:generateText 与 streamText

AI SDK Core 围绕两个核心函数构建:

函数用途场景
generateText非流式文本生成 + 工具调用自动化任务、Agent 编排、数据处理
streamText流式文本生成 + 工具调用聊天机器人、实时应用、Generative UI

两个函数共享同一套配置接口,包括:

  • model:模型标识符(格式为 provider/model-id
  • system:系统提示词
  • prompt / messages:用户输入
  • tools:工具定义
  • output:结构化输出定义
  • stopWhen:多步调用的停止条件

generateText 返回的是一个 Promise,包含完整结果:

const result = await generateText({
  model: "anthropic/claude-sonnet-4.5",
  prompt: "用一句话解释函数式编程",
});

console.log(result.text);       // 生成的文本
console.log(result.usage);     // Token 使用量
console.log(result.finishReason); // 停止原因
console.log(result.response.messages); // 可追加到消息历史

streamText 返回的是一个流式结果对象:

const result = streamText({
  model: "anthropic/claude-sonnet-4.5",
  prompt: "写一首关于 TypeScript 的诗",
  onError({ error }) {
    console.error("流式错误:", error);
  },
});

// 作为 AsyncIterable 消费
for await (const textPart of result.textStream) {
  process.stdout.write(textPart);
}

1.3 模型提供商体系

AI SDK 采用提供商插件架构,每个提供商是一个独立的 npm 包:

# 核心包
npm install ai

# 提供商包(按需安装)
npm install @ai-sdk/openai
npm install @ai-sdk/anthropic
npm install @ai-sdk/google
npm install @ai-sdk/mistral
npm install @ai-sdk/amazon-bedrock
npm install @ai-sdk/azure

模型标识符格式为 provider/model-id,例如:

  • anthropic/claude-sonnet-4.5
  • openai/gpt-4o
  • google/gemini-2.5-pro
  • mistral/mistral-large-latest

这种设计使得切换模型只需要改一个字符串,其他代码完全不变。

1.4 提供商配置

每个提供商都可以独立配置:

import { createOpenAI } from "@ai-sdk/openai";
import { createAnthropic } from "@ai-sdk/anthropic";

// 自定义 OpenAI 配置(支持兼容 API)
const openai = createOpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  baseURL: "https://my-custom-endpoint.com/v1", // 支持自定义端点
});

// 自定义 Anthropic 配置
const anthropic = createAnthropic({
  apiKey: process.env.ANTHROPIC_API_KEY,
});

// 使用自定义提供商实例
const result = await generateText({
  model: anthropic("claude-sonnet-4.5"),
  prompt: "Hello",
});

这个设计非常实用——你可以用它来对接 DeepSeek、通义千问、智谱 GLM 等兼容 OpenAI API 格式的国产模型。


二、Tool Calling:从简单工具到 Agent 循环

2.1 工具定义的基本模式

Tool Calling 是 AI Agent 的核心能力。AI SDK 的工具定义非常优雅——使用 Zod schema 来定义参数,TypeScript 自动推断类型:

import { generateText, tool } from "ai";
import { z } from "zod";

const weatherTool = tool({
  description: "获取指定城市的天气信息",
  inputSchema: z.object({
    city: z.string().describe("城市名称"),
    unit: z.enum(["celsius", "fahrenheit"]).optional().describe("温度单位"),
  }),
  execute: async ({ city, unit = "celsius" }) => {
    // 实际调用天气 API
    const response = await fetch(
      `https://api.weather.com/v1?city=${city}&unit=${unit}`
    );
    return response.json();
  },
});

const result = await generateText({
  model: "anthropic/claude-sonnet-4.5",
  tools: { getWeather: weatherTool },
  prompt: "北京今天天气怎么样?",
});

2.2 多步调用(Multi-Step Agent Loop)

真正的 Agent 能力来自于多步调用——模型可以连续调用多个工具,每一步的结果反馈给模型,让它决定下一步做什么。

AI SDK 通过 stopWhen 参数控制这个循环:

import { generateText, tool, stepCountIs } from "ai";

const result = await generateText({
  model: "anthropic/claude-sonnet-4.5",
  tools: {
    searchDatabase: tool({
      description: "搜索数据库中的用户信息",
      inputSchema: z.object({
        query: z.string(),
      }),
      execute: async ({ query }) => {
        // 数据库搜索逻辑
        return await db.users.search(query);
      },
    }),
    sendEmail: tool({
      description: "发送邮件给指定用户",
      inputSchema: z.object({
        userId: z.string(),
        subject: z.string(),
        body: z.string(),
      }),
      execute: async ({ userId, subject, body }) => {
        return await emailService.send({ userId, subject, body });
      },
    }),
  },
  stopWhen: stepCountIs(10), // 最多 10 步
  prompt: "找到所有上个月没有登录的用户,给他们发送激活邮件",
});

内置的停止条件有:

  • stepCountIs(count) — 步数限制
  • hasToolCall(toolName) — 调用了特定工具后停止
  • isLoopFinished() — 永不主动停止,让模型自然结束
  • 自定义条件函数
  • 条件数组(任意一个满足即停止)

2.3 步骤跟踪与调试

多步调用中,你可以通过 steps 属性获取每一步的详细信息:

const { steps } = await generateText({
  model: "anthropic/claude-sonnet-4.5",
  stopWhen: stepCountIs(10),
  tools: { /* ... */ },
  prompt: "帮我分析一下这份代码的性能问题",
});

// 遍历每一步
for (const step of steps) {
  console.log(`步骤 ${step.stepNumber}:`);
  console.log(`  文本: ${step.text || "(无文本)"}`);
  console.log(`  工具调用:`, step.toolCalls);
  console.log(`  工具结果:`, step.toolResults);
  console.log(`  Token 用量:`, step.usage);
}

2.4 生命周期回调:可观测性的基石

AI SDK 提供了完整生命周期回调链,这是生产级可观测性的基础:

const result = await generateText({
  model: "anthropic/claude-sonnet-4.5",
  tools: { /* ... */ },
  prompt: "分析这个 bug",

  // 整体开始
  experimental_onStart({ model, settings, functionId }) {
    logger.info("生成开始", { model: model.modelId, functionId });
  },

  // 每一步开始
  experimental_onStepStart({ stepNumber, model, promptMessages }) {
    logger.info(`步骤 ${stepNumber} 开始`, { promptLength: promptMessages.length });
  },

  // 工具调用开始
  experimental_onToolCallStart({ toolName, toolCallId, input }) {
    logger.info(`调用工具: ${toolName}`, { toolCallId, input });
    startTimer(toolCallId);
  },

  // 工具调用结束
  experimental_onToolCallFinish({ toolName, toolCallId, output, error, durationMs }) {
    const elapsed = durationMs;
    if (error) {
      logger.error(`工具 ${toolName} 失败`, { toolCallId, error, elapsed });
    } else {
      logger.info(`工具 ${toolName} 完成`, { toolCallId, elapsed });
    }
    metrics.record("tool.duration", durationMs, { toolName });
  },

  // 每一步结束
  onStepFinish({ stepNumber, finishReason, usage }) {
    logger.info(`步骤 ${stepNumber} 完成`, { finishReason, usage });
    metrics.record("tokens.used", usage?.totalTokens ?? 0);
  },
});

2.5 工具执行审批机制

这是 AI SDK 一个非常实用的安全特性。对于敏感操作(如删除数据、执行命令、支付),你可以要求人工审批:

const deleteFileTool = tool({
  description: "删除指定文件",
  inputSchema: z.object({
    filePath: z.string(),
  }),
  needsApproval: true, // 强制需要人工审批
  execute: async ({ filePath }) => {
    return await fs.unlink(filePath);
  },
});

// 也可以根据参数动态决定是否需要审批
const paymentTool = tool({
  description: "处理支付",
  inputSchema: z.object({
    amount: z.number(),
    recipient: z.string(),
  }),
  needsApproval: async ({ amount }) => amount > 1000, // 超过 1000 元需要审批
  execute: async ({ amount, recipient }) => {
    return await processPayment(amount, recipient);
  },
});

审批流程是一个两阶段设计:第一次 generateText 返回 approval request,你的应用收集用户决策后,把 approval response 加入消息历史再次调用。

2.6 流式工具结果

AI SDK 支持工具返回 AsyncIterable,实现流式状态更新:

const researchTool = tool({
  description: "深度研究某个主题",
  inputSchema: z.object({
    topic: z.string(),
  }),
  async *execute({ topic }) {
    // 先返回"正在搜索"状态
    yield {
      status: "searching" as const,
      message: `正在搜索关于"${topic}"的信息...`,
      data: null,
    };

    const results = await searchEngine.search(topic);

    // 返回中间结果
    yield {
      status: "analyzing" as const,
      message: `找到 ${results.length} 条结果,正在分析...`,
      data: { resultCount: results.length },
    };

    // 最终结果
    yield {
      status: "done" as const,
      message: "分析完成",
      data: { summary: "..." },
    };
  },
});

2.7 动态工具与 MCP 集成

对于运行时才知道工具 schema 的场景(比如 MCP 协议的动态工具),AI SDK 提供了 dynamicTool

import { dynamicTool } from "ai";

const mcpTool = dynamicTool({
  description: "通过 MCP 协议调用的动态工具",
  inputSchema: z.object({}), // 运行时才知道具体 schema
  execute: async (input) => {
    // input 类型为 unknown,需要运行时校验
    return await mcpClient.callTool(input);
  },
});

// 类型安全处理
const result = await generateText({
  model: "anthropic/claude-sonnet-4.5",
  tools: { weather: weatherTool, mcp: mcpTool },
  onStepFinish({ toolCalls }) {
    for (const call of toolCalls) {
      if (call.dynamic) {
        console.log("动态工具:", call.toolName, call.input);
      } else {
        // 静态工具:完整的类型推断
        switch (call.toolName) {
          case "weather":
            console.log(call.input.city); // TypeScript 知道这是 string
            break;
        }
      }
    }
  },
});

2.8 prepareStep:每一步的精细控制

prepareStep 回调允许你在每一步开始前修改配置——这是实现复杂 Agent 编排的关键:

const result = await generateText({
  model: "anthropic/claude-sonnet-4.5",
  tools: { search: searchTool, analyze: analyzeTool, summarize: summarizeTool },
  stopWhen: stepCountIs(10),
  prompt: "研究并总结最新的 AI 框架趋势",

  prepareStep: async ({ stepNumber, steps, messages }) => {
    // 第一步:强制使用搜索工具
    if (stepNumber === 0) {
      return {
        toolChoice: { type: "tool", toolName: "search" },
        activeTools: ["search"],
      };
    }

    // 第二步:强制分析
    if (stepNumber === 1) {
      return {
        toolChoice: { type: "tool", toolName: "analyze" },
        activeTools: ["analyze"],
      };
    }

    // 后续步骤:使用更便宜的模型做总结
    if (stepNumber >= 2) {
      return {
        model: "anthropic/claude-haiku-4",
        activeTools: ["summarize"],
      };
    }

    // 长循环中的消息压缩
    if (messages.length > 20) {
      return {
        messages: messages.slice(-10), // 只保留最近 10 条
      };
    }

    return {}; // 使用默认配置
  },
});

三、Structured Output:类型安全的结构化数据生成

3.1 基本用法

Structured Output 让大模型生成符合你定义的 TypeScript 类型的数据。这对于信息提取、分类、数据生成等场景极为实用:

import { generateText } from "ai";

const result = await generateText({
  model: "anthropic/claude-sonnet-4.5",
  prompt: "分析这篇技术文章的核心观点",
  output: {
    type: "object",
    schema: z.object({
      title: z.string().describe("文章标题"),
      summary: z.string().describe("一句话摘要"),
      keyPoints: z.array(z.string()).describe("核心观点列表"),
      difficulty: z.enum(["beginner", "intermediate", "advanced"])
        .describe("技术难度"),
      tags: z.array(z.string()).describe("标签"),
    }),
  },
});

// result.object 是类型安全的
console.log(result.object.title);
console.log(result.object.keyPoints);       // string[]
console.log(result.object.difficulty);       // "beginner" | "intermediate" | "advanced"

3.2 数组输出

const result = await generateText({
  model: "openai/gpt-4o",
  prompt: "列出 10 个提高 Go 性能的技巧",
  output: {
    type: "array",
    schema: z.object({
      name: z.string(),
      description: z.string(),
      codeExample: z.string().optional(),
      impact: z.enum(["low", "medium", "high"]),
    }),
  },
});

// result.object 是类型安全数组
for (const tip of result.object) {
  console.log(`${tip.name}: ${tip.impact}`);
}

3.3 Generative UI:流式生成 React 组件

Structured Output 结合 streamText 可以实现"AI 生成 UI"的效果——模型输出的结构化数据直接映射为 React 组件:

// API Route
export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = streamText({
    model: "anthropic/claude-sonnet-4.5",
    messages,
    tools: {
      showWeatherCard: tool({
        description: "显示天气卡片",
        inputSchema: z.object({
          city: z.string(),
          temperature: z.number(),
          condition: z.string(),
        }),
      }),
      showStockChart: tool({
        description: "显示股票图表",
        inputSchema: z.object({
          symbol: z.string(),
          price: z.number(),
          change: z.number(),
        }),
      }),
    },
  });

  return result.toUIMessageStreamResponse();
}
// 前端
import { useChat } from "@ai-sdk/react";

function Chat() {
  const { messages } = useChat({
    api: "/api/chat",
  });

  return (
    <div>
      {messages.map((msg) => (
        <div key={msg.id}>
          {msg.content.map((part, i) => {
            if (part.type === "tool-invocation") {
              const { state, toolName } = part.toolInvocation;

              if (toolName === "showWeatherCard" && state === "result") {
                const { city, temperature, condition } = part.toolInvocation.result;
                return <WeatherCard city={city} temp={temperature} condition={condition} />;
              }

              if (toolName === "showStockChart" && state === "result") {
                const { symbol, price, change } = part.toolInvocation.result;
                return <StockChart symbol={symbol} price={price} change={change} />;
              }
            }

            return <span key={i}>{part.text}</span>;
          })}
        </div>
      ))}
    </div>
  );
}

四、AI SDK UI:前端集成的三种模式

4.1 useChat:聊天应用的核心 Hook

useChat 是 AI SDK UI 最常用的 Hook,专为聊天场景设计:

"use client";

import { useChat } from "@ai-sdk/react";

export default function ChatPage() {
  const {
    messages,       // 消息历史
    input,          // 当前输入
    setInput,       // 设置输入
    handleSubmit,   // 提交处理
    isLoading,      // 是否加载中
    error,          // 错误信息
    reload,         // 重新生成
    stop,           // 停止生成
    append,         // 追加消息
    data,           // 额外数据
  } = useChat({
    api: "/api/chat",
    initialMessages: [], // 可选的初始消息
    body: {
      // 每次请求附带的额外参数
      userId: "user-123",
    },
    onFinish({ message }) {
      // 生成完成回调
      analytics.track("chat_message", {
        role: message.role,
        contentLength: message.content.length,
      });
    },
    onError(error) {
      console.error("Chat error:", error);
    },
  });

  return (
    <div className="flex flex-col h-screen">
      <div className="flex-1 overflow-y-auto p-4">
        {messages.map((message) => (
          <div key={message.id} className="mb-4">
            <div className="font-bold">{message.role === "user" ? "你" : "AI"}</div>
            <div>{message.content}</div>
          </div>
        ))}
      </div>
      <form onSubmit={handleSubmit} className="p-4 border-t">
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="输入消息..."
          className="w-full p-2 border rounded"
        />
        <button type="submit" disabled={isLoading}>
          {isLoading ? "思考中..." : "发送"}
        </button>
      </form>
    </div>
  );
}

4.2 工具执行审批的前端处理

结合前面提到的 needsApproval,前端可以这样处理审批流程:

const { messages, setMessages } = useChat({ api: "/api/chat" });

// 监听消息更新,处理审批请求
useEffect(() => {
  const lastMessage = messages[messages.length - 1];
  if (!lastMessage) return;

  for (const part of lastMessage.parts) {
    if (part.type === "tool-invocation" && part.toolInvocation.state === "call") {
      const { toolName, args } = part.toolInvocation;

      // 弹出确认对话框
      const confirmed = window.confirm(
        `AI 请求调用工具 "${toolName}",参数:${JSON.stringify(args)},是否允许?`
      );

      // 发送审批响应
      addToolApprovalResponse({
        approvalId: part.toolInvocation.toolCallId,
        approved: confirmed,
        reason: confirmed ? "用户确认" : "用户拒绝",
      });
    }
  }
}, [messages]);

4.3 useCompletion:文本补全

import { useCompletion } from "@ai-sdk/react";

function CodeAssistant() {
  const {
    completion,
    input,
    setInput,
    handleSubmit,
    isLoading,
  } = useCompletion({
    api: "/api/complete",
    prompt: "你是一个 TypeScript 代码补全助手",
  });

  return (
    <div>
      <textarea
        value={input}
        onChange={(e) => setInput(e.target.value)}
        placeholder="输入你的代码..."
      />
      <button onClick={handleSubmit}>补全</button>
      {isLoading && <span>生成中...</span>}
      {completion && (
        <pre><code>{completion}</code></pre>
      )}
    </div>
  );
}

五、eve 框架:文件系统优先的 Durable Agent

5.1 设计哲学:约定优于配置

2026 年 Vercel Ship 大会最重磅的开源发布之一就是 eve——一个"文件系统优先"的 Agent 开发框架。它的核心理念是:Agent 的所有能力都应该通过文件系统的约定来组织,而不是通过复杂的编程 API。

这和 Rails 的"约定优于配置"思想一脉相承。一个 eve Agent 的项目结构:

my-agent/
└── agent/
    ├── agent.ts           # 可选:模型和运行时配置
    ├── instructions.md    # 必需:始终在线的系统提示词
    ├── tools/             # 可选:类型安全的工具函数
    │   └── get_weather.ts
    ├── skills/             # 可选:按需加载的技能(Markdown)
    │   └── plan_a_trip.md
    ├── channels/           # 可选:消息通道(HTTP、Slack、Discord)
    │   └── slack.ts
    └── schedules/          # 可选:定时任务
        └── weekly_recap.ts

5.2 快速上手

npx eve@latest init my-agent
cd my-agent
npm run dev

instructions.md 是 Agent 的"灵魂"——它就是 Agent 的 system prompt,始终在线:

你是一个专业的技术博客助手。你的职责是:
1. 帮助开发者撰写高质量的技术文章
2. 提供代码审查和架构建议
3. 解释复杂的技术概念

回答要求:
- 使用中文
- 代码示例用 TypeScript
- 风格简洁直接,不要套话

工具定义也非常直观:

// agent/tools/search_articles.ts
import { defineTool } from "eve/tools";
import { z } from "zod";

export default defineTool({
  description: "搜索技术文章数据库",
  inputSchema: z.object({
    query: z.string().min(1).describe("搜索关键词"),
    limit: z.number().min(1).max(50).optional().describe("返回数量"),
  }),
  async execute({ query, limit = 10 }) {
    const results = await articleDB.search(query, limit);
    return {
      articles: results.map((r) => ({
        id: r.id,
        title: r.title,
        summary: r.summary,
        url: r.url,
      })),
    };
  },
});

Agent 配置:

// agent/agent.ts
import { defineAgent } from "eve";

export default defineAgent({
  model: "anthropic/claude-sonnet-4.5",
  // 可以覆盖运行时配置
  // maxSteps: 20,
  // temperature: 0.7,
});

5.3 Skills:按需加载的技能

这是 eve 最独特的设计之一。Skills 是 Markdown 文件,定义了 Agent 可以"按需加载"的能力——类似于 Claude Code 的 SKILL.md 概念:

<!-- agent/skills/code_review.md -->
# 代码审查技能

当用户要求代码审查时,使用以下流程:

1. 阅读目标代码文件
2. 检查以下维度:
   - 代码风格一致性
   - 潜在的 bug 和安全问题
   - 性能优化建议
   - 可维护性
3. 输出审查报告,包含:
   - 严重程度分级(Critical/Warning/Info)
   - 具体的修改建议和代码示例
   - 优先级排序

5.4 多通道支持

Agent 可以同时接入多个消息通道:

// agent/channels/slack.ts
import { defineChannel } from "eve/channels";

export default defineChannel({
  type: "slack",
  name: "团队通知频道",
  botToken: process.env.SLACK_BOT_TOKEN,
  channelId: process.env.SLACK_CHANNEL_ID,
});

// agent/channels/http.ts
import { defineChannel } from "eve/channels";

export default defineChannel({
  type: "http",
  port: 3000,
});

5.5 定时任务

// agent/schedules/weekly_recap.ts
import { defineSchedule } from "eve/schedules";

export default defineSchedule({
  name: "weekly-recap",
  cron: "0 9 * * 1", // 每周一上午 9 点
  description: "生成上周技术总结报告",
});

5.6 eve 的核心优势

  1. 零学习成本的约定式开发:不需要学习复杂的框架 API,只需要按约定创建文件
  2. 可检查性:所有 Agent 能力都显式存在于文件系统中,任何团队成员都可以直接查看
  3. 可扩展性:工具、技能、通道、调度器都是独立模块,按需添加
  4. AI 友好:eve 包自带完整文档,Claude Code 等编程 Agent 可以直接从 node_modules/eve/docs 读取文档进行辅助开发
  5. Durable:Agent 状态持久化,支持从失败点恢复

六、Mastra:Gatsby 团队的全栈 AI Agent 框架

Mastra 是另一个值得关注的生态项目。它来自 Gatsby 团队,是一个功能全面的全栈 AI Agent 框架,GitHub 上已有 15000+ commits,活跃度极高。

6.1 核心特性

Mastra 的设计更加"重量级",适合构建复杂的 AI 应用:

import { Mastra } from "@mastra/core";

const mastra = new Mastra({
  workflows: {
    customerSupport: customerSupportWorkflow,
    dataAnalysis: dataAnalysisWorkflow,
  },
  agents: {
    supportAgent: supportAgent,
    analystAgent: analystAgent,
  },
  tools: {
    searchDB: searchDBTool,
    sendNotification: sendNotificationTool,
  },
});

6.2 Workflow 编排

Mastra 提供了强大的 Workflow 引擎,适合复杂的业务流程编排:

import { Workflow } from "@mastra/core/workflow";

const supportWorkflow = new Workflow({
  name: "customer-support",
  steps: [
    {
      id: "classify",
      execute: async ({ context }) => {
        // 分类用户问题
        const category = await classifyTicket(context.ticket);
        return { category };
      },
    },
    {
      id: "route",
      execute: async ({ context }) => {
        // 根据分类路由到不同处理流程
        if (context.category === "technical") {
          return { assignee: "tech-team" };
        }
        return { assignee: "general-team" };
      },
    },
    {
      id: "respond",
      execute: async ({ context }) => {
        // 生成回复
        const response = await generateResponse(context.ticket, context.category);
        await sendEmail(context.ticket.email, response);
        return { responseSent: true };
      },
    },
  ],
});

Mastra 和 eve 的定位不同:eve 是轻量级的、约定式的 Agent 框架,适合快速构建个人/小团队的 AI Agent;Mastra 是全栈的、功能完整的 AI 应用框架,适合构建企业级 AI 产品。


七、生产级实践:从开发到部署

7.1 多模型策略:降低成本的同时保证质量

生产环境中,不同任务应该用不同的模型:

// 简单任务用便宜模型
const fastModel = "anthropic/claude-haiku-4";
// 复杂推理用强模型
const smartModel = "anthropic/claude-sonnet-4.5";
// 最高要求用最强模型
const topModel = "anthropic/claude-opus-4";

async function processRequest(request: Request) {
  // 简单查询用 Haiku
  if (request.type === "simple_query") {
    return generateText({ model: fastModel, prompt: request.prompt });
  }

  // 复杂分析用 Sonnet
  if (request.type === "analysis") {
    return generateText({ model: smartModel, prompt: request.prompt });
  }

  // 关键决策用 Opus
  return generateText({ model: topModel, prompt: request.prompt });
}

通过 prepareStep 实现动态模型切换:

const result = await generateText({
  model: smartModel, // 默认模型
  tools: { search, analyze, summarize },
  stopWhen: stepCountIs(10),
  prompt: "深度分析这份报告",

  prepareStep: async ({ stepNumber, steps }) => {
    // 前两步用强模型做搜索和分析
    if (stepNumber < 2) return { model: smartModel };

    // 后续步骤用便宜模型做整合和总结
    return { model: fastModel };
  },
});

7.2 成本监控与限制

async function generateWithBudget(prompt: string, maxTokens: number) {
  const result = await generateText({
    model: "anthropic/claude-sonnet-4.5",
    prompt,
    maxTokens, // 限制最大输出 token
    onFinish({ totalUsage }) {
      const inputCost = (totalUsage.promptTokens / 1_000_000) * 3;   // $3/M
      const outputCost = (totalUsage.completionTokens / 1_000_000) * 15; // $15/M
      const totalCost = inputCost + outputCost;

      if (totalCost > 0.5) { // 单次请求超过 $0.5 告警
        alert(`本次请求成本 $${totalCost.toFixed(4)}`);
      }

      metrics.gauge("ai.cost.usd", totalCost);
      metrics.counter("ai.tokens.prompt", totalUsage.promptTokens);
      metrics.counter("ai.tokens.completion", totalUsage.completionTokens);
    },
  });

  return result;
}

7.3 消息历史管理

import { generateText, type ModelMessage } from "ai";

class ConversationManager {
  private messages: ModelMessage[] = [];
  private maxTokens: number;

  constructor(maxTokens = 100_000) {
    this.maxTokens = maxTokens;
  }

  async addAndGenerate(userMessage: string): Promise<string> {
    this.messages.push({ role: "user", content: userMessage });

    // 压缩过长的消息历史
    const compressed = await this.compressHistory();
    if (compressed) {
      this.messages = compressed;
    }

    const result = await generateText({
      model: "anthropic/claude-sonnet-4.5",
      messages: this.messages,
      tools: { /* ... */ },
    });

    // 追加 Assistant 消息到历史
    this.messages.push(...result.response.messages);

    return result.text;
  }

  private async compressHistory(): Promise<ModelMessage[] | null> {
    if (this.messages.length <= 10) return null;

    // 保留系统消息和最近 5 轮对话
    const recent = this.messages.slice(-10);
    return recent;
  }
}

7.4 错误处理与重试策略

import { generateText } from "ai";

async function reliableGenerate(params: Parameters<typeof generateText>[0]) {
  const MAX_RETRIES = 3;
  const RETRY_DELAY_MS = [1000, 2000, 4000]; // 指数退避

  for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
    try {
      return await generateText(params);
    } catch (error) {
      const isRetryable = error instanceof Error && (
        error.message.includes("rate_limit") ||
        error.message.includes("timeout") ||
        error.message.includes("529") ||
        error.message.includes("503")
      );

      if (!isRetryable || attempt === MAX_RETRIES - 1) {
        throw error;
      }

      await new Promise(resolve =>
        setTimeout(resolve, RETRY_DELAY_MS[attempt])
      );
    }
  }
}

7.5 部署架构

Next.js App Router 方案(推荐)

next-app/
├── app/
│   └── api/
│       └── chat/
│           └── route.ts      # streamText API
├── components/
│   ├── ChatWindow.tsx        # useChat 集成
│   └── ToolResultCard.tsx    # Generative UI 组件
└── lib/
    ├── tools/
    │   ├── search.ts
    │   └── database.ts
    └── prompts/
        └── system.ts

API Route 示例:

// app/api/chat/route.ts
import { streamText } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { searchTool, databaseTool } from "@/lib/tools";

export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = streamText({
    model: anthropic("claude-sonnet-4.5"),
    system: "你是一个技术助手,擅长编程和架构设计。",
    messages,
    tools: {
      search: searchTool,
      database: databaseTool,
    },
    stopWhen: stepCountIs(10),
    maxTokens: 4096,
    onError({ error }) {
      console.error("Stream error:", error);
    },
    onFinish({ totalUsage }) {
      // 记录使用量
      console.log(`Tokens: ${JSON.stringify(totalUsage)}`);
    },
  });

  return result.toUIMessageStreamResponse();
}

7.6 可观测性:与 Langfuse / OpenInference 集成

AI SDK 可以与 Langfuse 等可观测性平台无缝集成,实现 LLM 应用的全链路追踪:

// 使用 OpenTelemetry Instrumentation
import { instrument } from "ai-observability/openinference";
import { Langfuse } from "langfuse";

// 初始化 Langfuse
const langfuse = new Langfuse({
  publicKey: process.env.LANGFUSE_PUBLIC_KEY,
  secretKey: process.env.LANGFUSE_SECRET_KEY,
  baseUrl: "https://cloud.langfuse.com",
});

// AI SDK 自动采集 span 数据
const result = await generateText({
  model: "anthropic/claude-sonnet-4.5",
  prompt: "分析这段代码",
  experimental_trace: {
    name: "code-analysis",
    metadata: {
      userId: "user-123",
      sessionId: "session-456",
    },
  },
  tools: { /* ... */ },
});

八、Vercel AI SDK vs 其他框架的对比

维度Vercel AI SDKLangChainPydantic AIMastra
语言TypeScriptPython/JSPythonTypeScript
核心定位统一模型调用层全链路 AI 框架类型安全 Agent全栈 AI 应用
学习曲线中高
流式支持原生优秀一般良好良好
类型安全原生 TypeScript原生 Python原生 TypeScript
工具调用统一抽象繁琐简洁灵活
前端集成useChat/useCompletion需自行实现无内置有基础支持
多模型支持优秀良好良好良好
Agent 循环stopWhen 机制AgentExecutorLoopWorkflow
生产就绪高(Vercel 背书)中高
社区活跃度极高

选择建议:

  • TypeScript 开发者:首选 Vercel AI SDK + eve/Mastra
  • Python 开发者:首选 Pydantic AI(类型安全)或 LangChain(生态全面)
  • 全栈 AI 应用:Mastra 提供最完整的方案
  • 快速构建 Agent:eve 的约定式开发效率最高

九、完整实战:构建一个技术文章研究 Agent

让我们把所有知识串联起来,构建一个完整的技术文章研究 Agent:

9.1 项目结构

article-researcher/
├── agent/
│   ├── agent.ts
│   ├── instructions.md
│   ├── tools/
│   │   ├── search_web.ts
│   │   ├── search_github.ts
│   │   ├── read_article.ts
│   │   ├── analyze_code.ts
│   │   └── generate_outline.ts
│   └── skills/
│       ├── technical_writing.md
│       └── trend_analysis.md
├── package.json
└── tsconfig.json

9.2 核心实现

// agent/agent.ts
import { defineAgent } from "eve";

export default defineAgent({
  model: "anthropic/claude-sonnet-4.5",
});
<!-- agent/instructions.md -->
你是一个技术文章研究助手。你的任务是:

1. 搜索最新技术趋势和热门开源项目
2. 分析技术文章的质量和深度
3. 生成高质量的技术文章大纲

工作流程:
1. 先用 search_web 搜索相关主题
2. 用 search_github 查找相关开源项目
3. 用 read_article 阅读重点文章
4. 用 analyze_code 分析关键代码
5. 最后用 generate_outline 生成文章大纲

输出要求:
- 中文
- 结构化的 Markdown 格式
- 包含代码示例
- 标注参考资料来源
// agent/tools/search_web.ts
import { defineTool } from "eve/tools";
import { z } from "zod";

export default defineTool({
  description: "搜索技术文章和最新资讯",
  inputSchema: z.object({
    query: z.string().min(1).describe("搜索关键词"),
    freshness: z.enum(["day", "week", "month"]).optional()
      .describe("时间范围"),
    count: z.number().min(1).max(20).optional()
      .describe("返回结果数量"),
  }),
  async execute({ query, freshness = "week", count = 10 }) {
    const results = await searchService.search({
      query,
      freshness,
      count,
    });
    return {
      results: results.map((r) => ({
        title: r.title,
        url: r.url,
        snippet: r.snippet,
        publishedAt: r.publishedAt,
      })),
    };
  },
});
// agent/tools/search_github.ts
import { defineTool } from "eve/tools";
import { z } from "zod";

export default defineTool({
  description: "搜索 GitHub 上的热门开源项目",
  inputSchema: z.object({
    topic: z.string().describe("搜索主题"),
    sort: z.enum(["stars", "updated", "forks"]).optional()
      .describe("排序方式"),
    language: z.string().optional().describe("编程语言"),
  }),
  async execute({ topic, sort = "stars", language }) {
    const results = await github.search({
      q: `${topic}${language ? ` language:${language}` : ""}`,
      sort,
      order: "desc",
      per_page: 10,
    });
    return {
      repos: results.items.map((r) => ({
        name: r.full_name,
        description: r.description,
        stars: r.stargazers_count,
        forks: r.forks_count,
        url: r.html_url,
        language: r.language,
        updatedAt: r.updated_at,
      })),
    };
  },
});
// agent/tools/generate_outline.ts
import { defineTool } from "eve/tools";
import { z } from "zod";

export default defineTool({
  description: "基于收集的信息生成技术文章大纲",
  inputSchema: z.object({
    title: z.string().describe("文章标题"),
    keyPoints: z.array(z.string()).describe("核心要点"),
    targetAudience: z.enum(["beginner", "intermediate", "advanced"])
      .describe("目标读者"),
    estimatedWords: z.number().describe("预估字数"),
  }),
  async execute({ title, keyPoints, targetAudience, estimatedWords }) => {
    const outline = await generateText({
      model: "anthropic/claude-sonnet-4.5",
      prompt: `为以下文章生成详细大纲:

标题:${title}
核心要点:${keyPoints.join("、")}
目标读者:${targetAudience}
预估字数:${estimatedWords}

要求:
1. 每个章节都要有明确的技术要点
2. 标注需要代码示例的位置
3. 包含实战案例
4. 输出 Markdown 格式`,
    });
    return { outline: outline.text };
  },
});

十、总结与展望

10.1 核心价值

Vercel AI SDK + eve 生态在 2026 年提供的核心价值可以总结为:

  1. 统一模型层:一套代码对接所有大模型,消除模型切换的工程负担
  2. 类型安全的工具调用:Zod schema + TypeScript,从定义到执行全链路类型安全
  3. 多步 Agent 循环:stopWhen + prepareStep,精细控制 Agent 行为
  4. 安全审批机制:敏感操作人工确认,平衡自动化与安全性
  5. 前端深度集成:useChat / useCompletion / Generative UI,开箱即用的前端体验
  6. 约定式 Agent 开发:eve 的文件系统约定,让 Agent 开发回归简单
  7. 全栈覆盖:从 Core 到 UI 到 eve 到 Mastra,覆盖从简单到复杂的全场景

10.2 2026 下半年值得关注的趋势

  1. eve 正式版发布:目前处于 beta,正式版可能会带来更多企业级特性
  2. AI SDK 5.0 规划:更强大的 Agent 编排能力、更完善的可观测性
  3. 跨框架协作标准:OpenTelemetry + OpenInference 统一 LLM 应用的可观测性
  4. 成本优化:更多模型提供商支持、更智能的模型路由策略
  5. 边缘 AI:Cloudflare Workers、Vercel Edge Runtime 上的轻量 AI Agent

10.3 给开发者的建议

  1. 如果你刚开始 AI Agent 开发:从 Vercel AI SDK Core 开始,先掌握 generateText + tool calling,再逐步接触 streamText 和 AI SDK UI。
  2. 如果你在构建生产级聊天应用:直接使用 AI SDK UI 的 useChat,配合 Next.js App Router。
  3. 如果你在构建独立的 AI Agent:尝试 eve 的约定式开发,体验零配置的快感。
  4. 如果你在构建企业级 AI 产品:考虑 Mastra 的全栈方案,利用其 Workflow 编排和多 Agent 协作。
  5. 无论哪种场景:都要重视可观测性——AI 应用不同于传统软件,其行为具有一定的不确定性,需要更完善的监控和追踪体系。

2026 年是 AI Agent 工程化的元年。Vercel AI SDK 生态正在为 TypeScript 开发者铺就一条从简单到大复杂的完整路径。不管你是要构建一个简单的聊天机器人,还是一个复杂的多 Agent 协作系统,这套工具链都值得一试。

记住一句话:AI 的价值不在模型本身,而在你能用模型构建什么样的应用。Vercel AI SDK 给你的,正是构建应用的脚手架。

推荐文章

`Blob` 与 `File` 的关系
2025-05-11 23:45:58 +0800 CST
CSS 奇技淫巧
2024-11-19 08:34:21 +0800 CST
防止 macOS 生成 .DS_Store 文件
2024-11-19 07:39:27 +0800 CST
Vue3 vue-office 插件实现 Word 预览
2024-11-19 02:19:34 +0800 CST
宝塔面板 Nginx 服务管理命令
2024-11-18 17:26:26 +0800 CST
初学者的 Rust Web 开发指南
2024-11-18 10:51:35 +0800 CST
程序员茄子在线接单