今年出现的多数代理托管产品,解决的都是同一个首要问题:没人愿意让模型在自己的笔记本上跑 rm -rf,所以模型被放进别处的容器里。这部分已经成了大路货。没有成为大路货的、也是我想认真检查的部分,是当一个长时间运行的代理工作到一半、你不再盯着它时,它到底会怎样。
DigitalOcean 的 Managed Agents 最近进入公开预览,文档里的一个说法比它乍看之下更强。它说,暂停一个会话会保留进程、内存和工作区文件系统,恢复时把它们带回来。一个被停止的容器会丢掉所有没有写入卷的东西,所以如果那句话字面为真,它就是另一种东西,而我没有找到任何人去实测过。于是我花了一个上午和大约七美分去弄清楚。
这个测试最显而易见的版本毫无价值。如果你写一个文件、暂停、恢复、再把文件读回来,你只证明了磁盘还在,而这一点从来不是疑问所在。关于内存的说法,需要找一个只活在内存里、永远不会从任何地方被读回来的东西。
所以我写了一个最笨的进程。一个 bash 循环,用 shell 变量存一个计数器,每秒加一,把当前数值和时间戳追加进日志。这个日志从进程的角度看是只写的。没有任何东西会把它读回来,所以如果会话被销毁后重建、只是把文件系统恢复回来,计数器会从 1 重新开始,旧日志后面只会接上一段新的序列。
#!/bin/bashi=0while true; do i=$((i+1)) echo "$i $(date -u +%H:%M:%S)" >> /tmp/tick.log sleep 1done启动它需要一点小心,因为进入沙箱的执行通道关闭时会杀掉它的子进程。活下来的是 setsid nohup /tmp/tick.sh /dev/null 2>&1 & disown。
然后我让它跑了大约一分钟,暂停会话,去泡了杯咖啡,再恢复。
日志里相邻的两行,就是全部结果:
47 08:05:4248 08:10:10四十七,然后四十八,在同一个进程上,PID 590,握着它暂停前持有的同一个 shell 变量,而唯一能说明发生过什么的证据,是那四分二十八秒的空洞——本该有一秒一次的跳动。
暂停调用本身 0.86 秒返回,恢复用了 1.16 秒。这两个数字都没起多大作用,因为有意思的量是中间那四分半钟,那段时间里这个会话没有消耗任何东西。
我把同样的检查对着代理自己的上下文做了一遍,而不是对着一个 shell 变量。暂停之前,我让代理生成一个随机工单标识 HARBOUR-7742,并写进一个文件。恢复之后我问它工单叫什么,它从对话历史里用八个输出 token 答了出来,没有碰文件系统。两种状态都回来了,操作系统层面的和代理层面的。
有必要确认这个进程到底跑在什么上面,因为“沙箱”这个词从 chroot 到虚拟机什么都可能指。
Hypervisor detected: KVMCPU: 2 vCPU Memory: 3939 MB Disk: /dev/vda Kernel: 6.1.176这是一台带自己内核、自己块设备、底层有硬件虚拟化的 microVM,不是共享主机上的命名空间。从 API 调用到状态变成 READY,会话创建花了 15.97 秒,比容器慢,大致是一台 Firecracker 级别虚拟机的成本。规格从 mars-1vcpu-1gb 一直到 mars-16vcpu-32gb。
里面的代理由 DigitalOcean 自己的推理端点驱动,而不是第三方密钥。一次走 DeepSeek v4 Pro 的提示 7.3 秒返回,输入 15,793 个 token,输出 91 个,按要求写好了文件。推理和沙箱的账单进同一个账户,这比暂停功能小得多,但也不是没有价值。
有一个 fork 命令,我原本以为它做的是 checkpoint-and-restore 类产品常做的事:给磁盘拍个快照,再给你一个文件相同的沙箱。
结果不是。我把运行中的父沙箱 fork 了两次,两次一共花了 30.98 秒,然后去三个沙箱里检查那个计数器进程。
每一个里面都有同一个进程,同一个 PID,都在计数,而且都是从 fork 发生那一刻的数值继续往下走。一个正在运行的程序的三份拷贝,从共同的祖先开始分岔。如果你曾经想把一个代理跑到某个决策点,然后从那个状态出发去探索四条不同的路径,又不想把走到这里的工作重放一遍,这个原语就是干这个的。
单独做 checkpoint 花了 25.25 秒,报告的大小约 111 GB,那是稀疏分配的数字,不是实际存储量。
把所有操作的墙钟成本放在一起看,它们之间的差距会决定你怎么用它:
创建会话是最贵的一步,15.97 秒。暂停和恢复快到几乎不需要为它们做设计——这恰恰是暂停值得被主动使用的理由。
新沙箱的出网是开放的,我确认了这一点:在一个不做任何配置的沙箱里同时访问到了 example.com 和 api.github.com。往 manifest 里加一个主机,行为就完全翻转:
egress: - api.github.com之后,api.github.com 返回 200,其他一切都不返回任何东西,这是正确的设计,因为指定一个主机就是明确表示你想要默认拒绝的姿态。但一个未配置的会话有一个 g
热门跟贴