最近,Deep Agents 引入了动态子袋里这个新玩法:不再是每次工具调用都派发一个子袋里,而是让袋里自己写一段短脚本,把子袋里的协作全部编排好。这个脚本直接在代码解释器里跑——袋里写代码,代码执行袋里。
模式很强大,但背后藏着一个看似简单、实则极其棘手的问题:
安全又可靠地运行不可信代码,太难了。
运行不可信代码本身是个老话题,学界和工业界已经研究得很透。但运行「一个被不可信输入影响过的袋里写出来的代码」?那完全是另一回事。提示注入至今没有彻底解决,所以我们得假设:袋里写的代码迟早会干出它不该干的事。与其指望袋里老实听话,不如直接限定它的活动范围。要造出这样一个可信的袋里,必须满足三点设计需求:
- 执行隔离:袋里写的代码不能威胁宿主主机。
- 能力隔离:袋里只能碰我们刻意交给它的数据和操作。
- 持久暂停:执行可以停下来等人工输入,然后恢复,中间不丢进度。
在 Interrupt 2026 上,我们发布了两个基于这些需求的产品。
- LangSmith Sandboxes:给袋里一个完整的远程容器——自由度跟本地编码袋里差不多,但隔离在另一台机器上。
- Deep Agents 的代码解释器:走相反路线——一个更小的运行时,袋里可以写程序、跑程序,但只能在我们提供的框架里活动。
第一种沙箱我们已经专门写过了。这篇重点聊聊第二种:为什么编排工作流不一定需要一台沙箱化的电脑?以及在不牺牲沙箱那种隔离感的前提下,怎么把攻击面做小?
执行隔离
每个跑过不可信代码的人都会得出同一个结论:必须在它和其余一切之间划一条硬边界。解释器也需要这条边界,但不能脱离进程去做——这就是我们用 WebAssembly 的原因。
WebAssembly
WebAssembly(WASM)是一种紧凑的二进制格式,运行在沙箱化的进程内虚拟机里,有自己的内存空间,只能通过宿主提供的能力与外界交互。它那套独立的线性内存就是边界的核心:WASM 里跑的代码没法解引用宿主进程的指针,所以读不到、也改不了没交给它的内存。WASM 运行时让硬性的内存和执行上限变得极易实施,而且它和框架跑在一起,我们不需要额外起一台机器就能做监控。
AWS、Shopify、Figma 都在自己的平台上用 WASM 跑不可信代码,WebContainers、wasmtime 这类工具也是这个隔离模型。
QuickJS
WASM 给了我们沙箱,但沙箱里还得有东西去跑代码。QuickJS 就干这个:一个轻量、快速、符合 ECMA 规范的 Ja vaScript 引擎,纯 C 实现。它小,所以边界内部的受信面就小;它编译到 WASM 很干净,所以引擎本身也站在边界后面,而不是边界旁边。Ja vaScript 也很适合这类活儿:表达力足够写编排逻辑,又不需要编译步骤——这正是袋里产出的短程序的特点。
能力隔离
执行边界阻止了袋里攻陷宿主,但没说袋里到底能做什么。一个袋里有用还是危险,全看你给了它什么能力。
想象一个袋里在策划婚礼。要让它有用,它得从各个地方读取敏感数据(合同、RSVP、家庭群聊),还得在外部世界采取行动(给供应商发邮件、批准一笔押金)。每项能力单独看都合理;把它们组合到一个自治循环里——一条恶意的 RSVP 就可能读到私密预算,然后给供应商发一封邮件“批准”了修改。
Meta 的“两条规则”精准描述了这种约束:在提示注入解决之前,一个袋里最多只能做以下两项中的两项:
- 访问敏感数据
- 暴露于不可信内容
- 改变状态或对外通信
这正好是代码解释器与传统沙箱最大的分歧点。沙箱一开始就长得像一台电脑(文件系统、依赖包、shell),所以安全工作是减法:上来先给一大盘能力,再一点点往回扣。代码解释器呢?一开始啥也没有。开箱它读不了文件、发不了网络请求、装不了依赖。它只有语言本身:变量、函数、对象、循环、条件分支……所有更强大的东西都得通过框架小心翼翼地桥接进来。
能力桥接最典型的例子就是在代码里调子袋里。袋里拿到的不是一个进程管理器或网络栈,而是一个窄接口的函数,由框架负责执行。因为我们拥有这座桥,所以也能设它的限:同时最多跑多少子袋里?一次调用能生成几个?
持久暂停
执行隔离和能力限制保证了正在运行的程序是安全的;最后一个需求是让它活下来。一个生产级的袋里必须在做危险事情前停下来等人工拍板,而那个批准可能几秒、几小时、甚至几天后才回来——那时候袋里早被踢出进程了。所以,怎么把一个跑了一半的程序暂停那么久,还能原地恢复?
因为 QuickJS 跑在 WASM 里面,我们可以直接暂停程序本身,而不是去重建它。把解释器的线性内存序列化到 LangGraph 状态里,恢复时框架还原快照,然后把结果喂给那个正在等待的调用。程序看到的只是一个异步调用花了点时间才返回而已。
试试看
后面这俩包现在已经公开了,但都还处于实验阶段:
quickjs-rs—— 运行时和 Python 绑定,用于通过 WASM 跑 QuickJS。langchain-quickjs—— 基于quickjs-rs的 Deep Agents 中间件。
我们正在跟少数几个密切合作伙伴一起把它们推向生产,并从部署中学到的经验来打磨运行时。想了解解释器到底能做什么,可以读读我们关于动态子袋里的那篇文章,或者直接动手试试!
uv add deepagents langchain-quickjs
from deepagents import create_deep_agent
from langchain_quickjs import CodeInterpreterMiddleware
agent = create_deep_agent(
model="baseten:zai-org/GLM-5.2",
middleware=[CodeInterpreterMiddleware()]
)