2026年10月15日 1 分钟阅读

别让 Agent 沙箱一换就丢工作:Ramet 如何保存、分叉与选择性恢复工作区

tinyash 0 条评论

短生命周期沙箱适合运行 AI 编码 Agent:任务结束就销毁环境,能减少残留进程和资源占用。但如果 Agent 在里面改了代码、做了本地提交,下一次换沙箱时这些文件也可能一起消失。把整个目录打包虽能保住成果,却会把缓存、临时日志和可重建依赖一并带走;复制对话上下文更无法还原文件状态。

Ramet 是 Apache-2.0 许可的工作区持久化项目,定位在 Agent 框架与沙箱运行时之间。框架仍负责对话、调度和评估,沙箱负责运行代码,Ramet 管理可隔离的工作目录以及显式保存、恢复和回收。它不是 Agent 编排器,也不会自动判断哪些文件重要:由宿主程序决定何时保存,以及哪些路径应保留。

工作区与对话记忆是两回事

对话状态记录 Agent 说过什么;工作区状态则是文件、目录和本地 Git 状态。要让一个任务跨沙箱延续,通常需要同时持久化两种状态,并由自己的任务记录把它们关联起来。Ramet 管的是后者;项目文档明确指出,框架状态与快照 ID 的协调属于应用的恢复协议,不是 Ramet 提供的原子事务。

基本生命周期可以概括为:准备一个不可变基线、从池中取得隔离执行目录、让现有运行时使用该目录、停止所有写入者后再决定晋升保存或释放重置。并行尝试可以从同一基线派生各自的工作区;评估后只晋升选中的结果。

from ramet import Ramet

ramet = Ramet()  # 默认连接本机 http://127.0.0.1:7433
base = ramet.snapshot(source="/absolute/path/to/project")

with ramet.execution_pool(base, concurrency=4) as pool:
    with pool.acquire() as execution:
        # 将此路径交给自己的 Agent 沙箱或工具运行时
        print("workspace:", execution.path)
        (execution.path / "result.txt").write_text("candidate result\n")
        saved = execution.promote()

with ramet.execution_pool(saved, concurrency=1) as pool:
    with pool.acquire() as restored:
        print((restored.path / "result.txt").read_text())

这是 README 中的 Python SDK 快速示例所展示的同机生命周期,不代表任何外部沙箱都能直接挂载该路径。execution.path 位于 Ramet worker 的文件系统;远程 SDK URL 不会把文件传送到远端执行环境。若运行时无法挂载 worker 上的目录,就必须先解决文件系统连接问题。

不是所有文件都该同等保存

项目把路径策略分成几类:共享且不可变的输入可复用;需要延续的源代码或选定输出应持久化;依赖和构建产物可以记录重建要求;临时文件则可在晋升时排除。规则由宿主配置,Ramet 默认保留未分类路径,而不是猜测哪些内容可删。

一次 checkpoint 会保存当前支持的文件;promotion 则按策略筛选,并在发布快照前检查不可变输入等约束。promotion 前可以调用 execution.preview_promotion() 查看每条路径的处理决定,但预览只是建议,真正保存时会重新扫描。若策略把依赖标成可重建,应用仍要提供经过审核的处理函数和就绪检查;SDK 不会把配置中的命令字符串直接当作 shell 命令执行。

preview = execution.preview_promotion()
if not preview["valid"]:
    raise RuntimeError(preview["violations"])

saved = execution.promote()
print(saved.id)

注意调用顺序:在快照、promotion、reset 或 release 前,先停止沙箱及其后台子进程的写入,并完成挂载卸载。Ramet 文档将这项责任交给运行时适配层;租约续期、租约丢失时停止工作负载、崩溃后的孤儿进程清理,也不是简单传入一个路径就自动具备的能力。

适合哪些架构,哪些还要自己接

Ramet 内含同机 Docker 命令适配器,能覆盖较窄的本地集成场景;使用自建容器或 VM 时,需要自行实现目录挂载、进程停止、租约监管和异常清理。文档特别说明,LangChain/LangGraph、CrewAI、AutoGen 的接入路径是应用侧自定义适配,不是随附的专用插件。托管沙箱若不能访问 worker 文件系统,也没有通用适配器可以替代这一步。

项目 README 将当前版本标为 Phase 2 development alpha,适用于评估生命周期语义和受信任的运行时集成。其实现状态文档同时列出尚未完成的跨 worker 分布式路由等里程碑,因此不要把它当成已具备跨主机透明恢复、进程内存快照或外部副作用回滚的生产级能力。项目列出的 Linux/macOS 支持、Go/Python 要求与后端存储选择,应以当前文档为准;部署前还应验证自己的运行时和故障清理流程。

从单次任务开始试

先在可控的同机环境里,将项目目录做成基线快照;每次尝试从同一基线取得独立执行目录。评估器只需保存胜出结果的快照 ID,并把它与任务/会话 ID 一起写入应用自己的状态库。恢复时重新取得工作区,再让 Agent 框架恢复它自己的对话状态。

不要一开始就把所有目录都设为可丢弃,也不要把模型生成的重建命令未经审查地自动执行。先明确源代码、锁文件、构建产物、密钥和临时目录的策略,再用故障注入检查「进程仍在写入」「租约过期」「promotion 失败」时是否会误回收工作区。尤其要避免把凭据或 worker 私有目录挂进 Agent 可见的沙箱。

Ramet 解决的是 Agent 工作区在沙箱生命周期之外如何保存与隔离,不会替代工作流编排、代码审查、测试评估或会话记忆。若你的瓶颈是并行尝试相互污染、沙箱销毁导致本地改动丢失,而且愿意在可信宿主侧实现运行时适配,它提供了一套可检查的快照与工作区生命周期抽象;若期待的是无需适配的远端沙箱迁移,则还不够。

相关链接

发表评论

你的邮箱地址不会被公开,带 * 的为必填项。