以编程方式使用文档

解释器为代理提供了一个可编程的工作空间,让它们可以探索数据、协调工具调用,并将中间结果保存在模型上下文之外。代理编写代码来表达其意图,然后由 **in-memory** 运行时执行该代码并返回相关结果。

在哪里 沙箱 是针对环境进行操作的一种代码优先方式(如运行命令、安装依赖和编辑文件),而解释器则是代理循环内部进行操作的一种代码优先方式:组合工具、保存状态以及决定哪些信息应该返回给模型。

为什么要使用解释器?

大多数代理工作都在模型推理和工具调用之间交替进行。模型可以在一次响应中触发多个工具调用,但该批次的执行一旦发出就固定了。没有任何东西可以循环、根据结果分支、重试失败或将一个调用的输出反馈到下一个调用中,除非有另一次模型调用,而且每个结果都返回到模型的上下文中。模型还决定发出多少调用,因此要求它分发到数百个项目的任务是不可靠的,而且它往往只覆盖一个样本而不是全部。

解释器为代理提供了执行这些工作的运行时。每次迭代都会运行一个循环,工具从代码中被调用,中间值保存在变量中,只有紧凑的结果返回给模型。

Programmatic tool calling (PTC)

从解释器代码中调用选定的工具,包括循环、重试、分支和并行批次。

Dynamic subagents

从代码中分发子代理,用于大型输入的扇出、验证和递归工作流。

Stateful work

将中间值保存在运行时状态中,而不会使模型上下文过载。

Deterministic transforms

在代码中对结构化数据进行排序、分组、解析、验证、评分、聚合和探索。

选择一种模式

在代理循环内部使用解释器执行代码:组合工具、保存状态并控制返回给模型的内容。使用 沙箱 针对环境执行代码:shell 命令、包安装、测试、文件系统编辑和操作系统级执行。

需求使用
一到两个简单的外部调用常规工具调用
循环、分支、重试或聚合结果的小型程序解释器
应从代码运行的多个选定工具调用程序化工具调用 (PTC)
多个独立的工作单元、多种视角或对大型输入的递归分析动态子代理
Shell 命令、包安装、测试或完整的操作系统文件系统访问沙箱

快速入门

安装 QuickJS 中间件包,然后使用 middleware 参数在 create_deep_agent.

pip install -U "deepagents[quickjs]"
uv add "deepagents[quickjs]"
from deepagents import create_deep_agent
from langchain_quickjs import CodeInterpreterMiddleware

agent = create_deep_agent(
    model="openai:gpt-5.5",
    middleware=[CodeInterpreterMiddleware()],
)

解释器的工作原理

中间件向代理添加了一个 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:

from deepagents import create_deep_agent
from langchain_quickjs import CodeInterpreterMiddleware

agent = create_deep_agent(
    model="openai:gpt-5.5",
    middleware=[CodeInterpreterMiddleware(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() 全局的。跨越多个独立单元的任务,例如审查目录中的每个文件或分类一批工单,变成一个将工作分散出去并综合结果的循环。

使用动态子代理的场景:

  • 扇出和综合:并行运行多种相同类型的工作,然后合并结果。
  • 验证:将发现发送给独立的验证子代理,只保留已确认的结果。
  • 递归工作流:在工作集中保持解释器变量,选择切片,调用子代理,并优化结果。

有关配置、示例、编排模式和安全注意事项,请参阅 动态子代理.

持久化

CodeInterpreterMiddleware 默认情况下,在每个代理运行后快照解释器状态,并在下一个运行前恢复它。快照是解释器内存中JavaScript状态的序列化副本,包括在代理完成运行代码时存在的全局变量、变量、函数和导入模块。

跨对话轮次,生命周期如下:

  1. 一个轮次开始, CodeInterpreterMiddleware 恢复该线程的最新解释器快照。
  2. 代理调用 eval,代码可以读取或修改解释器变量。
  3. 代理运行完成,中间件将更新后的解释器状态快照到图状态中。
  4. 下一个轮次从恢复的解释器状态开始,而不是空的运行时。

在单个代理运行中,重复调用 eval 使用活动的解释器上下文对象。中间件不会在这些调用之间进行快照和恢复;它在运行完成时快照上下文,以便在后续轮次或检查点重放时恢复。

快照保留解释器内存,而不是外部世界的影响。如果解释器代码通过PTC调用工具,恢复先前的解释器快照不会撤销该工具调用的副作用。它只恢复记录或处理结果的解释器变量。

当图使用检查点时,这与 LangGraph时间旅行配对。恢复图检查点可以恢复存储在图状态中的解释器快照,因此您可以在调试或重放时返回到更早的代理上下文和解释器状态。

from deepagents import create_deep_agent
from langchain_quickjs import CodeInterpreterMiddleware
from langgraph.checkpoint.memory import MemorySaver

checkpointer = MemorySaver()

agent = create_deep_agent(
    model="openai:gpt-5.5",
    checkpointer=checkpointer,
    middleware=[
        CodeInterpreterMiddleware(
            snapshot_between_turns=True,  # Default
        )
    ],
)

您可以使用以下方式禁用跨轮次快照 snapshot_between_turns=False.

安全

解释器使用QuickJS运行不受信任的JavaScript,具有严格的默认隔离。将此视为作用域解释器运行时,而不是完整的生产沙盒后端。

您通过PTC暴露的每个工具都是解释器代码可以使用的外部能力。将PTC允许列表视为权限边界:只暴露代理需要的工具,避免桥接可以访问敏感系统、花费资金、修改数据或调用无限制网络的广泛工具,除非该行为是有意为之。

能力默认可用如何暴露
JavaScript执行添加解释器中间件
顶层 await在解释器代码中使用promise
console.log 捕获通过以下方式禁用 capture_console=False
代理工具添加 PTC 白名单
文件系统访问添加 内置文件系统工具 通过 PTC 白名单
网络访问通过 PTC 暴露特定网络工具
挂钟时间或日期时间访问需要时暴露显式时间工具
Shell 命令、包安装、测试、操作系统级执行使用 沙箱后端

配置

CodeInterpreterMiddleware 接受以下选项:

Kwarg 参数默认值用途
memory_limit64 * 1024 * 1024 <br/>(64 MB)QuickJS 堆内存限制(字节)。
timeout5.0每次求值的超时时间(秒)。
max_ptc_calls256最大 tools.* 次调用/求值。仅在 None 受信任环境中使用。
tool_name"eval"暴露给模型的解释器工具名称。
max_result_chars4000从结果和 stdout 块返回的最大字符数。
capture_consoleTrue是否 console.log, console.warnconsole.error 输出被捕获。
subagentsTrue暴露内置 task() 全局变量用于 动态子代理。设置为 False 以要求通过常规 task 工具路径进行子代理调度。
ptcNonePTC 白名单:工具名称列表或 BaseTool 实例。
snapshot_between_turnsTrue解释器状态快照是否在代理轮次之间保持。
max_snapshot_bytesNone最大序列化快照大小。默认为 memory_limit.