解释器为代理提供了一个可编程的工作空间,让它们可以探索数据、协调工具调用,并将中间结果保存在模型上下文之外。代理编写代码来表达其意图,然后由 **in-memory** 运行时执行该代码并返回相关结果。
在哪里 沙箱 是针对环境进行操作的一种代码优先方式(如运行命令、安装依赖和编辑文件),而解释器则是代理循环内部进行操作的一种代码优先方式:组合工具、保存状态以及决定哪些信息应该返回给模型。
为什么要使用解释器?
大多数代理工作都在模型推理和工具调用之间交替进行。模型可以在一次响应中触发多个工具调用,但该批次的执行一旦发出就固定了。没有任何东西可以循环、根据结果分支、重试失败或将一个调用的输出反馈到下一个调用中,除非有另一次模型调用,而且每个结果都返回到模型的上下文中。模型还决定发出多少调用,因此要求它分发到数百个项目的任务是不可靠的,而且它往往只覆盖一个样本而不是全部。
解释器为代理提供了执行这些工作的运行时。每次迭代都会运行一个循环,工具从代码中被调用,中间值保存在变量中,只有紧凑的结果返回给模型。
Programmatic tool calling (PTC)
从解释器代码中调用选定的工具,包括循环、重试、分支和并行批次。
Dynamic subagents
从代码中分发子代理,用于大型输入的扇出、验证和递归工作流。
Stateful work
将中间值保存在运行时状态中,而不会使模型上下文过载。
Deterministic transforms
在代码中对结构化数据进行排序、分组、解析、验证、评分、聚合和探索。
选择一种模式
在代理循环内部使用解释器执行代码:组合工具、保存状态并控制返回给模型的内容。使用 沙箱 针对环境执行代码:shell 命令、包安装、测试、文件系统编辑和操作系统级执行。
| 需求 | 使用 |
|---|---|
| 一到两个简单的外部调用 | 常规工具调用 |
| 循环、分支、重试或聚合结果的小型程序 | 解释器 |
| 应从代码运行的多个选定工具调用 | 带 程序化工具调用 (PTC) |
| 多个独立的工作单元、多种视角或对大型输入的递归分析 | 带 动态子代理 |
| Shell 命令、包安装、测试或完整的操作系统文件系统访问 | 沙箱 |
快速入门
安装 QuickJS 中间件包,然后使用 middleware 参数在 create_deep_agent.
npm install deepagents @langchain/quickjs
pnpm add deepagents @langchain/quickjs
yarn add deepagents @langchain/quickjs
const agent = createDeepAgent({
model: "openai:gpt-5.5",
middleware: [createCodeInterpreterMiddleware()],
});
解释器的工作原理
中间件向代理添加了一个 eval 工具。在适当的时候,代理编写 JavaScript 并调用 eval;您不直接调用解释器。该工具在持久化上下文中运行代码,捕获 console.log,并返回最后一个表达式的结果。
代理可以像这样编写代码:
const rows = [
{ team: "alpha", score: 8 },
{ team: "beta", score: 13 },
{ team: "alpha", score: 21 },
];
const totals = rows.reduce((acc, row) => {
acc[row.team] = (acc[row.team] ?? 0) + row.score;
console.log(`${row.team} score: ${acc[row.team]}`)
return acc;
}, {});
totals;
代码在 **QuickJS**,一个轻量级 JavaScript 运行时。默认情况下,解释器代码无法访问主机文件系统、网络、shell、包管理器或时钟。它可以计算、保存状态,并写入 console.log,仅此而已。
两个明确的桥接扩展了这一范围:
- 工具,通过 程序化工具调用(PTC)。将工具的允许列表作为异步函数公开在
tools命名空间下。这些可以是代理自己的工具,也可以是您定义并传入的独立工具。 - 子代理,通过 动态子代理。从代码中调度配置好的子代理,并用纯 JavaScript 进行编排。
程序化工具调用默认关闭,直到您 启用它。子代理调度在代理有子代理时默认开启,您可以将其关闭。除非您主动暴露,否则没有任何东西会跨越 QuickJS 边界。
程序化工具调用(PTC)
程序化工具调用(PTC)在解释器内部的全局 tools 命名空间下公开选定的代理工具。与其让模型发出一工具调用、等待结果、然后决定下一个调用,代理可以直接编写代码以循环、分支、重试或并行批次的方式调用工具。
这在中间结果只是下一步输入时很有帮助:解释器在返回任何内容给模型之前会过滤或聚合它们,保持多步骤工作流的 token 效率。它与模型无关,通过中间件实现,而非提供商特定的工具调用 API。
中间件将每个允许列表中的工具作为异步函数公开在 tools下。代理使用 await调用它,在代码中处理结果,模型只看到最终的解释器输出,而非每个中间值。工具名称会被转换为驼峰命名,而输入对象仍遵循工具的模式,因此名为 web_search 的工具会变成 tools.webSearch(...):
const result: string = await tools.webSearch({
query: "deepagents interpreters",
});
启用 PTC
使用显式允许列表启用 PTC:
const agent = createDeepAgent({
model: "openai:gpt-5.5",
middleware: [createCodeInterpreterMiddleware({ ptc: ["web_search"] })],
});
启用 PTC 后,代理可以从解释器代码中调用允许列表中的工具。此示例并行搜索多个主题,并在返回给模型之前合并结果:
const topics = ["retrieval", "memory", "evaluation"];
const results = await Promise.all(
topics.map((topic) =>
tools.webSearch({ query: `${topic} best practices 2025` }),
),
);
results.join("\n\n");
动态子代理
动态子代理让解释器调度配置好的 子代理 使用内置的 task() 全局的。跨越多个独立单元的任务,例如审查目录中的每个文件或分类一批工单,变成一个将工作分散出去并综合结果的循环。
使用动态子代理的场景:
- 扇出和综合:并行运行多种相同类型的工作,然后合并结果。
- 验证:将发现发送给独立的验证子代理,只保留已确认的结果。
- 递归工作流:在工作集中保持解释器变量,选择切片,调用子代理,并优化结果。
有关配置、示例、编排模式和安全注意事项,请参阅 动态子代理.
安全
解释器使用QuickJS运行不受信任的JavaScript,具有严格的默认隔离。将此视为作用域解释器运行时,而不是完整的生产沙盒后端。
您通过PTC暴露的每个工具都是解释器代码可以使用的外部能力。将PTC允许列表视为权限边界:只暴露代理需要的工具,避免桥接可以访问敏感系统、花费资金、修改数据或调用无限制网络的广泛工具,除非该行为是有意为之。
| 能力 | 默认可用 | 如何暴露 |
|---|---|---|
| JavaScript 执行 | 是 | 添加解释器中间件 |
顶级 await | 是 | 在解释器代码中使用 promises |
console.log 捕获 | 是 | 通过以下方式禁用 captureConsole: false |
| 代理工具 | 否 | 添加 PTC 白名单 |
| 文件系统访问 | 否 | 添加 内置文件系统工具 通过 PTC 白名单 |
| 网络访问 | 否 | 通过 PTC 暴露特定网络工具 |
| 挂钟时间或日期时间访问 | 否 | 需要时暴露显式时间工具 |
| Shell 命令、包安装、测试、操作系统级执行 | 否 | 使用 沙箱后端 |
配置
createCodeInterpreterMiddleware 接受以下选项:
| 选项 | 默认值 | 用途 |
|---|---|---|
ptc | 省略 | PTC 允许列表:工具名称或 StructuredToolInterface 实例数组。 |
memoryLimitBytes | 64 * 1024 * 1024 <br/>(64 MB) | QuickJS 内存限制(字节)。 |
maxStackSizeBytes | 320 * 1024 | QuickJS 堆栈大小限制(字节)。 |
executionTimeoutMs | 5000 | 每次求值的超时时间(毫秒)。负值将禁用超时。 |
systemPrompt | null | 覆盖内置解释器的系统提示。 |
maxPtcCalls | 256 | 最大 tools.* 次调用每求值。仅在 null 受信任环境中使用。 |
maxResultChars | 4000 | 保留自控制台输出、结果和错误字符串的最大字符数。 |
toolName | "eval" | 暴露给模型的解释器工具名称。 |
captureConsole | true | 是否 console.log, console.warn 和 console.error 输出被捕获。 |
subagents | true | 暴露内置 task() 全局变量用于 动态子代理。设置为 false 以要求通过正常的 task 工具路径分发子代理。 |