以编程方式使用文档

解释器为代理提供了一个可编程的工作空间,让它们可以探索数据、协调工具调用,并将中间结果保存在模型上下文之外。代理编写代码来表达其意图,然后由 **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 实例数组。
memoryLimitBytes64 * 1024 * 1024 <br/>(64 MB)QuickJS 内存限制(字节)。
maxStackSizeBytes320 * 1024QuickJS 堆栈大小限制(字节)。
executionTimeoutMs5000每次求值的超时时间(毫秒)。负值将禁用超时。
systemPromptnull覆盖内置解释器的系统提示。
maxPtcCalls256最大 tools.* 次调用每求值。仅在 null 受信任环境中使用。
maxResultChars4000保留自控制台输出、结果和错误字符串的最大字符数。
toolName"eval"暴露给模型的解释器工具名称。
captureConsoletrue是否 console.log, console.warnconsole.error 输出被捕获。
subagentstrue暴露内置 task() 全局变量用于 动态子代理。设置为 false 以要求通过正常的 task 工具路径分发子代理。