如何配置 Mastra code mode 让代理在隔离沙箱中执行多工具计算
当代理需要连续调用多个工具才能回答一个问题时(比如“取前 5 名产品并计算每个的平均评分”),默认行为是 agentic loop 每轮选一个工具、把完整工具响应追加进上下文,重复若干轮。Mastra 的 code mode(@mastra/core@1.38.0 起提供,目前处于 beta,API 稳定前可能有 breaking changes)改变了这一过程:模型为查询写出一个定制的 TypeScript 函数,在隔离沙箱中把配置好的工具当作 external_* 函数编排起来,做归约、聚合和运算,最后只向代理返回一个结构化结果。
这篇文章完成一件事:把 code mode 工具配置到你的 Agent 上,选一个合适的隔离执行边界,并验证生成的程序确实只在沙箱内运行。
准备条件
@mastra/core版本不低于1.38.0。- 按你要选择的执行边界安装对应包(三种都是可选,装哪个取决于第三节的选型):
# 进程内 V8 隔离
npm install @mastra/isolated-vm
# 或:QuickJS(WebAssembly,无原生二进制)
npm install @mastra/quickjs
# 或:远程微 VM 沙箱
npm install @mastra/e2b
isolated-vm 是原生插件,常见平台提供预编译二进制;只有在不匹配的平台才需要 C++ 工具链从源码编译。@mastra/quickjs 只包含 WebAssembly 模块,安装即复制文件,无需其他设置。
主路径:用 createCodeMode() 创建工具并挂到 Agent
createCodeMode() 返回工具本身和一段生成好的 instructions。不指定 id 时,工具名默认是 execute_typescript。两样都要加到 Agent:instructions 合并进 instructions 数组,工具以同一个 id 注册进 tools。
import { Agent } from '@mastra/core/agent'
import { createCodeMode, createTool } from '@mastra/core/tools'
import { LocalSandbox } from '@mastra/core/workspace'
import { z } from 'zod'
const getTopProducts = createTool({
id: 'getTopProducts',
description: 'Get top selling products',
inputSchema: z.object({ limit: z.number() }),
outputSchema: z.object({
products: z.array(z.object({ id: z.string(), name: z.string(), totalSales: z.number() })),
}),
execute: async ({ limit }) => fetchTopProducts(limit),
})
const getProductRatings = createTool({
id: 'getProductRatings',
description: 'Get ratings for a product',
inputSchema: z.object({ productId: z.string() }),
outputSchema: z.object({ ratings: z.array(z.object({ score: z.number() })) }),
execute: async ({ productId }) => fetchRatings(productId),
})
const { tool, instructions } = createCodeMode({
tools: { getTopProducts, getProductRatings },
sandbox: new LocalSandbox(),
})
export const shopAgent = new Agent({
id: 'shop-assistant',
name: 'shop-assistant',
instructions: ['You are a helpful shopping assistant.', instructions],
model: 'openai/gpt-5.6-sol',
tools: { execute_typescript: tool },
})
示例中的 fetchTopProducts / fetchRatings 是文档示例里假定的数据获取函数,替换为你自己的实现;model: 'openai/gpt-5.6-sol' 是文档示例展示的模型标识,可按你接入的模型替换。
配置项的适用条件(来自 createCodeMode() reference):
tools:暴露给生成代码的工具,以external_<id>函数形式出现。生成代码只能调用传给这次createCodeMode()的工具,别的不行。sandbox:执行生成代码的沙箱。除非 Agent 运行在自带沙箱的 workspace 中,或 transport 自带执行边界,否则必须显式传入。timeout:执行超时(毫秒),默认30000。id:生成的工具 id,默认execute_typescript。
注意 new LocalSandbox() 的含义:它和主机共享文件系统,生成的程序以主机 node 进程、带主机权限运行,只应用于受信任的代码或本地开发。生产边界见下一节。
选择隔离执行边界
code mode 的隔离边界由 transport 决定。三种 transport 都在主机侧执行同一套白名单、工具校验和 tracing,区别在程序本身能触达什么、主机需要提供什么(对照表来自 QuickJsCodeModeTransport 文档):
StdioCodeModeTransport(默认) |
IsolatedVmCodeModeTransport |
QuickJsCodeModeTransport |
|
|---|---|---|---|
| 隔离边界 | Workspace sandbox | V8 isolate | QuickJS WebAssembly runtime |
| 需要沙箱 | 是 | 否 | 否 |
| 原生二进制 | 沙箱内的 Node.js runtime | 是 | 否 |
| Node.js 标志 | 无 | Node.js 20 及以后需要 --no-node-snapshot |
无 |
| 可在浏览器运行 | 否 | 否 | 是 |
| 执行速度 | 最快 | 快 | 最慢 |
进程内 V8 隔离:IsolatedVmCodeModeTransport
不需要沙箱、不派生进程、不写临时文件,适合没有 OS 级沙箱的 serverless 或多租户主机。把 transport 作为 createCodeMode() 的第二个参数传入,配置里不再需要 sandbox:
import { createCodeMode } from '@mastra/core/tools'
import { IsolatedVmCodeModeTransport } from '@mastra/isolated-vm'
const { tool, instructions } = createCodeMode(
{ tools: { getTopProducts, getProductRatings } },
new IsolatedVmCodeModeTransport({ memoryLimitMb: 128 }),
)
硬性前提:在 Node.js 20 及以后,宿主进程必须带 --no-node-snapshot 启动,否则创建 isolate 会崩溃,构造器会以错误形式报告缺少该标志:
NODE_OPTIONS=--no-node-snapshot npm run dev
isolate 没有文件系统、网络、进程或模块访问能力,唯一能力就是回调到主机的 external_* 函数。memoryLimitMb(默认 128)是 V8 isolate 堆上限(MiB),超限的程序被终止,工具返回错误结果。每次运行创建全新 isolate,运行结束后销毁。
替代分支:QuickJS(主机装不了原生插件时)
主机既不能装原生插件也不能设 Node.js 标志(serverless 平台常见)时,用 @mastra/quickjs 的 QuickJsCodeModeTransport。执行边界相同——程序无文件系统、网络、进程、模块访问——代价是执行更慢:QuickJS 是解释执行,计算密集循环可比 V8 isolate 慢几十倍;而主要时间在 await external_* 上的程序两者表现接近,Code Mode 程序通常属于后者。
import { createCodeMode } from '@mastra/core/tools'
import { QuickJsCodeModeTransport } from '@mastra/quickjs'
const { tool, instructions } = createCodeMode(
{ tools: { getTopProducts, getProductRatings } },
new QuickJsCodeModeTransport({ memoryLimitMb: 128 }),
)
参数:memoryLimitMb(默认 128,MiB 堆上限,超限程序被终止并返回错误结果);maxStackSizeBytes(默认 1048576,字节,通常由失控递归触发)。
替代分支:远程微 VM 沙箱(E2B)
默认的 StdioCodeModeTransport 把程序写到主机文件系统再跑 node,这只有在沙箱与主机共享文件系统(如 LocalSandbox)时成立。E2B 这类在自己微 VM 里运行的远程沙箱没有主机路径,需要把程序写进沙箱文件系统的 transport。@mastra/e2b 提供 E2BCodeModeTransport,作为第二个参数传入:
import { createCodeMode } from '@mastra/core/tools'
import { E2BSandbox, E2BCodeModeTransport } from '@mastra/e2b'
const { tool, instructions } = createCodeMode(
{
tools: { getWeather, getForecast },
sandbox: new E2BSandbox({ timeout: 60_000 }),
},
new E2BCodeModeTransport(),
)
使用前需要可用的 E2B API key:E2BSandbox 的 apiKey 参数缺省时回退到 E2B_API_KEY 环境变量。E2BCodeModeTransport 会在沙箱未运行时自动启动它,在主机侧用 esbuild 剥离 TypeScript(不依赖沙箱内的 Node 版本),在 VM 内运行 node,并在结束后清理程序文件。更多 E2B 沙箱参数见 E2B 集成文档。
验证配置是否生效
验证分两层:
- 行为层:向 Agent 提出一个需要组合多个工具的问题,例如文档示例中的 “What are the top 5 products and the average rating for each?”。配置正确时,模型发出一次
execute_typescript调用,而不是多次分开的工具调用。文档示例展示的生成程序如下(示例代码,你的工具不同则不同):
const top = await external_getTopProducts({ limit: 5 })
const ratings = await Promise.all(
top.products.map(p => external_getProductRatings({ productId: p.id })),
)
return top.products.map((product, i) => {
const scores = ratings[i].ratings.map(r => r.score)
const avg = scores.reduce((sum, s) => sum + s, 0) / scores.length
return {
name: product.name,
sales: product.totalSales,
averageRating: Math.round(avg * 100) / 100,
}
})
所有评分查询并行执行,平均数在 JavaScript 中算出,代理收到一个结构化结果。
- 返回值层:生成的工具返回
CodeModeToolResult:
success: boolean——生成代码是否无抛错地跑完;result: unknown——生成代码的返回值(可选);logs: string[]——按顺序捕获的console.log/console.info/console.warn/console.error输出(可选);error: { message, name?, line? }——代码抛错或执行失败时的错误详情(可选)。
success 为 false 时看 error.message 和 error.line 定位生成代码的问题;正常跑完但结果不对时,logs 是调试入口。
如果只想检查注入给模型的提示内容,用 createCodeModeInstructions():
import { createCodeModeInstructions } from '@mastra/core/tools'
console.log(
createCodeModeInstructions({
tools: { getTopProducts, getProductRatings },
}),
)
输出包含使用约定和每个工具一行带类型的 declare function external_<id>(...)。工具 id 会被净化成合法 TypeScript 函数名;净化后重名会抛错——如果这里报错,说明你的工具 id 命名冲突。
另外,只有需要单独管理 instructions 时才用 createCodeModeTool();多数 Agent 应使用 createCodeMode(),让工具和配套 instructions 保持绑定。
限制与注意事项
- beta:code mode 相关 API 在稳定前可能无 major 版本号升级就发生 breaking change。
LocalSandbox无隔离:程序以主机权限的node进程运行,只用于受信任代码或本地开发;生产请用 V8 isolate、QuickJS 或远程沙箱。- Node.js 20+ 的启动标志:漏掉
--no-node-snapshot时,IsolatedVmCodeModeTransport的构造器会报错,这是最典型的启动问题。 - 内存与超时:
memoryLimitMb超限、或超过createCodeMode()的timeout(异步挂起和同步死循环都覆盖,运行结束后 isolate/runtime 即销毁)都会导致程序被终止、工具返回错误结果。 - 最小权限隔离:一个 Agent 可以挂多个 code mode 工具,多次调用
createCodeMode()、每次给不同id和不同的tools子集,各工具只能调用自己那次调用声明的external_*函数,互不可达。instructions 要每个都加进 Agent。
完整文档见 Code mode 与 createCodeMode() reference;沙箱本身的概念见 Sandbox overview。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.22 K638- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python440
cherry-studio🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端TypeScript2.01 K146
hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程Python49368
new-apiAI模型聚合管理中转分发系统,一个应用管理您的所有AI模型,支持将多种大模型转为统一格式调用,支持OpenAI、Claude、Gemini等格式,可供个人或者企业内部管理与分发渠道使用。🍥 A Unified AI Model Management & Distribution System. Aggregate all your LLMs into one app and access them via an OpenAI-compatible API, with native support for Claude (Messages) and Gemini formats.Go21143
JeecgBoot🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~Java34551