Chapter 03

Agent 与模型:一套 API 跑遍所有 LLM

Agent 是 Mastra 的原子——它封装了 instructions、model、tools 三要素。模型层复用 Vercel AI SDK 的 provider 抽象,OpenAI / Anthropic / Google / Ollama / OpenRouter 一行代码切换。

Agent 的三要素

instructions
System prompt,描述角色、行为边界、输出风格。可写成函数,每次调用动态生成(比如注入用户信息、当前时间)。
model
AI SDK 的 LanguageModel 实例。由 provider 工厂函数产生,例如 openai('gpt-4o')anthropic('claude-sonnet-4-6')
tools
可选。Agent 被允许调用的工具集。没有 tool 就是纯对话 Agent。

完整 Agent 构造签名

new Agent({
  name: string,                          // 唯一标识,Playground 显示
  instructions: string | (ctx) => string, // 静态或动态
  model: LanguageModel,                  // AI SDK provider 返回
  tools?: Record<string, Tool>,          // 静态或 (ctx) => tools
  memory?: Memory,                       // 第6章详说
  defaultGenerateOptions?: {             // 默认生成参数
    maxSteps: number,                   // tool 循环上限
    temperature: number,
  },
  voice?: CompositeVoice,                // TTS/STT,可选
  evals?: Record<string, Metric>,         // 第8章
})

AI SDK Provider 一览

Provider 包典型用法代表模型
@ai-sdk/openaiopenai('gpt-4o')GPT-4o、GPT-4o-mini、o1
@ai-sdk/anthropicanthropic('claude-sonnet-4-6')Claude Opus/Sonnet/Haiku
@ai-sdk/googlegoogle('gemini-2.0-flash')Gemini 系列
@ai-sdk/mistralmistral('mistral-large')Mistral / Codestral
@ai-sdk/groqgroq('llama-3.3-70b')Groq 托管的开源模型,极快
ollama-ai-providerollama('llama3.2')本地跑任意 Ollama 模型
@openrouter/ai-sdk-provideropenrouter('anthropic/claude-sonnet-4-6')一个 key 连 200+ 模型

示例:同一 Agent 切 3 家模型

import { Agent } from '@mastra/core/agent';
import { openai } from '@ai-sdk/openai';
import { anthropic } from '@ai-sdk/anthropic';
import { createOllama } from 'ollama-ai-provider';

const ollama = createOllama({ baseURL: 'http://localhost:11434/api' });

// 同一套 instructions,三种模型
const common = {
  name: 'translator',
  instructions: '把输入翻译成地道中文,不加任何解释。',
};

export const gpt = new Agent({ ...common, model: openai('gpt-4o-mini') });
export const claude = new Agent({ ...common, model: anthropic('claude-haiku-4-5-20251001') });
export const local = new Agent({ ...common, model: ollama('qwen2.5:7b') });

注册到 Mastra 实例后,Playground 左侧会出现三个 Agent 卡片,可以并排对比同一问题在不同模型上的输出。

动态 instructions

import { Agent } from '@mastra/core/agent';

export const reportAgent = new Agent({
  name: 'report',
  instructions: async ({ runtimeContext }) => {
    const user = runtimeContext.get('user');
    return `你为 ${user.name}(${user.role})写日报,
      保留 ${user.language},结构:今日完成/明日计划/风险。`;
  },
  model: openai('gpt-4o-mini'),
});

// 调用时注入上下文
await reportAgent.generate('生成日报', {
  runtimeContext: new RuntimeContext([
    ['user', { name: '老王', role: '前端', language: '中文' }],
  ]),
});

动态选模型

根据用户等级、任务难度、成本预算,同一 Agent 可以在运行时决定用哪个模型:

export const smart = new Agent({
  name: 'adaptive',
  instructions: '精准回答用户技术问题',
  model: ({ runtimeContext }) => {
    const tier = runtimeContext.get('tier');
    if (tier === 'pro') return anthropic('claude-opus-4-7');
    if (tier === 'plus') return openai('gpt-4o');
    return openai('gpt-4o-mini');  // free
  },
});

generate vs stream vs generateObject

agent.generate(input, opts?)
一次性返回 { text, toolCalls, toolResults, usage, finishReason }。适合后端任务、批处理。
agent.stream(input, opts?)
返回 textStreamfullStream 两种异步迭代器。配合 SSE/WebSocket 给前端推字。
agent.generate(input, { output: schema })
传入 Zod schema,返回严格类型化 JSON。底层用模型的 structured output 能力。
import { z } from 'zod';

const { object } = await agent.generate('分析这份代码的风险', {
  output: z.object({
    riskLevel: z.enum(['low', 'medium', 'high']),
    issues: z.array(z.string()),
    suggestion: z.string(),
  }),
});

// object 已经是类型安全的对象,ts 自动推断
console.log(object.riskLevel);

本地模型:Ollama 实战

# 1. 安装 Ollama(macOS)
brew install ollama
ollama serve &
ollama pull qwen2.5:7b

# 2. 安装 provider
pnpm add ollama-ai-provider
import { createOllama } from 'ollama-ai-provider';

const ollama = createOllama({
  baseURL: 'http://localhost:11434/api',
});

export const localAgent = new Agent({
  name: 'local',
  instructions: '用中文回答',
  model: ollama('qwen2.5:7b'),
});
本地模型的局限
7B 小模型 tool calling 能力普遍弱,遇到复杂 tool 组合易出 schema 错误。生产上建议 14B+ 或直接用云端模型,本地模型先做开发隔离、离线演示。

OpenRouter:一个 key 连所有模型

import { createOpenRouter } from '@openrouter/ai-sdk-provider';

const openrouter = createOpenRouter({
  apiKey: process.env.OPENROUTER_API_KEY!,
});

export const haiku = new Agent({
  name: 'haiku',
  instructions: '写 5-7-5 俳句',
  model: openrouter('anthropic/claude-haiku-4-5'),
});

// 切 DeepSeek 只改一行
export const deepseek = new Agent({
  name: 'haiku-ds',
  instructions: '写 5-7-5 俳句',
  model: openrouter('deepseek/deepseek-r1'),
});

模型能力差异与选型

能力推荐模型备注
复杂 tool 组合Claude Sonnet 4.6+、GPT-4o多步推理稳
长上下文(>200k)Claude(200k)、Gemini(1M)RAG 可少分段
低成本/高吞吐GPT-4o-mini、Haiku、Gemini Flash日志分类、摘要够用
数学/推理o1、DeepSeek-R1慢但准
中文创作Claude、Qwen2.5、DeepSeek英文模型中文腔重
Structured OutputGPT-4o、Claude Sonnet 4.6+严格 JSON

错误处理与重试

try {
  const { text } = await agent.generate(input, {
    maxRetries: 3,
    abortSignal: AbortSignal.timeout(30_000),
  });
} catch (e) {
  if (e.name === 'AI_APICallError') {
    // 401/429/5xx 都归在这里
    console.error(e.statusCode, e.url);
  }
  if (e.name === 'AbortError') {
    console.error('超时');
  }
}

本章小结