解释器需要
langchain-quickjs>=0.3.0 和 Python 3.11 或更高版本。解释器需要
@langchain/quickjs。为什么使用解释器?
大多数智能体工作在模型推理和工具调用之间交替。模型可以在一次回合中触发多个工具调用,但一旦发出,该批次就是固定的。在没有另一个模型回合的情况下,没有任何东西可以循环、根据结果分支、重试失败或将有一次调用的输出输入到下一次调用,并且每个结果都会返回到模型的上下文中。模型还决定发出多少次调用,因此要求它跨数百个项目分发工作是不可靠的,并且它倾向于覆盖样本而不是每个项目。 解释器将这种编排移入代码,以便模型推理要做什么,而不是每个中间步骤。Programmatic tool calling (PTC)
从解释器代码中调用选定的工具,包括循环、重试、分支和并行批次。
Dynamic subagents
从代码中分发子智能体以进行发散、验证和大型输入上的递归工作流。
Stateful work
在运行时状态中保留中间值,而不会使模型上下文过载。
Deterministic transforms
对结构化数据进行排序、分组、解析、验证、评分和聚合,而无需另一个模型回合。
选择模式
在智能体循环内部使用解释器:组合工具、保留状态和控制返回给模型的内容。 使用 沙盒 针对环境编写代码:shell 命令、包安装、测试、文件系统编辑和操作系统级执行。快速入门
:::python 安装 QuickJS 中间件包,然后使用middleware 参数在 create_deep_agent 上传递解释器中间件。
:::
:::js
安装 QuickJS 中间件包,然后使用 middleware 参数在 createDeepAgent 上传递解释器中间件。
:::
:::python
解释器如何工作
中间件向智能体添加了一个eval 工具。当有用时,智能体编写 JavaScript 并调用 eval;您不会直接调用解释器。该工具在 QuickJS 上下文中运行代码,其变量可以在 eval 调用之间持久化,具体取决于持久化 mode。它捕获 console.log、console.warn 和 console.error,并返回最后一个表达式的结果。
智能体可以编写如下代码:
mode="thread"),解释器状态在同一个线程内的回合之间持久化。有关 mode 选项和快照生命周期的信息,请参阅 持久化。
:::
代码在 QuickJS 上运行,这是一个轻量级的 JavaScript 运行时。默认情况下,解释器代码无法访问主机文件系统、网络、shell、包管理器或时钟。它可以计算、保留状态并写入 console.log、console.warn 或 console.error,并且除此之外不做任何其他操作。
有两个显式的桥梁扩展了这种范围:
- 工具,通过 程序化工具调用 (PTC)。将允许的工具列表作为异步函数在
tools命名空间下提供。这些可以是智能体自己的工具或您定义并传递的独立工具。 - 子智能体,通过 动态子智能体。当智能体配置了子智能体时,解释器会暴露一个
task()全局变量用于从代码中调度它们。
task() 的子智能体调度默认情况下在智能体具有子智能体时开启,并且您可以将其关闭。没有其他东西可以跨越 QuickJS 边界。
程序化工具调用 (PTC)
程序化工具调用 (PTC) 在解释器下通过全局tools 命名空间暴露选定的智能体工具。与其要求模型发出一次工具调用、等待结果然后决定下一次调用,不如智能体可以编写代码来在循环、分支、重试或并行批次中调用工具。
这有助于在中间结果仅作为下一步输入时:解释器在结果返回模型之前进行过滤或聚合,保持多步工作流的 Token 高效。它是模型无关的,由中间件实现,而非特定提供者的工具调用 API。
中间件将每个允许的工具作为异步函数在 tools 下暴露。智能体使用 await 调用它,在代码中处理结果,模型仅看到最终的解释器输出,而非每个中间值。工具名称转换为 camelCase,而输入对象仍遵循工具的架构,因此名为 web_search 的工具变为 tools.webSearch(...):
启用 PTC
通过显式允许列表启用 PTC: :::python动态子智能体
下方的概述涵盖了何时使用动态子智能体和最小task() 模式。关于配置、编排示例、工作流触发和安全注意事项,请参阅 动态子智能体。
动态子智能体允许解释器使用内置 task() 全局从代码中调度配置的 子智能体。一个跨越多个独立单元的任务,例如审查目录中的每个文件或分派一批工单,变成一个发散工作并综合结果的循环。
使用动态子智能体用于:
- 发散和综合:并行运行相同类型的工作跨多个项目,然后组合结果。
- 验证:将发现发送给独立的验证子智能体,并仅保留确认结果。
- 递归工作流:在解释器变量中保留工作集,选择片段,调用子智能体,并细化结果。
持久化
使用mode 参数在 CodeInterpreterMiddleware 上控制跨回合状态:
"thread"(默认):状态跨eval调用和智能体回合持久。中间件在每个智能体回合后快照解释器状态,并在下一个回合前恢复它。"turn":状态跨一个智能体回合内的多个eval调用持久,然后在下一个回合重置。"call":每个eval调用在一个新的 REPL 中运行,没有来自先前调用的延续。
mode="thread" 时,快照是解释器内存 JavaScript 状态的序列化副本,包括智能体运行代码时存在的全局变量、变量、函数和导入的模块。跨对话回合的生命周期是:
- 回合开始,中间件恢复线程的最新解释器快照。
- 智能体调用
eval一次或多次。这些调用共享一个活动上下文;中间件在它们之间不快照。 - 回合结束,中间件将更新后的快照写入图状态。
- 下一个回合从该快照恢复,而非空运行时。
快照仅保留可序列化数据。函数、类和其他不可序列化的运行时对象在恢复后成为无法访问的遗留物。访问它们会抛出类似
Value for 'fn' was not restored because it is not serializable (type: function). 的错误mode="turn" 设置为仅持久化回合内的解释器状态,或使用 mode="call" 为每个 eval 设置一个全新的 REPL。
:::
安全
解释器使用 QuickJS 运行不受信任的 JavaScript,并具有严格的默认隔离。将其视为一个作用域解释器运行时,而非完整的生产沙盒后端。 通过 PTC 暴露的每个工具都是一个解释器代码可以使用的外部能力。将 PTC 允许列表视为权限边界:仅暴露智能体需要的工具,并避免桥接可以访问敏感系统、花费金钱、修改数据或调用无限制网络的广泛工具,除非这种行为是故意的。 :::python
:::python
代码执行的工作原理解释器代码在 QuickJS 编译为 WebAssembly 后运行,由
quickjs-rs 提供。WebAssembly 沙盒是隔离边界:JavaScript 在客体的线性内存中执行,不能读取或写入主机进程的内存。每个 LangGraph 线程获得自己的 WebAssembly 实例,因此一个线程上的解释器状态无法到达另一个线程。沙盒在 wasmtime 内部主机进程中运行,因此 wasmtime 漏洞是跳出沙盒的剩余路径。保持 wasmtime 更新。对于敌对的多租户工作负载,还应在隔离的 Worker 进程或容器中运行智能体。详情请参阅 quickjs-rs 安全指南。沙盒包含引擎,而不是你赋予它的功能。解释器代码可以调用桥接到其中的每个工具,因此请保持 PTC 允许列表狭窄。代码执行的工作原理解释器代码通过 QuickJS-Emscripten 在 WASM 沙盒化的 QuickJS 运行时中运行,而不是在主机 Node.js 进程中。将解释器视为范围受限的执行层:仅桥接智能体需要的工具和子智能体,并保持 PTC 允许列表狭窄。
配置
:::pythonCodeInterpreterMiddleware 接受以下选项:
:::js
createCodeInterpreterMiddleware 接受以下选项:
官方原文:src/oss/deepagents/interpreters.mdx · 非官方翻译,译文由 AI 生成,以英文原文为准。