Cube Sandbox v0.3.0:AI Agent 的时间机器和克隆间
在现代 AI Agent 技术栈中,沙箱扮演着"安全运行时"的角色——它是实际执行模型产生的代码和工具调用的地方。Cube Sandbox 刚刚发布了 v0.3.0。除了来自 22 位贡献者的 82 次提交之外,这次发布是一次针对 AI Agent 大规模运行时痛点的基础架构升级:高并发下的运行时复用和故障隔离、长任务链以及强化学习工作负载。
1. 基础:更完整的 AI Infra 故事
在深入快照功能之前,先看看基础层面的变化。v0.3.0 在三个维度上进行了迭代:
引擎内核(cubecow + 增量内存):一个全新的 Copy-on-Write 快照引擎——
cubecow,专为沙箱卷设计;在内存方面,基于 Linux 内核的soft-dirty位图实现了增量内存快照。在连续快照场景中,系统不再需要刷新完整内存,只持久化自上次快照以来产生的脏页。因此,快照创建和恢复都降到了每个沙箱毫秒级。开发者生态(Go SDK + WebUI):继 Python SDK 之后,Go 开发者现在拥有了原生 SDK,完全覆盖沙箱和模板生命周期。对于运维和管理工作流,内置的 Web 控制台现已上线,一目了然地展示每个节点的资源负载和每个沙箱的运行状态。
部署与运维:一键安装程序已迁移到 systemd + Docker Compose,内置预检和诊断脚本(cgroup v2 等),显著改善了跨云提供商的开箱即用兼容性。
在这些基础更新中,最值得关注的是围绕沙箱核心状态的快照/回滚/克隆系统。
2. 快照/克隆/回滚:Agent 的时间机器
本次发布引入了三个 SDK 原语——snapshot、clone 和 rollback——它们共同构成了沙箱的完整状态管理方案。
2.1 每个原语的作用
snapshot——冻结当前状态
将运行中沙箱的内存、运行时状态和磁盘转储到持久存储,作为一个独立的快照文件。快照的生命周期与源沙箱解耦:快照在源沙箱销毁后仍然存在,快照 ID 本身可以作为模板批量启动新沙箱。
clone——将一个沙箱扇出为 N 个
单次调用从一个运行中的源沙箱派生出 N 个完全独立的副本。关键特性:
- 继承性:每个副本从与源相同的状态启动——内存、文件、连接。
- 隔离性:副本之间物理隔离。
- 连续性:源沙箱不受影响,继续运行。
接口提供 concurrency=C 参数和"任一失败则中止并清理"策略,大规模扇出不会留下孤儿沙箱。
rollback——一行代码回到某个时刻
沙箱可以原地恢复到先前快照的状态——内存和文件系统完全回滚。回滚后,sandbox_id 和沙箱对象保持不变;无需重新连接或重建。
2.2 为什么 Agent 真正需要这些
在传统 Web 服务中,容器基本上是无状态的:启动、服务、丢弃。AI Agent 不是这样工作的——它们是被"培养"出来的。由此产生两个反复出现的痛点:
第一:如何复制一个已经"训练好"的沙箱?
当你需要并行运行更多任务,或引入新团队成员时,从头重放设置脚本既慢又无法忠实地复现内存上下文、已加载的模型权重或热缓存。通过 snapshot + clone,"30 分钟 × N"变成"毫秒 × N",每个副本都是一个完全就绪的 Agent 环境。

第二:当环境被破坏时怎么办?
Agent 会犯错——错误的依赖、删除的文件、无限循环。传统的答案是"杀死容器,从镜像重建,重新运行 pip install"——浪费几分钟。rollback 将恢复从几分钟压缩到几百毫秒,且 sandbox_id 不变,所以 Agent 可以继续执行。

2.3 这些原语解锁的四个真实场景
1) Agentic RL 训练 / SWE-Bench 评估
痛点:需要从同一基线运行大量独立实验,每个实验必须可复现。
Cube 方案:
python# 准备基线环境 base = Sandbox.create(template=TEMPLATE_ID) base.run_code("# 安装依赖、下载数据集 ...") snap = base.create_snapshot() # 并行扇出 100 个独立实例 clones = Sandbox.create(template=snap.snapshot_id).clone(n=100, concurrency=10)价值:基线只构建一次;后续每次扩展都是毫秒级克隆。
2) 并行多策略探索
- 痛点:想要同时对同一问题尝试多种解决路径。
- Cube 方案:使用
clone(n=N)将当前状态分叉为 N 个隔离沙箱,独立运行每个策略,然后汇总。 - 价值:探索吞吐量线性扩展,各次运行之间实验条件严格一致。
3) Agent 试错循环
痛点:执行过程中某一步失败时,传统做法是杀死沙箱重新开始。
Cube 方案:
pythoncheckpoint = sb.create_snapshot() sb.run_code("# 尝试方案 A ...") if failed: sb.rollback(checkpoint.snapshot_id) # 回到 A 之前的状态 sb.run_code("# 用不同方案重试 ...")价值:无需重建环境——节省时间和资源,自然映射 Agent 的试错模式。
4) 长期环境复用
- 痛点:配置了一个复杂的开发环境(大量依赖),不想每次都重新设置。
- Cube 方案:快照一次;以后每个沙箱都从该快照创建。
- 价值:冷启动 + 环境初始化合并为一步。
3. 快照底层工作原理
在传统虚拟化中,快照是一项重量级运维操作。Cube Sandbox 的快照系统在存储层端到端使用 reflink,配合 Copy-on-Write(CoW)语义,实现高效的快照创建和克隆。

存储模型:沙箱运行时,其磁盘数据以 CoW 模式挂载,内存同样以 CoW 模式从快照文件
mmap。沙箱启动后,所有只读内存页直接映射到底层快照文件——多个沙箱实例共享一份物理数据副本,无重复。拍摄快照:为运行中的沙箱拍摄新快照时,系统只将自上次快照以来产生的脏页写入新的快照文件——无完整序列化、无完整写出。由于脏页通常比总内存小一个数量级,快照 I/O 成本大幅下降,端到端延迟降低。
从快照启动:从现有快照创建新沙箱时,
reflink让新实例直接引用快照的元数据块——真正的"逻辑复制",无完整数据复制。文件系统级 reflink 大约是 O(1) 的,这使得从快照冷启动沙箱极其快速。
在这个存储原语之上,SDK 将 clone 和 rollback 封装为简单的单行操作:

4. 实践:使用快照和回滚
场景 1:错误隔离和原地回滚
在沙箱生命周期的任意有意义时刻放置检查点。无论环境后来被破坏得多严重,一次 sb.rollback(checkpoint_id) 就能恢复到那个时刻——关键是 sandbox_id 和沙箱对象保持不变,可以继续使用:
from cubesandbox import Sandbox
from env import TEMPLATE_ID
# 步骤 1:在 v0 状态拍摄基础快照
with Sandbox.create(template=TEMPLATE_ID) as src:
src.run_code("open('/tmp/v.txt', 'w').write('v0')")
base = src.create_snapshot()
base_id = base.snapshot_id
print(f"base snapshot (v0): {base_id}")
# 步骤 2:从基础快照启动新沙箱
sb = Sandbox.create(template=base_id)
print(f"derived sandbox: {sb.sandbox_id}")
# 步骤 3:写入 v1 并放置检查点
sb.run_code("open('/tmp/v.txt', 'w').write('v1')")
checkpoint = sb.create_snapshot()
checkpoint_id = checkpoint.snapshot_id
print(f"checkpoint (v1): {checkpoint_id}")
# 步骤 4:写入 v2 并确认
sb.run_code("open('/tmp/v.txt', 'w').write('v2')")
before = sb.run_code("print(open('/tmp/v.txt').read())").logs.stdout
before = before[0].strip() if before else ""
print(f"before rollback: {before!r}")
assert before == "v2"
# 步骤 5:回滚到 v1 检查点
sb.rollback(checkpoint_id)
print(f"rolled back to checkpoint {checkpoint_id}")
# 步骤 6:验证状态恢复到 v1(sandbox_id 不变)
after = sb.run_code("print(open('/tmp/v.txt').read())").logs.stdout
after = after[0].strip() if after else ""
print(f"after rollback: {after!r}")
assert after == "v1", f"expected 'v1', got {after!r}"
print("OK: rollback restored state to checkpoint (v1)")
# 清理
sb.kill()
Sandbox.delete_snapshot(checkpoint_id)
Sandbox.delete_snapshot(base_id)
print("snapshots deleted")场景 2:通过高效克隆进行并行探索
在强化学习或多路径决策中,clone 可以从单个源沙箱一次派生多个环境——每个副本物理隔离但继承源的完整运行时状态。以下示例克隆 N 个副本并验证每个副本都继承了写入源的标记文件:
import os
from cubesandbox import Sandbox
from env import TEMPLATE_ID
N = int(os.environ.get("FORK_N", "10"))
CONCURRENCY = int(os.environ.get("FORK_CONCURRENCY", "5"))
src = Sandbox.create(template=TEMPLATE_ID)
src.run_code("open('/tmp/origin.txt', 'w').write('I am from sandbox a')")
print(f"src sandbox: {src.sandbox_id}")
# ★ 并发克隆——SDK 内部扇出 Sandbox.create
clones = src.clone(n=N, concurrency=CONCURRENCY)
print(f"cloned {len(clones)} sandboxes (concurrency={CONCURRENCY})")
# 验证每个克隆都继承了源的状态标记
expect = "I am from sandbox a"
ok = 0
for i, sb in enumerate(clones):
r = sb.run_code("print(open('/tmp/origin.txt').read())")
marker = r.logs.stdout[0].strip() if r.logs.stdout else ""
if marker == expect:
ok += 1
print(f" clone[{i:>2}] {sb.sandbox_id} marker={marker!r}")
print(f"\n{ok}/{N} clones inherited the origin marker")
assert ok == N, "some clones failed to inherit state"
# 清理
src.kill()
for sb in clones:
sb.kill()
print("all sandboxes killed")Cube Sandbox 在协议层与 E2B 深度兼容,但这两个原语在 E2B 的原生 API 中不存在。Cube 团队在应用层通过 cubesandbox SDK 桥接它们——这意味着开发者无需修改现有 E2B 兼容代码即可解锁这些高级状态管理原语。
5. 快照/克隆/回滚的 Web 控制台(预览),随版本开源
除了 SDK 层的 snapshot/rollback/clone API,本次发布还附带了一个基于 Cube Sandbox 的 OpenClaw Web 控制台开源预览。本次发布的所有新功能现在都可以通过点击操作完成:每个沙箱的实时快照时间线、一键回滚到任意检查点、按需扇出到多个 OpenClaw 副本,以及批量生命周期管理。
过去需要编写脚本调用 SDK 的操作——"时间机器"和"克隆间"——现在只需在浏览器中点击几下即可完成。

即将推出
在下一个版本中,我们将把"沙箱安全"再推进一层——从"隔离 Agent 在哪里运行"到"控制 Agent 能接触什么":
- 内置内容感知网络控制与审计:在沙箱网络边界实现内容感知的出站访问控制和完整审计跟踪,"Agent 调用了哪个外部 API、发送了什么数据"完全可追溯和可拦截。
- 凭证保险库:API Key、数据库密码和云凭证在沙箱安全侧集中管理;Agent 只能看到有范围限制的临时凭证,将密钥隔离在模型上下文和日志之外。
如果你在这个领域构建任何东西,请关注 Cube Sandbox——并考虑通过 Issue 或 PR 与我们一起构建。