1. 从零到一:为什么选择 Mastra 来构建你的 AI 应用?
如果你正在用 TypeScript 栈开发 AI 应用,并且已经尝试过直接调用 OpenAI 的 API 或者用 LangChain 搭过一些原型,那你大概率会遇到几个绕不开的痛点:模型切换成本高、Agent 状态管理混乱、复杂业务流程难以编排、生产环境下的可观测性几乎为零。每次想换个模型试试效果,都得改一堆代码;想做个多步骤的、带条件判断的 AI 流程,写着写着就变成了一团难以维护的回调地狱;更别提想把一个在本地跑得挺好的 AI 助手部署上线,还要考虑对话历史存储、工具调用权限、执行链路追踪这些“脏活累活”。
Mastra 的出现,就是为了系统性地解决这些问题。它不是一个简单的 SDK 封装,而是一个为 TypeScript 量身定制的、生产就绪的 AI 应用框架。它的核心设计哲学是“约定优于配置”和“渐进式复杂度”,让你能用最直观的方式从快速原型过渡到健壮的生产系统。我最初接触它,是因为厌倦了在不同 AI 项目间复制粘贴相似的胶水代码。用了 Mastra 之后,最大的感受是:它把那些重复的、容易出错的底层抽象(如模型路由、记忆管理、工作流引擎)都做成了开箱即用的模块,开发者可以更专注于业务逻辑和 AI 能力本身。
简单来说,Mastra 帮你做了三件关键事:
- 统一入口:通过一个标准接口连接 40+ 家模型提供商,让你在 OpenAI GPT-4、Anthropic Claude、Google Gemini 甚至开源模型间无缝切换,成本控制和效果对比变得异常简单。
- 提供两种核心范式:对于开放性的、需要“思考”的任务,用Agent;对于确定性的、多步骤的流程,用Workflow。这两种范式覆盖了绝大多数 AI 应用场景。
- 内置生产工具:从开发阶段的评估(Evals)到上线后的可观测性(Observability),再到关键的人类介入(Human-in-the-loop)和状态持久化,它都提供了原生支持。
接下来,我会以一个实际的“智能客服工单处理助手”为例,带你深入 Mastra 的各个核心模块,拆解其设计思路、实操步骤,并分享我在构建过程中踩过的坑和总结的经验。
2. 核心概念与架构设计解析
在动手写代码之前,理解 Mastra 的几个核心抽象至关重要。这能帮你建立正确的心智模型,知道该在什么地方用什么功能。
2.1 Agent vs. Workflow:如何选择?
这是 Mastra 里最根本的决策点。很多新手会混淆两者,导致架构设计不合理。
Agent(智能体):可以理解为一个自主的、目标驱动的“大脑”。你给它一个目标(比如“分析这份用户反馈并总结核心问题”),它会自行规划步骤、调用工具(如搜索数据库、调用 API)、进行多轮“思考”(Chain-of-Thought),直到达成目标或满足停止条件。Agent 适合处理非结构化、探索性的任务,其执行路径在运行时才确定。
- 适用场景:开放式问答、复杂问题分析、创意生成、需要多步推理的决策。
- Mastra 实现:通过
createAgent函数定义,核心是配置其使用的 LLM、可用的工具(Tools)、记忆系统以及停止条件。
Workflow(工作流):则是一个预定义的、图结构的执行流程。它像一张流程图,节点是具体的操作(调用 LLM、运行函数、条件判断),边定义了执行顺序和条件分支。Workflow 适合处理结构化、确定性高的业务流程。
- 适用场景:用户注册审核流程、电商订单状态跟踪、数据提取与格式化管道、需要严格步骤控制的自动化任务。
- Mastra 实现:使用
createWorkflow定义,通过.then(),.branch(),.parallel()等链式调用或更直观的defineGraph方式来编排步骤。
选择心法:问自己一个问题——“这个任务的步骤和判断逻辑,我能在写代码时就基本确定吗?”如果能,用 Workflow;如果不能,或者希望 AI 自己决定怎么做,就用 Agent。在我们的工单处理例子中,“将用户问题分类”可以用一个简单的分类 Agent;“根据分类执行一系列固定操作(如查询知识库、生成回复模板、转交人工)”则更适合用 Workflow 来编排。
2.2 上下文管理:让 AI 拥有记忆和知识
一个健壮的 AI 应用不能是“金鱼脑”(只有7秒记忆)。Mastra 的上下文管理分为几个层次:
对话历史:最基础的记忆,存储用户与 AI 的多轮对话。Mastra 内置了对话历史管理,会自动处理上下文窗口的截断(比如只保留最近 N 轮或 N 个 Token 的对话),你无需手动拼接
messages数组。工作记忆:这是 Agent 的“便签纸”。在单次任务执行过程中,Agent 可以将中间结论、思考过程暂存于此,供后续步骤参考。这模拟了人类的短期记忆,对于复杂推理任务至关重要。
语义记忆/向量检索:这是 AI 的“长期知识库”。你可以将文档、数据库记录等转换成向量存入向量数据库(如 Pinecone、Weaviate)。当用户提问时,Mastra 能自动检索相关片段作为上下文注入给 LLM。这就是 RAG 的核心能力,Mastra 将其流程封装得非常简洁。
状态存储:对于 Workflow 和可挂起的 Agent,Mastra 需要将执行状态(进行到哪一步、中间变量是什么)持久化到数据库。它支持多种存储后端(如 PostgreSQL、SQLite),确保即使服务重启,也能从断点恢复。
实操提示:在定义 Agent 时,通过memory配置项灵活组合这些记忆类型。对于客服助手,通常需要“对话历史” + “语义记忆(知识库)”。配置语义记忆时,注意分块(Chunking)策略和检索数量(top-K)对效果和成本的影响。块太大,信息可能不精准;块太小,可能丢失上下文。通常从 500-1000 字符的块大小和检索 top-3 开始调试。
2.3 工具与 MCP:扩展 AI 的行动边界
Agent 的强大之处在于能使用工具。Mastra 中的工具就是普通的 TypeScript 异步函数,但需要用createTool函数进行包装,以提供名称、描述和参数模式(遵循 Zod Schema)。LLM 会根据描述决定是否以及如何调用它。
高级特性:MCP(模型上下文协议)服务器。这是 Mastra 的一个亮点。你可以将一组工具、数据源甚至其他 Agent 打包成一个 MCP 服务器。这个服务器可以被任何支持 MCP 协议的客户端(如某些 AI 桌面应用)使用。这意味着,你用 Mastra 为内部系统开发的 AI 能力,可以轻松暴露给更广泛的生态。例如,为客服系统开发的“工单查询工具”,通过 MCP 服务器,也能被公司的数据分析助手直接调用。
3. 实战:构建智能工单处理系统
让我们把理论付诸实践。假设我们要构建一个系统:用户提交文本工单,AI 自动分类、检索知识库尝试解答,若置信度低则挂起流程等待人工审核。
3.1 项目初始化与环境搭建
首先,使用官方推荐的方式创建项目:
npm create mastra@latest my-support-agent cd my-support-agent npm install这会产生一个结构清晰的项目骨架。关键目录:
src/agents/:存放 Agent 定义。src/workflows/:存放 Workflow 定义。src/tools/:存放工具函数。src/index.ts:应用主入口。mastra.config.ts:全局配置文件(模型、存储、内存等)。
接下来,配置mastra.config.ts。这是核心配置文件,我建议将不同环境的配置分离(如mastra.config.dev.ts和mastra.config.prod.ts),通过环境变量切换。
// mastra.config.ts import { defineConfig } from '@mastra/core'; import { openai } from '@ai-sdk/openai'; import { memoryStorage } from '@mastra/core/storage'; export default defineConfig({ // 1. 模型提供商配置:这里使用 OpenAI,但可以轻松切换 llm: { providers: { openai: openai({ apiKey: process.env.OPENAI_API_KEY!, }), // 可以同时配置 anthropic, google 等 }, // 默认模型,也可以在每个 Agent 单独指定 defaultModel: 'openai:gpt-4o-mini', }, // 2. 存储配置:用于持久化 Workflow 状态和记忆 storage: memoryStorage(), // 开发用内存存储,生产需换为 postgresStorage 等 // 3. 日志与可观测性配置 observability: { enabled: true, // 可配置输出到控制台、文件或 OpenTelemetry 收集器 }, });注意:
memoryStorage仅用于开发和测试,因为它不会持久化数据,服务重启后状态全丢。生产环境务必使用如postgresStorage等持久化存储。切换时,只需修改配置,业务代码通常无需改动,这体现了框架抽象的价值。
3.2 创建核心工具
工具是 Agent 的手和脚。我们先创建两个工具:一个查询内部知识库,一个创建待人工审核的工单。
// src/tools/search-knowledge-base.ts import { createTool } from '@mastra/core'; import { z } from 'zod'; // 假设有一个知识库服务客户端 import { knowledgeBaseClient } from '../lib/kb-client'; export const searchKBTool = createTool({ id: 'search_knowledge_base', description: '在内部知识库中搜索与用户问题相关的解决方案文章。', inputSchema: z.object({ query: z.string().describe('用户的原始问题或关键词'), maxResults: z.number().default(3).describe('返回的最大结果数'), }), outputSchema: z.array( z.object({ title: z.string(), content: z.string(), relevanceScore: z.number(), }) ), async execute({ query, maxResults }) { // 这里是模拟的搜索逻辑,实际应调用你的向量数据库或搜索服务 console.log(`正在知识库中搜索: "${query}"`); const results = await knowledgeBaseClient.semanticSearch(query, { limit: maxResults }); // 确保返回格式符合 outputSchema 定义 return results.map(r => ({ title: r.title, content: r.contentSnippet, relevanceScore: r.score, })); }, });// src/tools/create-manual-ticket.ts import { createTool } from '@mastra/core'; import { z } from 'zod'; import { ticketService } from '../lib/ticket-service'; export const createManualTicketTool = createTool({ id: 'create_manual_ticket', description: '当AI无法自信地解决问题时,创建一个待人工客服处理的工单。', inputSchema: z.object({ customerId: z.string(), originalQuery: z.string(), aiAnalysis: z.string().describe('AI对问题的分析和已尝试的步骤'), urgency: z.enum(['low', 'medium', 'high']).default('medium'), }), outputSchema: z.object({ ticketId: z.string(), message: z.string(), }), async execute({ customerId, originalQuery, aiAnalysis, urgency }) { const ticket = await ticketService.create({ customerId, title: `AI转交: ${originalQuery.substring(0, 50)}...`, description: `用户问题: ${originalQuery}\n\nAI分析: ${aiAnalysis}`, status: 'pending', priority: urgency, assignedTo: null, // 等待人工分配 }); return { ticketId: ticket.id, message: `已创建人工工单 #${ticket.id},客服团队将尽快处理。`, }; }, });工具设计心得:
- 描述要精准:
description字段是 LLM 决定是否调用该工具的关键。要用自然语言清晰说明工具的用途、适用场景和输入参数的意义。 - Schema 是契约:使用 Zod 定义输入输出 Schema,这不仅是类型安全,Mastra 和 LLM 都会利用这些信息。
describe方法可以进一步注释每个字段,帮助 LLM 理解。 - 工具要幂等:尽可能让工具的执行是幂等的,避免因 LLM 重复调用导致副作用(如重复创建工单)。可以在工具内部实现简单的去重逻辑。
3.3 构建分类 Agent
这个 Agent 负责判断用户问题的类型和紧急程度。
// src/agents/classifier.agent.ts import { createAgent } from '@mastra/core'; import { z } from 'zod'; export const classifierAgent = createAgent({ name: 'ticket_classifier', instructions: `你是一个工单分类专家。请分析用户提交的问题,判断其所属类别和紧急程度。 类别包括:账单问题、技术故障、功能咨询、账户管理、投诉建议、其他。 紧急程度分为:low(可延迟处理)、medium(正常)、high(需尽快响应)。 请仅输出JSON格式,不要有任何额外解释。`, model: 'openai:gpt-4o', // 分类任务对精度要求高,可以用更强模型 output: z.object({ category: z.enum(['billing', 'technical', 'inquiry', 'account', 'complaint', 'other']), urgency: z.enum(['low', 'medium', 'high']), confidence: z.number().min(0).max(1).describe('分类置信度'), keywords: z.array(z.string()).describe('从问题中提取的关键词'), }), }); // 这个Agent没有配置工具,它是一个纯分析型Agent。Agent 配置解析:
instructions:给 AI 的“角色设定”和任务指令。要具体、清晰,并约束输出格式。这里我们明确要求只输出 JSON。model:可以覆盖全局默认模型。对于关键任务,指定一个更可靠的模型是值得的。output:使用 Zod Schema 定义 Agent 的最终输出结构。这保证了输出类型的严格性,并方便后续 Workflow 节点消费。
3.4 构建解答与转交 Workflow
这是业务的核心流程,我们使用 Workflow 来编排。
// src/workflows/ticket-processing.workflow.ts import { createWorkflow } from '@mastra/core'; import { classifierAgent } from '../agents/classifier.agent'; import { searchKBTool, createManualTicketTool } from '../tools'; export const ticketProcessingWorkflow = createWorkflow({ id: 'ticket_processing', name: '智能工单处理流程', // 定义工作流的输入模式 inputSchema: z.object({ customerId: z.string(), customerQuery: z.string(), sessionId: z.string().optional(), // 用于关联对话历史 }), }, (workflow) => { const { customerId, customerQuery, sessionId } = workflow.input; // 步骤1:分类工单 const classification = workflow.addStep({ id: 'classify', description: '使用AI对工单进行分类和紧急度评估', execute: async () => { // 运行我们之前定义的分类Agent const result = await classifierAgent.generate({ messages: [{ role: 'user', content: customerQuery }], sessionId, // 传入sessionId以关联记忆(如果需要) }); return result.object; // 返回解析后的JSON对象 }, }); // 步骤2:基于分类结果,并行执行知识库检索和初步分析 const [kbSearch, initialAnalysis] = workflow.addParallelSteps([ { id: 'search_kb', description: '根据用户问题检索知识库', execute: async ({ context }) => { // 使用工具进行检索 const results = await searchKBTool.execute({ query: customerQuery, maxResults: 3, }); // 可以在这里对检索结果进行初步过滤,比如只保留相关性高于阈值的 const relevantResults = results.filter(r => r.relevanceScore > 0.7); return { relevantResults }; }, }, { id: 'initial_analysis', description: 'AI初步分析问题并生成草稿回复', execute: async ({ context }) => { // 这里可以调用另一个LLM,结合分类信息和原始问题生成回复草稿 // 为简化示例,我们直接返回一个模拟分析 return { draftResponse: `关于您提到的“${customerQuery}”,这属于${classification.category}类别。根据一般经验,可能的解决方案包括...`, confidence: 0.8, // 模拟一个置信度 }; }, }, ]); // 步骤3:决策点 - 是否需要人工介入? const decision = workflow.addStep({ id: 'make_decision', description: '根据检索结果和分析置信度,决定是自动回复还是转交人工', execute: async ({ context }) => { const hasRelevantKB = kbSearch.relevantResults.length > 0; const isHighConfidence = initialAnalysis.confidence > 0.85; const isHighUrgency = classification.urgency === 'high'; let action: 'auto_reply' | 'manual_ticket' | 'escalate'; let reason: string; if (hasRelevantKB && isHighConfidence) { action = 'auto_reply'; reason = '知识库有高相关性答案且AI分析置信度高。'; } else if (isHighUrgency) { // 高紧急度问题,即使AI有答案也转人工复核 action = 'escalate'; reason = '问题紧急度高,建议人工立即处理。'; } else { action = 'manual_ticket'; reason = '知识库答案不足或AI置信度较低,需人工处理。'; } return { action, reason, hasRelevantKB, isHighConfidence, isHighUrgency }; }, }); // 步骤4:分支执行 - 根据决策走不同路径 workflow.addBranch( decision, { // 分支1:自动回复 auto_reply: workflow.addStep({ id: 'generate_final_response', description: '整合知识库内容和分析,生成最终回复', execute: async ({ context }) => { // 这里可以调用一个专门的“回复生成Agent” const finalResponse = `根据您的“${classification.category}”问题,我们为您找到以下解决方案:\n${kbSearch.relevantResults[0]?.content}\n\n${initialAnalysis.draftResponse}`; return { finalResponse, resolved: true }; }, }), // 分支2:创建人工工单 manual_ticket: workflow.addStep({ id: 'create_ticket', description: '调用工具创建待处理的人工工单', execute: async ({ context }) => { const ticket = await createManualTicketTool.execute({ customerId, originalQuery: customerQuery, aiAnalysis: `分类: ${classification.category}, 紧急度: ${classification.urgency}. 知识库检索结果: ${kbSearch.relevantResults.length}条相关。初步分析置信度: ${initialAnalysis.confidence}.`, urgency: classification.urgency, }); return { ...ticket, resolved: false }; }, }), // 分支3:升级处理(高紧急度) escalate: workflow.addStep({ id: 'escalate_ticket', description: '创建高优先级人工工单并通知值班客服', execute: async ({ context }) => { const ticket = await createManualTicketTool.execute({ customerId, originalQuery: customerQuery, aiAnalysis: `[紧急]分类: ${classification.category}. ${decision.reason}`, urgency: 'high', }); // 模拟发送通知 console.log(`[警报] 高紧急度工单 #${ticket.ticketId} 已创建,请立即处理!`); return { ...ticket, resolved: false, escalated: true }; }, }), } ); // 定义工作流的最终输出(所有分支最终会汇聚) return workflow.complete({ outputSchema: z.object({ workflowId: z.string(), customerId: z.string(), actionTaken: z.string(), result: z.any(), // 根据分支不同,结果结构也不同 timestamp: z.string(), }), }); });Workflow 设计精要:
- 清晰的步骤定义:每个
addStep都应该有明确的id和description,这有助于调试和可观测性。 - 利用并行步骤:
addParallelSteps可以同时执行多个独立任务(如检索和分析),缩短整体耗时。 - 条件分支:
addBranch是实现业务逻辑的关键。它基于上一步的结果动态选择路径。Mastra 会负责状态管理和路径追踪。 - 输入输出模式化:Workflow 的
inputSchema和outputSchema提供了强类型约束,使得在大型项目中集成和测试更加可靠。
3.5 集成与运行:将 Workflow 暴露为 API
最后,我们需要一个入口来触发这个工作流。这里以 Next.js API Route 为例:
// app/api/ticket/route.ts (Next.js App Router) import { mastra } from '@/mastra'; // 你的Mastra实例 import { ticketProcessingWorkflow } from '@/workflows/ticket-processing.workflow'; import { NextRequest, NextResponse } from 'next/server'; export async function POST(request: NextRequest) { try { const { customerId, query } = await request.json(); if (!customerId || !query) { return NextResponse.json({ error: 'Missing customerId or query' }, { status: 400 }); } // 1. 启动工作流 const run = await mastra.workflows.start(ticketProcessingWorkflow, { input: { customerId, customerQuery: query, sessionId: request.headers.get('x-session-id'), // 可选,用于关联对话 }, }); // 2. 立即返回一个运行ID,支持异步轮询或Webhook return NextResponse.json({ workflowRunId: run.id, status: 'started', // 对于简单场景,也可以在这里等待完成(await run.output()),但会阻塞请求 _links: { status: `/api/ticket/status/${run.id}`, }, }, { status: 202 }); // 202 Accepted } catch (error) { console.error('Failed to start ticket workflow:', error); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } } // 状态查询端点 export async function GET(request: NextRequest, { params }: { params: { runId: string } }) { const run = await mastra.workflows.getRun(params.runId); if (!run) { return NextResponse.json({ error: 'Run not found' }, { status: 404 }); } return NextResponse.json({ runId: run.id, status: run.status, // 'running', 'completed', 'failed', 'suspended' output: run.output, // 完成后才有 error: run.error, }); }4. 生产环境进阶:可观测性、评估与调试
一个原型能跑起来只是第一步,要上线,必须解决“看得见”和“管得住”的问题。
4.1 利用内置可观测性
Mastra 的 Observability 模块会自动记录 Workflow 和 Agent 的每一次执行、每一个步骤、每一次工具调用以及对应的 LLM 请求和响应。在配置中启用后,你可以在控制台看到结构化的日志,也可以集成到如 OpenTelemetry 的体系中,将数据发送到 Jaeger、Datadog 等平台。
关键可观测数据:
- 执行追踪:整个 Workflow 的流程图,每个节点的状态(成功/失败/耗时)。
- LLM 调用详情:输入提示词、输出结果、Token 使用量、成本。
- 工具调用记录:输入参数、输出结果、执行时间。
- 错误堆栈:任何步骤失败时的详细错误信息。
在开发阶段,多查看这些日志,能帮你快速定位是提示词问题、工具错误还是逻辑缺陷。
4.2 实施评估(Evals)
Evals 是衡量 AI 应用表现的核心。Mastra 提供了框架来定义和运行评估。例如,对于我们的分类 Agent,可以定义如下评估:
// src/evals/classifier.eval.ts import { defineEval } from '@mastra/core/evals'; import { classifierAgent } from '../agents/classifier.agent'; export const classifierAccuracyEval = defineEval({ id: 'classifier_accuracy', dataset: [ { input: '我的账单金额不对,多扣了钱。', expected: { category: 'billing', urgency: 'high' } }, { input: '这个按钮点击了没反应。', expected: { category: 'technical', urgency: 'medium' } }, // ... 更多测试用例 ], async run({ input }) { const result = await classifierAgent.generate({ messages: [{ role: 'user', content: input }], }); return result.object; // 返回Agent的实际输出 }, grade({ output, expected }) { // 评分逻辑 let score = 0; if (output.category === expected.category) score += 0.7; if (output.urgency === expected.urgency) score += 0.3; return { score, passed: score > 0.8, // 自定义通过阈值 details: { predicted: output, expected }, }; }, });定期运行评估(可以集成到 CI/CD 流程中),可以监控 Agent 性能的波动,比如在切换模型版本后效果是否下降。
4.3 人类介入(Human-in-the-loop)
这是生产系统中不可或缺的安全网。Mastra 允许你在 Workflow 的任何步骤“挂起”(Suspend)执行,等待外部输入(如人工审核)。上面的 Workflow 示例中,我们可以在decision步骤后,如果决定auto_reply,不直接发送,而是先挂起,等待人工确认。
// 在Workflow中添加一个可挂起的步骤 const humanApprovalStep = workflow.addStep({ id: 'human_approval', description: '等待人工审核AI生成的回复', execute: async ({ context }) => { // 这里不会立即执行,而是将工作流状态持久化,并返回一个“挂起”信号 // 在实际中,你需要一个后台任务或API来检查是否有挂起的任务供人工处理 // Mastra 提供了 `workflow.suspend()` 和后续的 `workflow.resume()` 机制 // 此处为概念展示 const approvalResult = await waitForHumanApproval(workflow.id, context.draftResponse); return approvalResult; // { approved: boolean, feedback?: string } }, });实现时,你需要提供一个 UI 界面(如内部管理后台)来展示挂起的任务,让客服人员审核或修改 AI 的回复,然后调用一个 Resume API 来继续工作流。Mastra 的存储层会确保状态恢复。
5. 常见陷阱与性能优化实战记录
在真实项目中趟过一些坑,这里分享出来帮你避雷。
陷阱一:工具描述过于笼统或矛盾LLM 根据工具描述来决定调用。如果描述不清或两个工具描述相似,它可能调用错误。对策:为每个工具撰写独特、精准的描述,明确其职责边界。可以像写 API 文档一样,说明输入参数的准确含义。
陷阱二:无限循环或过长思考Agent 有时会陷入“思考-调用工具-再思考”的循环,或者生成极其冗长的内部独白(Chain-of-Thought),导致 Token 消耗剧增。对策:在创建 Agent 时,务必设置maxSteps(最大步骤数)和maxTokens(最大输出 Token 数)等限制。对于 Workflow,要设计明确的结束条件。
陷阱三:状态管理混乱在 Workflow 中,多个步骤间传递复杂对象时,如果直接修改上下文对象,可能导致难以追踪的状态副作用。对策:遵循函数式编程思想,每个步骤的execute函数应尽量是纯函数,接收输入,返回新的输出。Mastra 会帮你管理这些状态的版本和流转。
陷阱四:忽略错误处理和重试网络波动、模型 API 限流、工具依赖的外部服务宕机……生产环境错误无处不在。对策:为 Workflow 的每个addStep配置重试策略(retry)。对于关键的业务逻辑步骤(如创建工单),要在工具内部实现幂等性和更细致的错误处理,并向 Workflow 抛出有意义的错误信息,以便在决策节点进行分支处理(如“创建工单失败,转由发送邮件通知客服”)。
性能优化点:
- 模型选型:不是所有任务都需要 GPT-4。分类、摘要等简单任务用
gpt-4o-mini或claude-haiku成本更低、速度更快。在mastra.config.ts中配置多个模型,然后在不同 Agent 中按需指定。 - 缓存:对于频繁且结果不变的查询(如根据产品ID查询名称),可以在工具层或使用 Mastra 的中间件添加缓存层,减少对 LLM 或外部服务的调用。
- 流式响应:对于需要长时间运行的 Workflow,不要阻塞 HTTP 请求。采用我们上面示例的“启动-轮询”或“启动-Webhook 回调”模式。对于 Agent 的文本生成,考虑使用流式输出(Streaming)以提升用户体验。
- 向量检索优化:RAG 的性能瓶颈常在检索。确保你的文档分块大小和重叠度合理,并索引到高性能的向量数据库。对于实时性要求高的数据,考虑建立定时更新索引的管道。
6. 从开发到部署:项目结构与运维建议
一个可维护的 Mastra 项目结构通常如下:
my-support-agent/ ├── src/ │ ├── agents/ # 所有Agent定义 │ │ ├── classifier.agent.ts │ │ └── response-generator.agent.ts │ ├── workflows/ # 所有Workflow定义 │ │ └── ticket-processing.workflow.ts │ ├── tools/ # 所有工具定义 │ │ ├── search-kb.tool.ts │ │ └── create-ticket.tool.ts │ ├── evals/ # 评估定义 │ ├── lib/ # 共享工具函数、第三方客户端 │ ├── types/ # 全局TypeScript类型定义 │ └── index.ts # 初始化并导出mastra实例 ├── mastra.config.ts # 主配置文件 ├── mastra.config.prod.ts # 生产环境配置 └── package.json部署考量:
- 无服务器部署:Mastra 应用可以打包成独立的 Node.js 服务器或集成到 Next.js 中。对于 Vercel 等无服务器平台,注意冷启动时 Mastra 的初始化时间,以及工作流状态存储必须使用外部数据库(如 Vercel Postgres)。
- 容器化部署:使用 Docker 容器化是更通用的选择。确保在
Dockerfile中正确设置环境变量(如OPENAI_API_KEY,DATABASE_URL)。 - 存储后端:生产环境务必使用如 PostgreSQL 等持久化存储。运行数据库迁移命令来创建 Mastra 所需的数据表。
- 监控与告警:除了 Mastra 的内置可观测性,将应用日志和指标接入你的集中式监控系统(如 Grafana + Loki/Prometheus)。为关键错误(如工作流频繁失败、工具调用超时)设置告警。
最后,我个人最深的体会是,Mastra 带来的最大价值并非某个炫酷的功能,而是它提供了一套完整、一致、类型安全的抽象层。它迫使你以结构化的方式思考 AI 应用,将杂乱的 Prompt 工程、临时拼凑的脚本,变成了由 Agent、Workflow、Tool 等组件构成的、可测试、可监控、可迭代的软件系统。开始可能会觉得学习曲线稍陡,但一旦适应,开发效率和应用可靠性都会得到质的提升。尤其是在团队协作中,这种架构的优越性会更加明显。