Mastra 核心原理与工程实践
# Mastra 核心原理与工程实践
先从一个可运行项目建立 Mastra 的整体认识,再理解 Agent、Tool、Runtime Context、Memory、RAG、Workflow、Multi-Agent、MCP 与评测怎样协作,最后把运行状态安全地接到前端并部署。代码用于验证概念,不把记住 API 当成掌握框架。
# 先记住一句话
Mastra 是面向 TypeScript 应用的 AI 工程框架:Agent 负责根据上下文动态决策,Tool 提供有类型的行动能力,Workflow 编排确定性流程,Memory 与 Storage 保存跨步骤状态,宿主应用负责身份、权限、事务和最终验收。
真正需要掌握的不是 new Agent() 的参数,而是下面这条边界:
模型负责提出决策
↓
Mastra 负责组织模型、工具、记忆和流程
↓
宿主应用负责可信身份、权限、真实副作用和业务正确性
2
3
4
5
# Mastra 解决什么问题
直接调用模型 API 只能得到一次生成结果。一个可运行的 Agent 系统还需要解决:
- 如何把工具描述交给模型,并执行模型提出的调用;
- 如何保存会话、用户信息和长任务状态;
- 如何将固定流程与模型的动态决策组合;
- 如何暂停审批、失败恢复和避免重复副作用;
- 如何追踪轨迹、评测质量并控制成本;
- 如何把 MCP、Skill、文件系统或沙箱等能力接入同一个运行时。
Mastra 把这些通用能力组织成一组可组合的基础模块,但它不会自动替你定义业务完成标准,也不会因为使用了 Schema 就自动获得权限安全和事务一致性。
# 从零跑起一个最小 Mastra 项目
如果简历里写了 Mastra,至少要知道项目怎样创建、核心代码放在哪里,以及 Agent 怎样被框架发现。使用官方脚手架创建项目后,开发服务器会同时启动 Mastra Server 和本地 Studio:Server 负责真正运行 Agent、Tool 与 Workflow,Studio 用来聊天测试、查看执行过程和调试组件。
# 创建项目;openai 表示选择 OpenAI 作为初始模型提供方。
npm create mastra@latest interview-assistant --default --llm openai
# 进入脚手架生成的项目目录。
cd interview-assistant
# OPENAI_API_KEY 由模型提供方后台获取,应写入本地环境变量,不能提交到 Git。
export OPENAI_API_KEY='替换为自己的密钥'
# 启动本地 Mastra Server 与 Studio,默认可通过 http://localhost:4111 调试。
npm run dev
2
3
4
5
6
7
8
9
10
11
脚手架生成的核心目录可以这样理解:
interview-assistant/
├── src/
│ └── mastra/
│ ├── agents/
│ │ └── interview-agent.ts # 定义 Agent 的模型、Instructions 和 Tools
│ ├── tools/
│ │ └── explain-term.ts # 定义可被 Agent 调用的具体能力
│ ├── workflows/
│ │ └── interview-flow.ts # 定义顺序、分支、并行和暂停恢复
│ └── index.ts # 注册组件,是 Mastra 项目的入口
├── package.json # 依赖与 dev、build、start 等脚本
└── .env # 本地密钥;必须加入 .gitignore
2
3
4
5
6
7
8
9
10
11
12
下面这个 Tool 使用内存对象代替数据库,因此复制到脚手架项目后即可理解和调试。真实项目只需要把 termNotes 换成笔记服务或数据库查询,输入输出契约保持不变。
// src/mastra/tools/explain-term.ts
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'
// 这里故意使用内存数据,让最小示例不依赖数据库。
// 生产项目应改为调用只返回当前用户有权读取内容的笔记服务。
const termNotes: Record<string, string> = {
Agent: '能够根据目标和上下文动态决定下一步,并调用工具完成任务。',
RAG: '先检索外部证据,再让模型根据证据生成答案。'
}
export const explainTerm = createTool({
// id 是日志、Trace 和模型工具调用中使用的稳定标识。
id: 'explain-term',
// description 帮助模型判断什么时候应该调用这个 Tool。
description: '从技术笔记中查询 Agent 开发术语的简要解释',
// inputSchema 校验模型生成的工具参数。
inputSchema: z.object({
term: z.string().min(1).describe('需要解释的技术术语')
}),
// outputSchema 约束返回给 Agent 的结果,避免调用方猜测字段。
outputSchema: z.object({
found: z.boolean(),
explanation: z.string()
}),
// execute 的第一个参数已经通过 inputSchema 校验。
execute: async ({ term }) => {
const explanation = termNotes[term]
return {
found: Boolean(explanation),
explanation: explanation ?? '当前笔记暂未收录该术语。'
}
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// src/mastra/agents/interview-agent.ts
import { Agent } from '@mastra/core/agent'
import { explainTerm } from '../tools/explain-term'
export const interviewAgent = new Agent({
// id 用于通过 API 或 Mastra 注册表稳定定位这个 Agent。
id: 'interview-agent',
// name 是 Studio、日志和 Trace 中展示的可读名称。
name: 'Interview Agent',
// Instructions 说明职责、使用工具的时机和证据不足时的行为。
instructions: `
你是技术面试学习助手。
遇到术语解释问题时,先调用 explainTerm 查询笔记。
如果笔记没有收录,明确说明未知,不要编造答案。
`,
// provider/model 是 Mastra Model Router 的模型标识;运行时会读取 OPENAI_API_KEY。
model: 'openai/gpt-5-mini',
// 只有注册到 tools 中的能力才会暴露给当前 Agent。
tools: { explainTerm }
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { interviewAgent } from './agents/interview-agent'
// Mastra 入口负责注册组件;注册后 Studio 和 Server 才能发现这个 Agent。
export const mastra = new Mastra({
agents: { interviewAgent }
})
2
3
4
5
6
7
8
Studio、模板和示例分别解决什么问题
Studio 是本地或团队使用的调试与观测界面,可以直接测试 Agent、Tool 和 Workflow,并查看 Trace;它不是给最终用户使用的业务前端。Templates / Examples 是可以参考或合并进项目的示例代码,适合快速了解推荐目录和 API,但接入真实项目后仍要重新检查权限、数据来源和完成标准。
# 核心组成与职责
| 组成 | 它负责什么 | 不应该负责什么 |
|---|---|---|
| Mastra 实例 | 注册和组装 Agent、Workflow、Storage、Logger 等运行组件 | 具体业务规则 |
| Agent | 读取目标和上下文,选择模型或工具,循环到完成或停止 | 直接持有数据库超级权限 |
| Model / Router | 完成推理、结构化输出和工具选择,可按场景路由模型 | 判断业务操作是否被授权 |
| Tool | 用 Schema 描述一个边界清晰的外部能力 | 包办整个开放式任务 |
| Runtime Context | 携带本次请求的租户、用户、权限、模型策略等可信运行信息 | 充当长期记忆或数据库 |
| Memory | 保存 thread、resource、历史消息、工作记忆或可召回信息 | 保存所有业务事实 |
| Workflow | 编排 step、分支、并行、循环、暂停与恢复 | 让模型随意改写关键流程 |
| Storage / Snapshot | 持久化记忆、Workflow 状态和恢复点 | 替代领域数据库事务 |
| Processor / Guardrail | Processor 在输入输出生命周期中检查或转换内容;Guardrail 泛指阻止不合规行为的防线 | 仅靠 Prompt 保证安全 |
| Workspace / Skill | 提供文件、沙箱和可复用任务方法 | 自动成为有自主决策能力的 Agent |
| MCP | 以标准协议接入或暴露工具、资源和提示模板 | 替代 Tool 的权限校验 |
| Scorer / Observability | 记录 Trace、评估质量、发现回归 | 只看最终答案就判断系统健康 |
| Client SDK / AI SDK Adapter | 从浏览器或服务端调用 Agent、Workflow、Memory 并消费流式事件 | 把服务端权限下放给浏览器 |
# Mastra 中一次 Agent 运行经历什么
Agent 开发总览 已经说明不绑定框架的通用运行链路。下面是在 Mastra 中的具体落地,其中 Runtime Context、Memory、Processor 和 Trace 是 Mastra 对通用步骤的实现方式;整体仍然遵循 “模型决策 → 工具执行 → 观察结果 → 继续决策” 的 Agent Loop。
1. 宿主应用接收请求并完成鉴权
2. 创建本次 Runtime Context
3. Agent 解析 instructions、model、tools 和 memory
4. 加载与当前 thread / resource 相关的记忆
5. 输入 Processor 做清洗、裁剪和安全检查
6. 模型决定直接回答,或提出一个 Tool Call
7. 宿主应用校验参数、权限、预算和审批条件后执行 Tool
8. Tool 的真实结果作为 observation 回到上下文
9. 模型基于新状态继续决策,直到完成、暂停或触发上限
10. 输出 Processor 检查结果,随后持久化状态并记录 Trace
2
3
4
5
6
7
8
9
10
其中第 7 步非常关键。模型只是在非可信数据中提出 “我想调用这个工具”,真正执行前必须由宿主应用重新校验。
更容易与通用链路对照的五阶段版本
下面没有减少实际工作,只是把 Mastra 的十个步骤归入五个通用阶段:
1. 接收请求与初始化运行环境
├── 宿主应用验证身份与权限
└── 创建本次 Runtime Context
2. 组装本轮上下文
├── 读取 Agent 的 instructions、model、tools 和 memory 配置
├── 加载与当前 thread / resource 相关的记忆
└── 输入 Processor 清洗、裁剪并检查输入
3. 模型决定下一步
├── 已经可以完成 → 生成最终回答
└── 还需要行动 → 提出 Tool Call
4. 验证并执行工具
├── 宿主应用校验参数、权限、预算和审批条件
└── 执行 Tool,把真实结果作为 observation 返回上下文
5. 更新状态,继续或结束
├── 未完成 → 模型根据新状态继续决策
└── 已完成或暂停 → 输出 Processor 检查结果,保存状态并记录 Trace
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
五阶段版本适合理解和面试复述;十步骤版本适合查看 Mastra 的组件分别在哪个环节参与运行。
# Agent:动态决策的执行主体
一个 Agent 的核心配置通常包括:
instructions:角色、目标、边界和完成标准;model:默认模型或根据运行上下文动态选择的模型;tools:本次允许发现和调用的能力集合;memory:如何读取、裁剪和保存相关上下文;processors:进入模型前、输出给用户前的检查和转换;scorers:对结果或轨迹进行质量评估。
import { Agent } from '@mastra/core/agent'
// buildInstructions、selectModel、Tool、Memory 和 Processor 均由当前应用实现或注入。
// 这个示例用于说明配置之间的关系,不是一个可独立运行的完整文件。
const interviewAgent = new Agent({
// Agent 在 Mastra 注册表和 Trace 中使用的稳定名称。
name: 'interview-notes-agent',
// 根据服务端写入的可信上下文动态组装 Instructions。
instructions: ({ requestContext }) => buildInstructions({
role: requestContext.get('role'), // 当前用户经过鉴权后的角色。
knowledgeScope: requestContext.get('knowledgeScope') // 本次允许检索的知识范围。
}),
// 根据质量档位选择模型,不能让用户直接提交任意模型名称。
model: ({ requestContext }) => selectModel(
requestContext.get('qualityTier')
),
// 只暴露当前任务需要的 Tool,减少误调用和权限面。
tools: { searchNotes, previewLearningGap },
// memory 是应用配置好的 Mastra Memory 实例。
memory,
// 输入 Processor 在调用模型前检查注入风险并限制上下文长度。
inputProcessors: [promptInjectionDetector, contextLimiter],
// 输出 Processor 在结果返回给用户前检查引用。
outputProcessors: [citationChecker]
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
这段代码表达的是依赖关系,不要求死记某个版本的参数名。真正稳定的设计是:Agent 只获得本次任务需要的最小能力,配置可以读取可信运行上下文,但不能让模型伪造身份和权限。
# Runtime Context、Memory 与 Workflow State
这三个概念最容易混淆:
| 状态 | 生命周期 | 示例 | 读取者 |
|---|---|---|---|
| Runtime Context | 单次请求或运行 | userId、tenantId、权限、模型档位、请求来源 | Agent 配置、Tool、Processor |
| Memory | 跨轮次或跨会话 | 历史消息、已确认偏好、用户学习目标 | Agent 与记忆处理器 |
| Workflow State | 一次流程从开始到完成 | 当前 step、草稿、分数、重试次数、审批结果 | Workflow 各步骤 |
| 领域数据 | 长期业务事实 | 笔记正文、订单、账户余额、发布记录 | 宿主应用的领域服务与数据库 |
Runtime Context 决定 “这次运行是谁、能做什么”,Memory 决定 “过去有什么值得取回”,Workflow State 决定 “任务进行到哪里”。
不要把 userId 作为 Tool 参数交给模型填写;应从 Runtime Context 读取。Mastra 当前 API 中承载这类信息的参数名通常是 requestContext,本文的 Runtime Context 指的是它代表的运行时概念。也不要把账户余额、发布状态等权威事实只保存在消息历史里。
# Tool:模型与真实世界之间的契约
一个可靠 Tool 至少包含五部分:
- 单一且明确的职责;
- 足以帮助模型正确选择的描述;
- 严格的输入与输出 Schema;
- 执行前的权限、预算和风险检查;
- 结构化成功结果与可行动的错误结果。
import { createTool } from '@mastra/core/tools'
// z 是 Zod 导出的 Schema 构造器,下面用它校验模型生成的工具参数和工具结果。
import { z } from 'zod'
export const searchNotes = createTool({
// Tool 的稳定标识,供模型选择、日志记录和 Trace 展示。
id: 'search-notes',
// description 会提供给模型,用于判断什么时候应调用该 Tool。
description: '在当前用户允许访问的技术笔记中检索相关段落',
// inputSchema 校验模型生成的调用参数。
inputSchema: z.object({
query: z.string().min(2), // 至少两个字符的检索词。
limit: z.number().int().min(1).max(8).default(5) // 最多返回 8 条,默认 5 条。
}),
// noteExcerptSchema 由应用定义,用来约束每条笔记片段的字段。
outputSchema: z.object({
items: z.array(noteExcerptSchema)
}),
// 第一个参数已经通过 inputSchema 校验;requestContext 由可信宿主应用传入。
execute: async ({ query, limit }, { requestContext }) => {
// userId 必须来自服务端运行上下文,不能让模型或浏览器自行填写。
const userId = requestContext.get('userId')
// 在真正检索前再次执行服务端权限检查。
await permissionService.assertCanReadNotes(userId)
// noteService 是应用自己的领域服务,负责访问数据库或搜索索引。
return noteService.search(userId, query, limit)
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Schema 解决的是 “数据长什么样”,权限解决的是 “谁能调用”,幂等键解决的是 “重试会不会重复执行”。三者不能相互替代。
对于发送邮件、删除文件、转账、发布内容等高风险 Tool,推荐先生成预览和 actionId,进入审批节点后再执行;同时为副作用设置幂等约束。
Tool Streaming 是什么
Tool Streaming 是在 Agent 流式运行期间,把工具参数生成、工具开始执行、工具结果或错误等生命周期事件及时传给调用方。它的价值不是让数据库查询本身变成逐字输出,而是让前端知道 Agent 正在调用什么、是否等待审批以及何时拿到结果。页面仍应把底层事件转换成自己的稳定 UI 状态,不能只拼接文本。
# Memory:不是把聊天记录无限塞回模型
Mastra 的 Memory 可以围绕不同范围组织信息:
- Thread:一次连续会话或任务的消息与上下文;
- Resource:跨多个 thread 共享的用户或实体级信息;
- Working Memory:当前工作中需要持续维护的结构化事实;
- Conversation History:近期对话;
- Semantic Recall:按相关性取回较早信息;
- Processors:负责截断、摘要、筛选或写入策略。
Memory 的正确流程是:
候选信息产生 → 判断是否值得保存 → 按作用域持久化
↓ 下一次运行
按任务检索 → 去除过期或冲突内容 → 放入有限 Context
2
3
只有用户确认且未来确实有复用价值的信息才适合长期保存。模型推测、临时计划和过期状态不能直接升级为长期事实。
# RAG:把外部知识作为可追溯证据
Memory 主要解决过去交互中哪些信息值得再次取回,RAG 主要解决怎样从外部知识库找到与当前问题相关的原文证据。在 Mastra 中,完整 RAG 仍然分为离线索引和在线检索两条链路:
离线索引
原始 Markdown
└── MDocument 读取文档
└── chunk() 切成语义片段
└── Embedding 模型生成向量
└── Vector Store 保存向量、原文和来源元数据
在线检索
用户问题
└── createVectorQueryTool 生成查询向量
└── Vector Store 相似度检索与权限过滤
└── 可选 rerank 重新排序
└── 原文片段作为 Context 交给 Agent 回答
2
3
4
5
6
7
8
9
10
11
12
13
先安装 RAG、Embedding 和本地向量库需要的依赖:
# @mastra/rag 提供文档切分和向量检索工具;ai 提供批量 Embedding 调用。
# @mastra/libsql 只用于这个本地示例,生产环境可以替换成团队实际使用的向量库。
npm install @mastra/rag@latest @mastra/libsql@latest ai@latest
2
3
下面是一次性离线索引脚本。它负责把笔记切分并写入向量库,不应该在每次用户提问时重复执行。
// src/index-notes.ts
import { readFile } from 'node:fs/promises'
import { ModelRouterEmbeddingModel } from '@mastra/core/llm'
import { MDocument } from '@mastra/rag'
import { embedMany } from 'ai'
import { mastra } from './mastra'
// 笔记路径由索引任务指定;真实项目通常会遍历经过权限筛选的文档目录。
const notePath = 'docs/ai-fullstack/agent/overview.md'
const noteText = await readFile(notePath, 'utf8')
// MDocument 把原始文本包装为可切分、可携带元数据的文档对象。
const document = MDocument.fromText(noteText)
const chunks = await document.chunk({
strategy: 'recursive', // 优先沿自然分隔符递归切分,减少语义被截断。
maxSize: 512, // 单个片段的最大长度;最终值应由检索评测决定。
overlap: 50, // 相邻片段保留少量重叠,避免边界处信息丢失。
separators: ['\n\n', '\n', ' ']
})
// 文档和查询必须使用兼容的 Embedding 模型与相同向量维度。
const embeddingModel = new ModelRouterEmbeddingModel(
'openai/text-embedding-3-small'
)
const { embeddings } = await embedMany({
model: embeddingModel,
values: chunks.map(chunk => chunk.text)
})
// libSqlVector 是在 src/mastra/index.ts 中注册的 Vector Store。
const vectorStore = mastra.getVector('libSqlVector')
// 1536 是当前示例模型的向量维度;更换模型时必须同步修改。
// 生产项目通常通过 migration 创建索引,不在重复执行的业务请求中创建。
await vectorStore.createIndex({
indexName: 'agent-notes',
dimension: 1536
})
await vectorStore.upsert({
indexName: 'agent-notes',
vectors: embeddings,
// metadata 保存真正需要返回给模型和用户的原文与来源。
metadata: chunks.map(chunk => ({
text: chunk.text,
source: notePath,
knowledgeBase: 'agent-development'
}))
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
在线阶段把向量检索包装成 Tool,由 Agent 根据问题决定是否调用:
// src/mastra/agents/rag-interview-agent.ts
import { Agent } from '@mastra/core/agent'
import { ModelRouterEmbeddingModel } from '@mastra/core/llm'
import { createVectorQueryTool } from '@mastra/rag'
const searchKnowledgeBase = createVectorQueryTool({
// 名称必须与 Mastra 入口中 vectors 的注册键一致。
vectorStoreName: 'libSqlVector',
// 在线查询必须检索离线脚本写入的同一个索引。
indexName: 'agent-notes',
// 查询向量与文档向量使用同一个 Embedding 模型。
model: new ModelRouterEmbeddingModel('openai/text-embedding-3-small')
})
export const ragInterviewAgent = new Agent({
// id 是 API、注册表和 Trace 使用的稳定标识。
id: 'rag-interview-agent',
// name 是 Studio 中展示的可读名称。
name: 'RAG Interview Agent',
// Instructions 规定检索时机、证据边界和证据不足时的行为。
instructions: `
回答 Agent 开发问题前先检索知识库。
只把检索结果中的原文当作证据,并在回答中给出 source。
证据不足时明确说明笔记暂未覆盖,不得自行补造来源。
`,
// 回答模型与 Embedding 模型职责不同,这里配置的是生成回答的模型。
model: 'openai/gpt-5-mini',
// Agent 会根据 Instructions 和 Tool 描述决定何时检索。
tools: { searchKnowledgeBase }
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// src/mastra/vector-store.ts
import { LibSQLVector } from '@mastra/libsql'
export const libSqlVector = new LibSQLVector({
// id 是这个 Vector Store 实例在日志和内部组件中的稳定标识。
id: 'agent-notes-vector',
// 本地开发可把 VECTOR_DB_URL 设置为 file:/绝对路径/vector.db。
// 生产环境应换成可持久化、可备份并支持权限隔离的远程存储。
url: process.env.VECTOR_DB_URL!
})
2
3
4
5
6
7
8
9
10
这个示例重点说明代码放置和数据流。真实项目还要在检索阶段加入用户权限与知识库过滤,召回后可用 reranker 重排,并用 Recall@K、引用准确率等指标分别评估检索和回答。更完整的原理见 RAG 原理与工程实践。
# Workflow:把确定性控制放回代码
Workflow 适合明确的步骤、分支、并行、循环、重试和人工介入。例如笔记与面试助手可以这样编排:
validateRequest
↓
retrieveNotes ──并行── loadInterviewRubric
↓
runAgent
↓
evaluateDraft ──不通过且有预算──→ runAgent
↓通过
previewLearningGap
↓ suspend
saveLearningGap
2
3
4
5
6
7
8
9
10
11
Workflow 的关键能力不只是 “按顺序调用函数”:
- step 显式声明输入输出,降低隐藏依赖;
- branch / parallel / loop 分别表达条件分支、并行执行和循环;
- suspend / resume 让流程暂停等待外部输入,并在收到审批或补充信息后继续;
- snapshot 是保存下来的完整执行状态,可供另一个进程恢复;
- rewind 是回到较早状态重新运行,主要用于调试或重新处理后续步骤。
恢复并不意味着所有代码都只执行一次。暂停之前或失败步骤中的副作用仍应满足幂等,关键写入仍由数据库事务保证。
# 一个最小可运行的 Workflow
下面的示例把生成草稿和检查完成标准固定为两个步骤。它展示的是最稳定的主干:createStep() 定义步骤契约,createWorkflow() 定义整条流程,.then() 连接顺序,最后必须 .commit() 固化执行图。
// src/mastra/workflows/interview-flow.ts
import { createStep, createWorkflow } from '@mastra/core/workflows'
import { z } from 'zod'
import { interviewAgent } from '../agents/interview-agent'
const generateAnswer = createStep({
// id 会出现在 Workflow Trace 和 Studio 的执行图中。
id: 'generate-answer',
// inputSchema 定义本步骤允许接收的数据。
inputSchema: z.object({
question: z.string().min(1)
}),
// outputSchema 同时也是下一步骤的输入契约。
outputSchema: z.object({
question: z.string(),
draft: z.string()
}),
execute: async ({ inputData }) => {
// Agent 只负责需要语义判断的回答生成。
const response = await interviewAgent.generate(inputData.question)
return {
question: inputData.question,
draft: response.text
}
}
})
const checkAnswer = createStep({
// 这个步骤只检查结果,不再让 Agent 自己判断是否合格。
id: 'check-answer',
// 输入与 generateAnswer 的输出保持一致,连接时才能通过类型检查。
inputSchema: z.object({
question: z.string(),
draft: z.string()
}),
// passed 供后续分支决定完成、重试还是转人工检查。
outputSchema: z.object({
answer: z.string(),
passed: z.boolean()
}),
execute: async ({ inputData }) => {
// 这里只演示确定性完成标准;真实项目可以换成独立 Scorer。
const passed = inputData.draft.length >= 40
return {
answer: inputData.draft,
passed
}
}
})
export const interviewFlow = createWorkflow({
id: 'interview-flow',
// Workflow 输入来自 API、上层 Workflow 或另一个 Agent。
inputSchema: z.object({
question: z.string().min(1)
}),
// Workflow 输出必须与最后一个步骤的结果一致。
outputSchema: z.object({
answer: z.string(),
passed: z.boolean()
})
})
// then 表示前一步成功后,把输出交给下一步。
.then(generateAnswer)
.then(checkAnswer)
// commit 会完成图校验并固定 Workflow 定义;漏掉后不能正常运行。
interviewFlow.commit()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { interviewAgent } from './agents/interview-agent'
import { ragInterviewAgent } from './agents/rag-interview-agent'
import { libSqlVector } from './vector-store'
import { interviewFlow } from './workflows/interview-flow'
// 这是把前面 Agent、RAG 和 Workflow 合并后的最终入口。
export const mastra = new Mastra({
// agents 中注册需要由 Server 和 Studio 对外提供的 Agent。
agents: { interviewAgent, ragInterviewAgent },
// 注册键 interviewFlow 供 Server、Studio 和其他组件查找这条 Workflow。
workflows: { interviewFlow },
// 注册键 libSqlVector 必须与检索 Tool 的 vectorStoreName 一致。
vectors: { libSqlVector }
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
真实流程可以继续用 .parallel() 表达互不依赖的并行步骤,用 .branch() 表达互斥条件,用 .doWhile() / .doUntil() 表达有上限的循环。需要等待审批时,在 Step 中 suspend();收到可信的审批结果后再通过对应 Run 恢复。不要为了展示所有 API 把简单流程强行写成复杂执行图。
# Processor 与 Guardrail:把约束放进生命周期
Prompt 中写 “不要泄漏隐私” 只是行为提示,不是可靠安全边界。Processor 适合承担多次调用都会经过的通用检查和转换:
- 输入阶段:检测提示注入、PII、恶意文件和上下文超限;
- 模型阶段:裁剪消息、路由模型、限制工具集合;
- 输出阶段:检查敏感内容、引用、结构和完成条件;
- 记忆阶段:决定哪些内容可写入、需要过期或必须删除。
稳定做法是分层防护:Processor 负责早期发现与阻断,Tool 和宿主应用的领域服务仍进行最终授权,数据库负责最后的一致性约束。
# Workspace、Skill 与 Supervisor
Workspace 为 Agent 提供可控的文件系统、工作目录或沙箱。Skill 则把一类任务需要的指令、资源和脚本组织成可复用方法。
- Agent 决定当前目标和下一步;
- Skill 告诉 Agent 某类任务应遵循什么方法;
- Workspace 提供完成任务所需的工作环境;
- Tool 执行具体动作。
Supervisor Agent 用于把任务委派给专业 Agent,并汇总结果。只有当角色确实拥有不同工具、上下文或权限时才值得拆分;如果只是为了 “看起来智能” 而增加多个 Agent,只会提高成本、延迟和调试难度。
# Mastra 中怎样编排多个 Agent
Mastra 的多 Agent 编排不是只有一种写法,应先根据控制权选择:
| 方式 | 谁决定执行路径 | 更适合什么场景 |
|---|---|---|
| Workflow 调用多个 Agent | 代码中的执行图 | 顺序、并行和验收规则已知,要求稳定可审计 |
| Supervisor Agent | 主 Agent | 主控需要动态选择专家,但最终仍由主控汇总 |
.network() | 路由 Agent 的模型循环 | 路径事先难以确定,需要动态组合 Agent、Tool 和 Workflow |
下面以笔记生产为例:研究 Agent 负责找证据,写作 Agent 负责组织表达,主 Agent 根据任务决定先调用谁。子 Agent 的 description 很重要,因为主 Agent 会根据它判断是否委派。
// src/mastra/agents/note-network.ts
import { Agent } from '@mastra/core/agent'
const researchAgent = new Agent({
// id 是委派、日志和 Trace 中使用的稳定标识。
id: 'note-researcher',
// name 是 Studio 中展示的可读名称。
name: 'Note Researcher',
// description 面向主 Agent,说明这个子 Agent 适合接收什么任务。
description: '负责检索官方资料并返回带来源的已验证事实,不负责润色文章。',
// Instructions 约束研究过程和输出边界。
instructions: '只返回有来源支持的事实;无法核验时明确标记未知。',
// 每个子 Agent 可以选择适合自己任务的模型。
model: 'openai/gpt-5-mini'
})
const writingAgent = new Agent({
// 写作 Agent 使用独立 id,避免与研究 Agent 的运行记录混淆。
id: 'note-writer',
name: 'Note Writer',
// description 告诉主 Agent 何时应该把任务交给它。
description: '负责把已有证据改写成通俗的中文面试笔记,不负责外部检索。',
// Instructions 规定写作 Agent 只能使用已经交付的证据。
instructions: '根据收到的证据写作,不得补充来源中不存在的技术结论。',
model: 'openai/gpt-5-mini'
})
export const noteSupervisor = new Agent({
// 主 Agent 也需要独立 id,方便定位整条编排 Trace。
id: 'note-supervisor',
name: 'Note Supervisor',
// 主 Agent 负责拆分任务、选择子 Agent、检查结果并决定何时结束。
instructions: `
先判断是否缺少可靠证据,缺少时委派给 researchAgent。
获得证据后再委派给 writingAgent,最后检查来源和完成标准。
`,
// 主 Agent 的模型负责路由、验收和停止判断。
model: 'openai/gpt-5-mini',
// agents 中注册的是可被主 Agent 委派的专业 Agent,不是普通 Tool。
agents: { researchAgent, writingAgent }
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// src/run-network.ts
import { noteSupervisor } from './mastra/agents/note-network'
// network() 让主 Agent 在循环中动态选择子 Agent、Tool 或 Workflow。
// 调用结果仍需由应用按来源、格式和完成标准验收。
const result = await noteSupervisor.network(
'核验 Mastra Workflow 的最新 API,并生成一段面试笔记。'
)
// result 中包含网络运行的最终输出;生产环境还应记录 Trace 和成本。
console.log(result)
2
3
4
5
6
7
8
9
10
11
`.network()` 为什么要谨慎使用
.network() 当前属于实验性能力,版本变化速度可能快于 Agent 和 Workflow 的稳定 API。项目使用时应锁定 Mastra 版本并做回归测试。若执行顺序已知,优先用 Workflow 显式编排多个 Agent;只有路径确实需要模型动态决定时,再使用 Network。
# MCP:统一能力接入,不替代业务边界
Mastra 可以消费 MCP Server 提供的工具、资源和提示模板,也可以把自身能力暴露给其他 MCP Host。它解决的是跨应用的能力发现与调用协议。
Mastra Agent → MCP Client → MCP Server → 外部系统
外部 Host → MCP Client → Mastra MCP 能力
2
MCP Server 返回的描述和内容都属于外部输入。连接成功不代表可信,仍需做 Server 白名单、Tool 白名单、参数校验、超时、结果裁剪与写操作审批。
# Scorer、Eval 与 Observability
生产闭环要同时回答两个问题:
- Observability:这次运行经过了哪些模型、Tool 和 Workflow step,在哪里变慢或失败?
- Eval:这条轨迹和最终结果是否足够好?
Mastra 的 Trace 可以记录模型调用、工具调用、步骤、Token、延迟和错误,并通过 OpenTelemetry 等方式接入观测系统。Scorer 可评估答案正确性、引用覆盖、工具选择、安全和任务完成度。
推荐闭环:
生产 Trace 发现问题
↓
脱敏后加入固定评测集
↓
比较 Prompt / Model / Tool / Workflow 版本
↓
通过质量、成本和延迟门槛后灰度发布
2
3
4
5
6
7
# Client SDK:Mastra 怎样对接前端
@mastra/client-js 是 Mastra Server 的类型化客户端。它不仅能调用 Agent,还能访问 Workflow、Memory Thread、Tool、Trace 等服务端资源。
React / Vue / Mobile
↓ @mastra/client-js 或 AI SDK UI
宿主应用自己的 API Route / BFF(推荐用于用户系统)
↓ 身份认证、权限映射、限流、审计
Mastra Server
↓
Agent / Workflow / Memory / Storage
2
3
4
5
6
7
# 初始化 Client
import { MastraClient } from '@mastra/client-js'
export const mastraClient = new MastraClient({
// 浏览器可见的 Mastra Server 或 BFF 地址,不应包含任何 Secret。
baseUrl: import.meta.env.VITE_MASTRA_BASE_URL,
// 跨请求携带由服务端设置的登录 Cookie;服务端仍需完成鉴权。
credentials: 'include'
})
2
3
4
5
6
7
8
浏览器里的 baseUrl 本来就是公开信息,不能把 API Key、数据库凭据或其他服务端 Secret 写进前端环境变量。Cookie 或 Token 应由 Mastra Server / BFF 验证,并在服务端把登录用户映射为可信 Runtime Context。
# 同步生成与流式生成怎样选择
// 从上面初始化的 Client 中取得服务端注册的 Agent。
const agent = mastraClient.getAgent('interview-notes-agent')
// 适合短任务:等待完整结果后一次更新页面。
const result = await agent.generate('解释 MCP 和 Tool Calling 的区别', {
memory: {
thread: threadId, // 当前会话 ID,来自页面状态或路由参数。
resource: resourceId // 记忆所属用户或资源 ID,服务端必须校验归属。
}
})
// 适合聊天和长回答:逐块更新页面,并显示 Tool 与运行状态。
const response = await agent.stream('模拟一道 Agent 系统设计面试题', {
memory: {
thread: threadId, // 让流式运行继续写入同一会话。
resource: resourceId // 决定从哪个资源范围读取 Memory。
}
})
// 把 Mastra 的原始 chunk 转成页面自己的稳定事件,再更新 UI 状态。
await response.processDataStream({
onChunk: chunk => dispatch(toUiEvent(chunk))
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
前端传来的 threadId 和 resourceId 都是不可信标识。服务端必须验证它们是否属于当前登录用户,不能因为 Client SDK 的类型检查通过就直接读取对应 Memory。
# 不要只拼接 text-delta
Mastra 的数据流包含多类 chunk。前端应先转换成自己的稳定事件,再更新 UI:
| Mastra 事件族 | 页面状态 | 推荐展示 |
|---|---|---|
start、step-start、step-finish | running、当前步骤 | “正在检索笔记” 之类的明确进度 |
text-start、text-delta、text-end | assistant message | 流式正文 |
tool-call | tool activity | 工具名、目的和安全参数摘要 |
tool-result、tool-error | tool result | 成功摘要或可重试错误 |
tool-call-approval、tool-call-suspended | awaitingApproval | 审批卡片,而不是一直显示加载中 |
finish | completed | 最终答案、引用、耗时 |
abort、error | cancelled、failed | 失败原因与重试入口 |
type ChatRunState = {
runId?: string // 当前服务端运行 ID,用于断线重连和查询状态。
status: 'idle' | 'running' | 'awaitingApproval' | 'completed' | 'failed' // 页面主状态。
text: string // 已收到并准备展示的回答正文。
activities: Array<{ id: string; type: string; status: string }> // 工具和步骤的可视化记录。
approval?: { toolCallId: string; summary: string } // 等待用户确认的工具调用摘要。
error?: string // 可以展示给用户的失败原因,不应包含服务端敏感信息。
}
2
3
4
5
6
7
8
SDK 的 chunk 类型可以随框架升级,页面自己的 ChatRunState 才应该是稳定契约。建议在适配层完成版本兼容、顺序校验和未知事件降级,不要让每个组件直接判断底层 chunk。
# 三种前端接入方式
| 方式 | 适合场景 | 主要取舍 |
|---|---|---|
浏览器直接使用 @mastra/client-js | 内部工具、同域部署、服务端已完整鉴权 | 最简单,但必须正确配置 CORS、认证和资源隔离 |
| Next.js / Nuxt / Node BFF 调用 Client SDK | 有 Cookie Session、私有权限或需要聚合领域数据 | 多一层接口,但安全边界和业务契约最清晰 |
@mastra/ai-sdk + useChat 等 UI Hook | 已使用 Vercel AI SDK 的聊天界面 | UI 集成快,但仍要理解 Mastra 原始事件和审批状态 |
面向真实用户的笔记与面试助手,推荐 BFF:浏览器只提交消息和页面需要的公开 ID;BFF 根据登录态确定 userId、resourceId 和允许使用的 Agent,再调用 Mastra。
// app/api/chat/route.ts
// requireSession、chatInputSchema、threadService 和 streamInterviewAgent 均由应用提供。
export async function POST(request: Request) {
// 先从 Cookie 或 Token 恢复可信登录身份。
const session = await requireSession(request)
// 再校验浏览器提交的消息和 threadId 是否符合输入契约。
const input = await chatInputSchema.parseAsync(await request.json())
// 防止用户读取或写入其他人的会话。
await threadService.assertOwner(input.threadId, session.userId)
// 只把服务端确认后的身份和资源范围传给 Agent。
return streamInterviewAgent({
message: input.message,
threadId: input.threadId,
resourceId: session.userId
})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
如果项目采用 AI SDK UI,可以通过 @mastra/ai-sdk 的 Route Handler 或 Stream Handler,把 Mastra Agent / Workflow 的输出转换为 useChat、useCompletion 或 useObject 能消费的协议。它是协议适配层,不会替代鉴权和领域校验。
# Thread、断线重连与 Durable Agent
普通 HTTP Stream 与当前连接绑定。网络中断或浏览器刷新后,前端至少要保存:
threadId:会话与 Memory 的逻辑标识;runId:某次 Agent 执行的标识;- 已接收事件的 sequence 或去重键;
- 当前是否处于审批、完成或失败状态。
对于需要跨刷新继续观察的长任务,可使用 Durable Agent:服务端缓存或持久化运行事件,Client SDK 通过 runId 调用 observe() 重新订阅。Thread 级交互还可以使用 subscribeToThread(),配合 sendMessage()、queueMessage() 或 Signal 接收活跃运行和后续轮次的事件。
// mastraClient 在“初始化 Client”一节创建;userMessage 和 runId 来自页面状态。
const durableAgent = mastraClient.getAgent('durable-interview-agent')
// 页面首次发起运行。
const response = await durableAgent.stream(userMessage, { runId })
// handleChunk 把服务端事件合并进页面状态,并按事件 ID 或序号去重。
await response.processDataStream({ onChunk: handleChunk })
// 刷新或断线后根据同一 runId 重新观察。
const resumed = await durableAgent.observe({ runId })
await resumed.processDataStream({ onChunk: handleChunk })
2
3
4
5
6
7
8
9
10
11
Durable Stream 解决 “客户端重新连接后还能观察运行”,Workflow Snapshot 解决 “流程暂停或失败后从保存状态恢复”。二者关注点不同,不要混为一谈。
# 前端提交审批时发生什么
收到 tool-call-approval / suspended
↓
页面展示工具、影响范围和参数摘要
↓ 用户批准、修改或拒绝
BFF 再次检查用户、runId、toolCallId 与权限
↓
调用 resume / approval API
↓
继续消费新的 Stream,直到 completed 或 failed
2
3
4
5
6
7
8
9
审批按钮需要防重复点击;服务端需要一次性审批记录和幂等键。不能只在前端把按钮禁用,因为用户可以绕过 UI 重放请求。
# 从本地 Studio 到生产部署
本地执行 npm run dev 时,Mastra Server 提供 Agent、Tool 和 Workflow 的运行接口,Studio 提供调试和观测界面。到了生产环境,这两部分可以一起托管,也可以分开部署:
| 部署方式 | Mastra Server 在哪里 | Studio / Observability 在哪里 | 适合场景 |
|---|---|---|---|
| 全托管 | Mastra 平台 | Mastra 平台 | 小团队快速上线,不想维护 Agent Runtime |
| 自托管 Server | 自己的容器、虚拟机或云平台 | 托管 Studio | 已有基础设施,希望数据面由自己控制 |
| 全自托管 | 自己的基础设施 | 自己的基础设施 | 合规、数据隔离或内网环境要求高 |
用户浏览器
└── Next.js / Node BFF
├── 登录认证、权限、限流与业务 API
└── Mastra Client
└── Mastra Server
├── Agent / Workflow / Tool
├── Memory / Storage / Vector Store
└── Trace → Studio / Observability
2
3
4
5
6
7
8
Server 是生产运行时,Studio 是开发与观测界面,二者不是同一个职责。前端可以和 Mastra Server 部署在同一个 Web 应用中,也可以通过 BFF 调用独立的 Mastra Server。需要独立扩缩容、服务多个客户端或隔离 Agent 运行资源时,拆成单独服务更合适;原型和小项目可以先同进程部署。
无论部署在哪里,都要同时配置模型密钥、持久化 Storage、向量库、认证中间件、日志与 Trace 导出。生产环境不能继续依赖进程内 Memory 或本地临时文件,否则重启、扩容或迁移实例时会丢失状态。Mastra Cloud 可以减少 Server 和 Studio 的运维工作,但不会自动替代应用自己的用户权限、领域数据库和数据合规设计。
# 用笔记与面试助手验证这些知识
这个项目不需要堆满 API,只要验证核心抽象:
- Runtime Context 携带用户身份和知识范围;
searchNotesTool 只返回允许访问的片段;- Agent 判断检索、追问或回答;
- Workflow 固定检索、回答、评测和审批;
- thread 保存本轮面试,resource 保存用户确认的长期目标;
- 保存薄弱点前 suspend,恢复后用
actionId幂等写入; - RAG 离线索引笔记,在线按权限检索并返回可追溯原文;
- 多 Agent 场景由 Supervisor 分配研究与写作任务,固定步骤仍交给 Workflow;
- Trace 记录模型、工具和步骤,Scorer 检查引用与知识点覆盖;
- Client SDK 将 chunk 转换成页面事件,刷新后可根据 threadId / runId 恢复界面;
- Mastra Server 使用持久化 Storage 部署,前端通过 BFF 安全访问。
做完后应该能解释每个状态放在哪里、一次失败怎样恢复、为什么不会越权,而不只是展示 “模型成功调用了一个工具”。
# 高频面试题与回答
回答顺序:先说结论,再解释原因,最后补一个例子或工程边界。不要逐字背诵,记住这条表达主线即可。
1. 2 分钟回答:你怎样理解 Mastra 的核心设计参考答案
我理解 Mastra 的核心是把 TypeScript Agent 应用里的 动态决策 和 确定性流程 分开。Agent 根据 Instructions、Context 和工具结果决定下一步;固定分支、校验、重试和人工审批放进 Workflow,并通过 Snapshot 支持暂停和恢复。Tool 的 Schema 只定义模型与代码之间的数据契约,真实身份、权限、幂等和事务仍由应用负责。状态也要分清:Runtime Context 是本次请求的可信配置,Memory 是跨轮次可能复用的信息,Workflow State 是任务进度。生产环境再用 Processor 检查输入输出、用 Trace 排查执行过程、用 Scorer 评估结果质量。
2. Mastra Agent 和 Workflow 怎样选择?参考答案
如果下一步必须由模型根据语义和工具结果临时判断,就用 Agent;如果步骤固定、风险高,或者需要稳定重试和人工审批,就用 Workflow。常见做法不是二选一,而是让外层 Workflow 控制关键阶段,把 Agent 放在其中一个需要动态判断的节点里。
3. Runtime Context 和 Memory 有什么区别?参考答案
Runtime Context 是应用为这一次运行传入的可信信息,例如当前用户、租户、权限范围和模型策略;Memory 保存过去交互中以后可能还要取回的信息。可以记成:Runtime Context 回答 “这次以什么身份和配置运行”,Memory 回答 “过去有什么值得记住”。
4. Schema 为什么不能保证 Tool 安全?参考答案
因为 Schema 只检查参数格式,例如金额是不是数字,不能证明用户有权转账,也不能防止同一笔转账重复执行。Tool 真正执行前,服务端仍要验证可信身份、业务规则和审批,并用幂等键控制重复请求。
5. Mastra 的 Memory、Workflow Snapshot 和业务数据库怎样分工?参考答案
Memory 保存 Agent 以后可能复用的历史和偏好;Workflow Snapshot 保存这一次流程执行到哪一步,供暂停后恢复;业务数据库保存订单、账户和笔记等最终权威事实。三者用途不同,不能因为框架能保存 Memory 或 Snapshot,就把业务数据库省掉。
6. 怎样判断自己真正掌握了 Mastra?参考答案
不只是能运行一个 Agent Demo,而是能讲清一次请求怎样经过 Agent、Tool 和 Workflow,各类状态分别存在哪里;还能实现安全 Tool、可暂停恢复的 Workflow、前端流式交互和评测追踪。更重要的是,能说明什么时候原生 SDK 或普通 Workflow 已经够用。
7. Mastra 怎样与前端页面对接?参考答案
我通常让前端先请求自己的 BFF,也就是专门服务前端的后端接口层。BFF 根据登录态确定用户和可访问资源,再用 Mastra Client SDK 调用 Agent,避免把敏感凭据放到浏览器。前端把流里的文本、工具、审批、完成和错误事件转换成自己的 UI 状态;threadId 标识会话,runId 标识一次运行。长任务要把状态持久化并支持重新订阅,这样页面刷新后还能恢复观察;审批和资源权限始终在服务端复核。
8. 你在项目中怎样组织 Mastra 代码?参考答案
我把 Agent、Tool 和 Workflow 分目录定义,再在 src/mastra/index.ts 统一注册。Agent 保存模型、Instructions 和允许使用的能力;Tool 封装单个外部动作并校验输入输出;Workflow 固定关键步骤、分支和审批。开发时用 Studio 调试执行图和 Trace,生产请求则经过 BFF 完成身份与权限校验后再进入 Mastra Server。
9. Mastra 中的 RAG 是怎样接入 Agent 的?参考答案
我把它拆成离线和在线两部分。离线使用 MDocument 切分笔记,通过 Embedding 模型生成向量,再把向量、原文和来源写入 Vector Store;在线把向量查询封装成 Tool,Agent 需要证据时再调用。召回结果还要经过权限过滤和必要的重排,最终回答携带真实来源。这样向量库负责找候选资料,Agent 负责阅读证据并组织回答,两者职责不会混在一起。
10. Mastra 的 Workflow、Supervisor 和 Network 怎样选择?参考答案
执行路径已知、需要审计和恢复时,我优先用 Workflow;需要主 Agent 根据语义选择专业 Agent 时,可以使用 Supervisor;只有路径事先难以确定、确实需要动态组合多个 Agent、Tool 和 Workflow 时,才考虑 Network。Network 更灵活,但成本、失败路径和版本风险也更高,所以固定业务规则仍然放在 Workflow 和宿主代码里。
11. Mastra 项目怎样从本地部署到生产?参考答案
本地用 Mastra Server 运行组件、用 Studio 调试和查看 Trace。生产环境可以使用托管平台,也可以把 Server 部署在自己的容器或云平台,并单独选择托管或自托管的 Studio。无论采用哪种方式,浏览器都不直接持有模型和数据库密钥;BFF 负责认证、权限和限流,Memory、Workflow Snapshot 与向量索引使用可持久化存储,同时接入日志、Trace、成本和延迟监控。
# 接下来学什么
下一篇学习 LangChain 生态核心,重点理解 create_agent 的执行框架、LangGraph 的状态与持久化模型,以及 LangSmith 的追踪评测闭环。
# 参考资料
- Mastra:AI Agent Framework (opens new window)
- Mastra:AI Agents (opens new window)
- Mastra:Quickstart (opens new window)
- Mastra:AI Workflows (opens new window)
- Mastra:完整 RAG Pipeline (opens new window)
- Mastra:Research Assistant RAG 示例 (opens new window)
- Mastra:Agent Network 的演进与
.network()(opens new window) - Mastra:Server 与 Studio 部署模式 (opens new window)
- Mastra:MCP Guide (opens new window)
- Mastra:Workflow Snapshots (opens new window)
- Mastra:Agent Observability (opens new window)
- Mastra:Skills (opens new window)
- Mastra:Client SDK (opens new window)
- Mastra:Client SDK Agents API (opens new window)
- Mastra:Durable Agents (opens new window)
- Mastra:AI SDK 前端适配 (opens new window)