Mastra 集成
摘要: 本文将展示如何通过 2 行代码,将强大的 Agent 基础设施平台 AgentRun 与流行的 Agent 编排框架 Mastra 结合。让 Mastra 继续负责上层工作流,而 AgentRun 提供模型、沙箱和工具集等底层能力,实现"1+1 > 2"的效果。
核心痛点:Agent 开发的"最后一公里"
在构建 Agent 应用时,开发者常常在解决了核心的编排逻辑后,遇到一系列棘手的工程问题:
- 模型供应商锁定:切换不同的大模型(如从 OpenAI 到 Qwen)意味着需要重写 SDK 调用、适配鉴权和参数,成本高昂。
- 基础设施重复造轮子:代码沙箱(Sandbox)、工具集(ToolSet)等关键组件,都需要大量时间和精力自行搭建和维护。
- 技术栈整合难题:如果你的项目已经采用了 Mastra 这样的编排框架,如何优雅地接入一个更全面、更专业的 Agent 基础设施平台,而不是推倒重来?
本文为你提供一个简洁高效的解决方案。
强强联合:Mastra 作大脑,AgentRun 作基座
要理解这个方案的优势,我们首先需要明确两个平台的定位:
- Mastra:Agent 的"大脑"与"指挥官" 它专注于 Agent 编排、工作流定义和多 Agent 协作。你可以用它设计复杂的任务流,决定 Agent 应该在何时、以何种顺序调用哪些能力。
- AgentRun:Agent 的"能力底座"与"能源中心"
作为阿里云的 Agent 基础设施平台,它提供 Agent 运行所需的一切底层能力:
- 统一模型层:通过统一的 API 访问和切换多种模型(通义千问、OpenAI 等)
- 安全沙箱:隔离执行代码、访问文件等高风险操作(支持代码解释器和浏览器自动化)
- 工具集管理:统一管理和调用各种外部工具(OpenAPI、MCP 协议)
- 观测与治理:日志、监控、审计等企业级能力
因此,最佳实践是将两者结合:
- Mastra (编排层) + AgentRun (能力层) = 高效、可扩展的 Agent 应用
- Mastra 负责"做什么"和"怎么做",AgentRun 负责提供完成任务所需的"工具"和"动力"。
准备工作:安装与配置
安装 SDK 在你的 Node.js/TypeScript 项目中执行:
- npm
- Yarn
- pnpm
- Bun
npm install @agentrun/sdk @mastra/core --registry=https://registry.npmmirror.com
yarn add @agentrun/sdk @mastra/core --registry=https://registry.npmmirror.com
pnpm add @agentrun/sdk @mastra/core --registry=https://registry.npmmirror.com
bun add @agentrun/sdk @mastra/core --registry https://registry.npmmirror.com
AgentRun SDK 支持如下配置,可以通过多种方式注入程序
| Config 配置项 | 环境变量 | 说明 |
|---|---|---|
access_key_id | AGENTRUN_ACCESS_KEY_ID、ALIBABA_CLOUD_ACCESS_KEY_ID | Access Key ID |
access_key_secret | AGENTRUN_ACCESS_KEY_SECRET、ALIBABA_CLOUD_ACCESS_KEY_SECRET | Access Key Secret |
security_token | AGENTRUN_SECURITY_TOKEN、ALIBABA_CLOUD_SECURITY_TOKEN | STS Token |
account_id | AGENTRUN_ACCOUNT_ID、FC_ACCOUNT_ID | 账号 ID |
token | 请求数据链路时,使用的 token | |
region_id | AGENTRUN_REGION、FC_REGION | 区域 |
timeout | ||
read_timeout | ||
control_endpoint | AGENTRUN_CONTROL_ENDPOINT | 控制端点 |
data_endpoint | AGENTRUN_DATA_ENDPOINT | 数据端点 |
devs_endpoint | DEVS_ENDPOINT | Devs 端点 |
AGENTRUN_SDK_DEBUG | 开启 DEBUG 日志 | |
headers | 发送请求时,附加的头部 |
要访问您在云上的 AgentRun 资源,需要配置阿里云的密钥。通常您的密钥为 ACCESS_KEY_ID 和 ACCESS_KEY_SECRET。当使用 AssumeRole 方式生成临时密钥时,还会存在 SECURITY_TOKEN。 如果您只需要访问数据链路,也可以仅配置 AgentRun Token
- 通过 .env 配置
- 通过 export 配置
- 通过代码配置
.env 是一个特殊的文件,用来约定程序运行需要的环境变量。
将您的 Agent 需要的环境变量写入在 .env 后,SDK 会自动读取 .env 的配置。这样既方便管理,又避免了在代码中硬编码敏感信息。
请确保将 .env 文件添加到 .gitignore,避免误提交到版本控制系统,导致敏感信息泄漏。
AGENTRUN_ACCESS_KEY_ID="LT*************"
AGENTRUN_ACCESS_KEY_SECRET="DU*************"
AGENTRUN_ACCOUNT_ID="143*********149"
AGENTRUN_REGION="cn-hangzhou"
如果仅仅是一次性配置环境变量,也可以在终端中临时进行配置环境变量
使用该方式,仅有 ./start 可以访问到环境变量
AGENTRUN_ACCESS_KEY_ID="LT*************" AGENTRUN_ACCESS_KEY_SECRET="DU*************" ./start
使用该方式,当前 shell 及子进程中均能访问到环境变量
export AGENTRUN_ACCESS_KEY_ID="LT*************"
export AGENTRUN_ACCESS_KEY_SECRET="DU*************"
./start
您也可以在代码中直接创建 Config 对象来全局参数配置。这种方式适合需要动态切换配置的场景:
创建的 Config 对象可以在调用 SDK API 时作为参数传入。如果同时存在环境变量配置和代码配置,SDK 会优先使用代码中显式传入的配置。
对于需要支持多账号或多区域的应用,可以创建多个 Config 对象并在调用时指定。例如,某些操作在国内区域执行,某些操作在海外区域执行。
from agentrun.utils.config import Config
config = Config(
access_key_id="LT*************",
access_key_secret="DU*************",
)
import { Config } from '@agentrun/sdk';
const config = new Config({
accessKeyId: 'LT*************',
accessKeySecret: 'DU*************',
});
在部署到 AgentRun 时,您可以在 Agent Runtime 配置环境变量来替代您在本地 .env。
为了增强安全性,可以通过配置角色的方式来替代 AGENTRUN_ACCESS_KEY_ID 等环境变量,AgentRun 在启动您的 Agent 时,会根据角色权限为您创建临时的密钥并注入在环境变量中。
配置模型服务
要创建模型服务,需要进入 AgentRun 控制台 - 模型管理

AgentRun 支持注册第三方的模型,也可以直接在函数计算 FunModel 部署开源/私有大模型 对于注册的第三方模型,需要选择模型的来源(用来确认请求的交互协议以及 BaseURL) 一个模型服务可以配置多个模型,如果通过 SDK 调用且未明确指定模型名时,会使用列表的第一个模型

创建完成后,您应该可以在模型列表看到您创建的模型

配置浏览器沙箱
要创建 Sandbox,需要进入 AgentRun 控制台 - 运行时与沙箱 - Sandbox 沙箱

AgentRun 提供了多种 Sandbox,这里以浏览器沙箱为例

如果仅作测试,除去沙箱名称外的其他信息均不需要修改;当您要将沙箱正式对外使用时,除去配置计算资源规格等参数外,建议您正确配置 “入站:访问凭证配置” 避免被第三方请求您的资源造成非预期的费用

创建完成后,您应该可以在沙箱列表看到您创建的沙箱

配置时间获取 MCP 工具
要创建工具,需要进入 AgentRun 控制台 - 其他 - 工具管理

AgentRun 工具市场已经内置了大量预置的工具,方便您快速进行集成。这里以 “时间服务” MCP 工具为例

如果仅作测试,除去名称外的其他信息均不需要修改;当您要正式对外使用时,建议您正确配置 “访问凭证” 避免被第三方请求您的资源造成非预期的费用

核心改动:2 行代码接入 AgentRun 资源
现在,我们进入最关键的环节。你只需在 Mastra 的 Agent 初始化逻辑中,引入 AgentRun 的模型即可。
这正是那核心的 2 行代码:
import { model } from '@agentrun/sdk/integration/mastra'; // 1. 引入 AgentRun SDK
const llm = await model({ name: 'my-agentrun-model' }); // 2. 创建指向 AgentRun 模型的实例
// 1. 引入 AgentRun SDK
import { model } from '@agentrun/sdk/integration/mastra';
async function createDemoAgent() {
const mastraAgent = new Agent({
id: 'run_agent',
name: 'AgentRun',
instructions: `
你是一个智能助手,你会帮助用户完成各种任务。你的输出,必须是返向输出的。
如,用户输入 “你好”,应该输出 “?么的您助帮以可么什有,好您”
`.trim(),
// 2. 将 AgentRun 的模型转换为 Mastra 可以识别的模型
model: await model({ name: 'my-agentrun-model' }),
});
return mastraAgent;
}
当然,工具、沙箱等资源也可以一键接入
// 1. 引入 AgentRun SDK
import { model, sandbox, toolset } from '@agentrun/sdk/integration/mastra';
async function createDemoAgent() {
const mastraAgent = new Agent({
id: 'run_agent',
name: 'AgentRun',
instructions: `
你是一个智能助手,你会帮助用户完成各种任务。你的输出,必须是返向输出的。
如,用户输入 “你好”,应该输出 “?么的您助帮以可么什有,好您”
`.trim(),
model: await model({ name: 'my-agentrun-model' }),
// 2. 将 AgentRun 的工具转换为 Mastra 可以识别的模型
tools: async () => {
const sandboxTools = await sandbox({
templateName: 'my-agentrun-browser',
});
const toolsetTools = await toolset({ name: 'my-agentrun-time-mcp' });
const allTools = { ...sandboxTools, ...allTools };
return allTools;
},
});
return mastraAgent;
}
在这里,有一些常见的问题需要您注意
-
如果您使用 Bun 作为运行时,那么 Playwright 可能会超时,相关 Issue 见 Playwright connectOverCDP() not working
-
您需要自行安装 Playwright 依赖,为了避免引入过大的依赖项,AgentRun SDK 不会为您自动安装 Playwright
-
如果相较于 Playwright,您更偏好于 Puppeteer 或 Selenium,您也可以使用沙箱的
sandbox.getCdpUrl();获取 CDP 端点地址,通过 Puppeteer 或 Selenium 进行连接 -
AgentRun SDK 封装了一些常用的操作,但这也导致沙箱的生命周期无法被您管控,如果您的业务需要精细化控制沙箱,建议您自行维护沙箱工具
-
如果您要使用 Mastra 的 Dev Server,那么 Mastra 实例需要是同步声明的(需要被
export),Mastra Agent 也应该是同步声明的,因此模型也需要被同步声明。
但访问 AgentRun 是一个异步的网络请求行为,因此无法直接在同步上下文中调用await model(...)。要解决该问题,您可以使用
model: ()=>model(...)的方式初始化模型,这样可以在 Agent 被调用时才真正初始化模型。但这会导致每个请求都会GetModelService,可能会导致 流控。
因此,建议您将产生的模型实例进行缓存,避免不必要的开销。// 缓存大模型实例化的结果
let llm = null
export const mastraAgent = new Agent({
id: 'run_agent',
name: 'AgentRun',
instructions: `
你是一个智能助手,你会帮助用户完成各种任务。你的输出,必须是返向输出的。
如,用户输入 “你好”,应该输出 “?么的您助帮以可么什有,好您”
`.trim(),
// 仅在未初始化的情况下获取大模型
model: async ()=> {
if (llm) return llm
// 此时,您也可以根据不同的请求上下文,使用不同的模型
llm = await model({ name: 'my-agentrun-model' }),
return llm
}
});
您可以询问大模型今天是几号,也可以要求他打开某个页面,访问其中的内容
data: {"type":"RUN_STARTED","threadId":"2c7b5272-f2b5-401e-a6a4-f62c6b8f44bb","runId":"a7760759-49ba-41c5-9bd2-247902b7dfc3"}
data: {"type":"TOOL_CALL_START","toolCallId":"call_df2498ad5d43415a8d3ad0e9","toolCallName":"start-mcp-time-ggda_get_current_time"}
data: {"type":"TOOL_CALL_ARGS","toolCallId":"call_df2498ad5d43415a8d3ad0e9","delta":"{}"}
data: {"type":"TOOL_CALL_END","toolCallId":"call_df2498ad5d43415a8d3ad0e9"}
data: {"type":"TOOL_CALL_RESULT","messageId":"tool-result-call_df2498ad5d43415a8d3ad0e9","toolCallId":"call_df2498ad5d43415a8d3ad0e9","content":"{\"error\":true,\"message\":\"Tool input validation failed for start-mcp-time-ggda_get_current_time. Please fix the following errors and try again:\\n- timezone: Invalid input: expected string, received undefined\\n\\nProvided arguments: {}\",\"validationErrors\":{\"_errors\":[],\"timezone\":{\"_errors\":[\"Invalid input: expected string, received undefined\"]}}}","role":"tool"}
data: {"type":"TOOL_CALL_START","toolCallId":"call_5a1238ab6aff48658b28d7e4","toolCallName":"start-mcp-time-ggda_get_current_time"}
data: {"type":"TOOL_CALL_ARGS","toolCallId":"call_5a1238ab6aff48658b28d7e4","delta":"{\"timezone\":\"UTC\"}"}
data: {"type":"TOOL_CALL_END","toolCallId":"call_5a1238ab6aff48658b28d7e4"}
data: {"type":"TOOL_CALL_RESULT","messageId":"tool-result-call_5a1238ab6aff48658b28d7e4","toolCallId":"call_5a1238ab6aff48658b28d7e4","content":"[{\"type\":\"text\",\"text\":\"{\\n \\\"timezone\\\": \\\"UTC\\\",\\n \\\"datetime\\\": \\\"2026-01-30T10:13:25+00:00\\\",\\n \\\"is_dst\\\": false\\n}\"}]","role":"tool"}
data: {"type":"TEXT_MESSAGE_START","messageId":"2f5a07f6-d65c-4a33-b62c-610053fd8091","role":"assistant"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"2f5a07f6-d65c-4a33-b62c-610053fd8091","delta":"。"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"2f5a07f6-d65c-4a33-b62c-610053fd8091","delta":"时"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"2f5a07f6-d65c-4a33-b62c-610053fd8091","delta":"区"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"2f5a07f6-d65c-4a33-b62c-610053fd8091","delta":" UTC"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"2f5a07f6-d65c-4a33-b62c-610053fd8091","delta":" 在 20"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"2f5a07f6-d65c-4a33-b62c-610053fd8091","delta":"26 年 1"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"2f5a07f6-d65c-4a33-b62c-610053fd8091","delta":" 月 30 日"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"2f5a07f6-d65c-4a33-b62c-610053fd8091","delta":",现在是"}
data: {"type":"TEXT_MESSAGE_END","messageId":"2f5a07f6-d65c-4a33-b62c-610053fd8091"}
data: {"type":"RUN_FINISHED","threadId":"2c7b5272-f2b5-401e-a6a4-f62c6b8f44bb","runId":"a7760759-49ba-41c5-9bd2-247902b7dfc3"}
客户端调用方式
AgentRun 提供了两种调用方式
- OpenAI Chat Completions 兼容协议: 使用场景广泛,可以快速接入到 Open WebUI、Cherry Studio 等各种场景,方便以大模型的方式调用您的 Agent
- AG-UI 协议: 开源的 Agent 交互规范,适合与前端页面交互时用于内容渲染,可以流式展示工具调用的细节
通过 AgentRun Server,你可以快速将 Agent 与这两种协议进行对接。
async function* invokeAgent(
request: AgentRequest,
): AsyncGenerator<AgentEventItem> {
// AgentRunServer 本身并非和 Mastra 绑定,您可以通过自己转换的方式,与任何 Agent 框架进行集成
// 通过 Mastra 集成提供的 MastraConverter,可以方便地将 Mastra 的流式输出转换为 AgentRun 事件流
const converter = new MastraConverter();
const mastraStream = await mastraAgent.stream(
request.messages.map(
(msg) =>
({
role: msg.role,
content: msg.content || '',
}) as any,
),
);
for await (const chunk of mastraStream.fullStream) {
const events = converter.convert(chunk);
for (const event of events) {
// 这里返回的内容完全由您控制,您可以实现一个 “大模型” 做内容反转,但实现上可能只是一行 reverse 代码
yield event;
}
}
}
const server = new AgentRunServer({
invokeAgent,
config: { corsOrigins: ['*'] },
});
server.start({ port: 9000 });
AgentRunServer 会在 9000 端口启动 http 服务,您可以通过如下代码进行调用,也可以在不同的语言中,安装 OpenAI、AG-UI 的 SDK 进行调用
- OpenAI Chat Completions 非流式
- OpenAI Chat Completions 流式
- AG-UI
curl http://127.0.0.1:9000/openai/v1/chat/completions \
-X POST \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": "天空为什么是蓝的?"
}
],
"stream": false
}'
{"id":"chatcmpl-1769763445398-g67ex5l","object":"chat.completion","created":1769763445,"model":"agentrun","choices":[{"index":0,"message":{"role":"assistant","content":"?的蓝是么什为天"},"finish_reason":"stop"}],"usage":{"prompt_tokens":0,"completion_tokens":0,"total_tokens":0}}
curl http://127.0.0.1:9000/openai/v1/chat/completions \
-X POST \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": "天空为什么是蓝的?"
}
],
"stream": true
}'
data: {"id":"chatcmpl-1769763283836-g5t0p3m","object":"chat.completion.chunk","created":1769763283,"model":"agentrun","choices":[{"index":0,"delta":{"role":"assistant","content":"?"},"finish_reason":null}]}
data: {"id":"chatcmpl-1769763283836-g5t0p3m","object":"chat.completion.chunk","created":1769763283,"model":"agentrun","choices":[{"index":0,"delta":{"content":"的"},"finish_reason":null}]}
data: {"id":"chatcmpl-1769763283836-g5t0p3m","object":"chat.completion.chunk","created":1769763283,"model":"agentrun","choices":[{"index":0,"delta":{"content":"蓝"},"finish_reason":null}]}
data: {"id":"chatcmpl-1769763283836-g5t0p3m","object":"chat.completion.chunk","created":1769763283,"model":"agentrun","choices":[{"index":0,"delta":{"content":"是"},"finish_reason":null}]}
data: {"id":"chatcmpl-1769763283836-g5t0p3m","object":"chat.completion.chunk","created":1769763283,"model":"agentrun","choices":[{"index":0,"delta":{"content":"么什为天"},"finish_reason":null}]}
data: {"id":"chatcmpl-1769763283836-g5t0p3m","object":"chat.completion.chunk","created":1769763283,"model":"agentrun","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]
curl http://127.0.0.1:9000/ag-ui/agent \
-X POST \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": "天空为什么是蓝的?"
}
]
}'
data: {"type":"RUN_STARTED","threadId":"35884228-0bbc-46d1-b476-5665bfb4fb9d","runId":"43d67a14-95e4-4e36-9f0f-9892362d2661"}
data: {"type":"TEXT_MESSAGE_START","messageId":"be7300f5-15c0-4fee-b007-aa25a07df54d","role":"assistant"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"be7300f5-15c0-4fee-b007-aa25a07df54d","delta":"?"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"be7300f5-15c0-4fee-b007-aa25a07df54d","delta":"么"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"be7300f5-15c0-4fee-b007-aa25a07df54d","delta":"的您"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"be7300f5-15c0-4fee-b007-aa25a07df54d","delta":"助帮以"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"be7300f5-15c0-4fee-b007-aa25a07df54d","delta":"可么什有,好"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"be7300f5-15c0-4fee-b007-aa25a07df54d","delta":"您"}
data: {"type":"TEXT_MESSAGE_END","messageId":"be7300f5-15c0-4fee-b007-aa25a07df54d"}
data: {"type":"RUN_FINISHED","threadId":"35884228-0bbc-46d1-b476-5665bfb4fb9d","runId":"43d67a14-95e4-4e36-9f0f-9892362d2661"}
当然,如果您希望使用 Mastra 官方的 Server,则完全可以不使用 AgentRunServer,按照您的场景启动服务即可。
完整的代码
import { Agent } from '@mastra/core/agent';
import { AgentRunServer, type AgentRequest } from '@agentrun/sdk/server';
import {
MastraConverter,
type AgentEventItem,
model,
toolset,
sandbox,
} from '@agentrun/sdk/integration/mastra';
const mastraAgent = new Agent({
id: 'run_agent',
name: 'AgentRun',
instructions: `
你是一个智能助手,你会帮助用户完成各种任务。你的输出后,必须是返向输出的。
如,用户输入 “你好”,应该输出 “?么的您助帮以可么什有,好您”
`.trim(),
model: () => model({ name: 'ohyee-test' }),
tools: async () => {
const sandboxTools = await sandbox({ templateName: 'my-agentrun-browser' });
const toolsetTools = await toolset({ name: 'my-agentrun-time-mcp' });
const allTools = { ...sandboxTools, ...allTools };
return allTools;
},
});
async function* invokeAgent(
request: AgentRequest,
): AsyncGenerator<AgentEventItem> {
const converter = new MastraConverter();
const mastraStream = await mastraAgent.stream(
request.messages.map(
(msg) =>
({
role: msg.role,
content: msg.content || '',
}) as any,
),
);
for await (const chunk of mastraStream.fullStream) {
const events = converter.convert(chunk);
for (const event of events) {
yield event;
}
}
}
const server = new AgentRunServer({
invokeAgent,
config: { corsOrigins: ['*'] },
});
console.log(`
curl http://127.0.0.1:9000/openai/v1/chat/completions -X POST \\
-H "Content-Type: application/json" \\
-d \'{"messages": [{"role": "user", "content": "天空为什么是蓝的?"}], "stream": true}\'
curl http://127.0.0.1:9000/ag-ui/agent -X POST \\
-H "Content-Type: application/json" \\
-d \'{"messages": [{"role": "user", "content": "天空为什么是蓝的?"}]}\'
`);
server.start({ port: 9001 });
下一步工作
到此为止,您已经成功将 Mastra 与 AgentRun 结合,打造了一个功能强大的 Agent 应用。接下来,您可以:
- 深入了解 AgentRun 的更多功能,如 记忆、知识库
- 将您的 Agent 部署到 AgentRun 云平台,享受企业级的运维和治理能力
- 在 AgentRun 部署您的私有大模型,实现更高的数据安全和定制化需求