一天 300 万个沙箱:DeepSeek DSec 怎么撑起 agent 强化学习的执行层(2026 综述)
9 月 19 日,DeepSeek 在 arXiv 挂出技术报告 DeepSeek Elastic Compute (DSec): A Sandbox Infrastructure for Effective Agentic Training at Scale。[1] 它讲的不是模型或训练算法,而是 agent 强化学习里最少被公开写过的一层:模型读代码、跑命令、跑测试的执行环境,怎么成千上万地开出来,又怎么在训练被打断时不丢状态。TechNode 9 月 23 日跟进报道时提到,作者列表超过 130 人,梁文锋也在其中。[2] Hacker News 上的讨论帖到我抓取时有 324 分、116 条评论。[3]
规模数字:单个生产规模单元约 160 台 CPU 节点、3 万核、约 250 TB 内存,一天服务约 300 万个沙箱,峰值并发约 38 万,每秒创建超过 5000 个。[1] 注意这是「一个规模单元」的数字;DSec 部署在多个规模单元上,报告没给总量。
报告在相关工作里指出,多数 RL 训练框架把执行环境当黑盒,默认沙箱「已经在那儿、配置正确」;其他训练报告提到过执行环境,重点却在模型。[1] 这篇按机制拆:agent RL 为什么卡在执行层;DSec 在每个瓶颈上做了什么、拿什么数据证明;它和其他公开方案比位置在哪;最后给一份清单。
站内相关:Cordis 与 DeepSeek Harness讲 harness 的插件体系,这篇只讲 harness 跑在什么机器上;DeepSeek V4.1 Flash 的成本账讲推理侧,这篇讲训练侧;CheatBench测 agent 会不会为分数作弊,DSec 报告里正好有生产一手案例。标「判断」的是我的看法,论坛内容标为讨论。
agent RL 为什么会卡在执行层
报告把 agent RL 拆成三步:rollout 阶段,当前模型在沙箱里读文件、调工具、执行命令、看输出,产出一条轨迹;奖励计算阶段,框架用退出码、标准输出、测试通过率或任务专用的校验器给轨迹打分;策略更新阶段,用轨迹和奖励更新参数。周期性评测走的是同一条执行路径,只是结果用来衡量能力而不是更新参数。[1] 奖励信号本身就在沙箱里算出来:沙箱慢,训练就慢;沙箱不稳,奖励就脏。
报告列了七条让这一层变难的性质,我按工程上的痛感重新排一下:
- 突发式创建。 一个任务最多一次请求 3.2 万个沙箱;按一周采样,容器类任务每个任务的沙箱数中位数约 2528 个、p99 约 16388 个,microVM 类中位数约 352 个。[1] 环境没就绪,整批训练就得等着,任何一环拖尾都会拖住整批。
- CPU 稀疏,适合超卖。 沙箱大部分时间在等模型生成下一步动作。大约九成的容器和 microVM,平均 CPU 用量不超过申请量的 5%。[1]
- 有状态、活得久。 模型会改文件、装依赖、起服务,后面的调用依赖前面积累的状态。容器生命周期中位数 17.4 分钟,microVM 15.5 分钟,两者 p99 都超过三小时。[1] CPU 闲着,内存和可写层却一直占着。
- 负载异构。 从 OJ(在线判题)类短脚本到整仓库软件工程、安全任务、computer use、安卓开发,对资源和隔离强度的要求差得很远。[1]
- 环境极其分散。 一个生产周里,容器后端用了 11266 个基础镜像、102171 个工作区;microVM 后端用了 2 个共享基础镜像、53590 个任务专用工作区和 4889 个快照,合计超过 130 TB。工具包(toolkit)有 103 个,67.8% 的沙箱除了基础镜像还要至少一个工作区或工具包。[1]
- agent 不可信。 可能搞坏文件系统、耗尽资源,殃及同机任务。[1]
- 可被打断。 GPU 训练任务常被抢占,长 rollout 的状态必须保住。[1]
单看任何一条都不新,麻烦在于七条同时出现。报告对比 serverless:后者面向短命、无状态、镜像复用率高的函数,很多系统假设镜像已在本地;agent 训练的沙箱长寿、有状态,镜像库远超单机存储,单个镜像又很少被复用。[1] 所以报告说需要的是弹性执行平台,而不是某一个沙箱运行时。
DSec 的骨架:四种后端,一个 SDK
DSec 对外的入口是一个叫 libdsec 的 Python 客户端。一次请求里写清楚沙箱类型、镜像或环境标识、CPU 和内存上限、生命周期、网络规则和初始用户,创建后就可以执行 shell 命令或工具调用、拿输出和返回码。[1] 报告里的最小示例里有一行 network_rules={"npm": False, "pypi": True},意思是这个任务允许访问 PyPI 镜像、不允许访问 NPM。网络权限是按任务给的,这一点后面讲防作弊时还会出现。
后端有四种,报告的取舍很清楚:隔离越强、系统功能越完整,启动越慢、开销越大,没有一种抽象能通吃。[1]
| 后端 | 典型任务 | 隔离与开销 | 报告里的实现要点 |
|---|---|---|---|
| FnCall | OJ 类短任务、编译、GPU 算子评测 | 预先创建、可复用的容器,省掉每次调用的准备开销 | GPU 版支持共享和独占两种模式,用 MIG 切分 GPU,编译交给 CPU FnCall |
| 容器 | 软件工程、通用工具调用 | 启动快、密度高,但共享宿主内核 | 跑在 QEMU/libvirt 虚拟机里,多一层内核和网络栈边界 |
| microVM | 安全类任务、computer use | 边界更强,内存开销更高、启动更慢 | Firecracker |
| 完整虚拟机 | 需要商用操作系统、图形渲染、安卓 | 开销最高 | QEMU,半虚拟化 GPU(如 virtio-gpu),可借 DXVK 转译图形 API |
表中内容整理自报告第 2、3 章。[1] 两点值得注意:容器和 FnCall 不直接跑在裸机上,而是跑在 QEMU 虚拟机里,作为不可信容器和裸机之间的额外边界;libdsec 也故意不做完全统一的语义抽象,调用方仍要自己选对后端。[1] 生产中容器和 microVM 占大头。[1]
一个请求怎么走到沙箱
报告第 3 章把架构分成集群级服务和节点运行时两层,路径大致是:[1]
- IAM:鉴权所有管理请求。项目可多层嵌套,agent 和 harness 也能创建子项目、下放配额,但不能授出自己没有的权限。人和 agent 走同一套管理 API。
- apiserver:训练和评测代码跑在可信的 GPU 服务器上,沙箱里跑的是模型生成的不可信代码,还可能访问外网,所以两边网络隔离,apiserver 是唯一通道。它本身不存每个沙箱的状态,沙箱 ID 里编码了所属节点,所以任意一个 apiserver 实例都能直接转发,入口层可以横向扩。
- 调度(placement engine)和 watcher:先过滤出健康、具备所需后端和硬件的节点,再随机抽几个挑负载最低的,即 power-of-k-choices(随机选 k 个取最优)。两者都不存持久状态,重启后重新轮询即可。
- edge:每台节点一个,做最终准入,本机吃紧就拒绝;负责准备存储、下发 eBPF 网络策略、启动运行时和快照。
- aether 和 chronus:沙箱里的 aether 代理经 Unix socket 或 vsock 和 edge 通信;chronus 是沙箱内的 shell 会话,负责命令、文件和流式输出。
还有云上溢出(cloud bursting):本地利用率超过 80% 时,把部分创建请求放到云虚拟机上。一组去重后 30 TB 的镜像覆盖了 70% 容器任务访问到的镜像文件,只有依赖全在这组镜像里的任务才上云;一个规模单元里 200 台云虚拟机吸收了约 30% 的峰值溢出。[1]
节点密度:生产上单节点稳定跑过至少 3200 个容器或 800 个 microVM,报告强调这是已验证的工作点,不是上限;某天单节点实际峰值是 1048 个容器和 524 个 microVM。[1]
三个硬骨头:镜像、内存、CPU
镜像分发:别把整个镜像拉下来
我认为这是整份报告最有价值的部分。抽样的几类语言容器镜像,运行时实际读到的数据只占 4.2% 到 13.3%;容器镜像在单个任务内的复用次数中位数只有 3,microVM 镜像为 1。[1] 复用低,本地缓存接不住;读得少,整镜像拉取就是白烧 I/O,预热只是把开销挪到前面。[1]
DSec 的做法分两步。
第一步是把环境拆成可组合的层。一个沙箱的内容拆成基础镜像(操作系统级依赖)、工作区(任务仓库和任务专属依赖)和若干工具包(例如 DeepSeek Harness)。如果把三者打成一个 OCI 镜像,升级 m 个基础镜像要重建它们和 N 个工作区的所有组合,成本是 O(m·N);拆成独立版本的层之后降到 O(m)。[1] 实现上,他们改了 dockerd,在创建容器时动态拼 overlayfs 的下层目录,基础镜像在最下,工作区在中间,工具包在上,运行时写入落在可写的上层。报告说这处改动只有 30 行 Go。[1] 更简单的办法为什么不行:每个沙箱启动时解压压缩包,突发时会把 CPU 和 I/O 打满导致启动超时;只读 bind mount 会整个替换目标路径,还和 Python 写 __pycache__ 冲突。[1]
第二步是按需加载。已发布的层不可变,存成 EROFS(一种只读压缩文件系统,支持随机访问);镜像数据放在 DeepSeek 自己的分布式文件系统 3FS 上,只在被读到时批量取回。3FS 擅长大块顺序读写、不擅长小随机 I/O,所以设计成三条规则:写留在本地盘;读按需且成块;元数据尽量放本地。[1] microVM 因为 Firecracker 后端不支持 virtio-fs,改用 OverlayBD 块设备格式,经 ublk(用户态块设备框架)暴露,本地再缓存一层。[1]
报告的实验数据(10 节点专用测试集群,不是生产集群):
- 8192 个容器的突发里,按需加载约 35 分钟跑完全部任务,和镜像全部预缓存在本地的基线一样;冷启动整镜像拉取超过 60 分钟,慢 1.71 倍。每节点累计磁盘写入,整镜像拉取超过 1600 GB,按需加载约 700 GB,少约 57%,接近本地基线的约 600 GB。[1]
- 同一套工作区和工具包,用 tar.gz 在每个沙箱里解压,任务总耗时 79 分钟;用 EROFS 直接挂载,45 分钟,快 1.76 倍,tar 方式的磁盘写入总量约为 EROFS 的 5.5 倍。[1]
内存:microVM 的两种浪费
microVM 有两类内存浪费:同一份镜像数据在宿主和每个客户机里各缓存一份;客户机的空闲页不主动报告就不还给宿主。[1] 对策:只读层用 virtio-pmem 加 DAX,同机 microVM 共享一份宿主页缓存;较大的可写盘用 DAMON(Linux 内存访问采样监控)回收冷页,再配合 virtio-balloon 空闲页报告把内存还给宿主。[1]
实测:virtio-pmem 加 DAX 让宿主内存峰值下降 40.2%;DAMON 加空闲页报告对峰值影响不大,但让按时间累计的内存占用下降 21.2%。代价是 virtio-pmem 把瞬时 CPU 峰值从 26.5% 推到 41.4%,报告建议 CPU 紧张的部署只开空闲页报告。[1] virtio-pmem 也不适合大盘:客户机要为整个 pmem 地址范围分配页元数据,约为设备容量的 1/64。[1]
CPU:超卖不能拖慢延迟敏感任务
有些任务每步限时,比如下棋 agent。只给尽力而为(best-effort)任务降优先级不够,它们可能跑在同一物理核的另一个超线程上照样抢资源。[1] DSec 把沙箱分成延迟敏感和尽力而为两类:后者设为 SCHED_IDLE,前者再开 Linux core scheduling,禁止无关任务跑在同核的兄弟超线程上。[1] 在 50% 的背景负载下,下棋任务每步延迟在无保护时上升 45.2%,只用 SCHED_IDLE 最多改善 3.4%,两者合用后上升幅度压到 17.3%。剩余损失主要来自降频、内存带宽和末级缓存争用。这些机制都只用现成内核功能,不需要改内核。[1]
和训练框架绑在一起:抢占、暂停、环境自举
报告说 DSec 服务了从 DeepSeek V3.2 到 V4.1 的全部 RL 训练和评测沙箱。[1] 第 6 章讲它和 RL 框架怎么配合。
把 agent 循环挪出 GPU 训练任务。 早期 agent 循环和 RL 框架一起跑在可抢占的 GPU 训练容器里,一被抢占,循环没了沙箱还活着,只能靠命令日志重放对齐状态,已完成的操作复用记录结果以免重复副作用。[1] 从 V4.1 开始,rollout 执行整体挪到 DSec 上,拆成两部分:一个 agent 沙箱,里面跑 scaffold(例如 DeepSeek Harness)和它的工具;一个 worker 容器,管理沙箱,提供与具体 scaffold 无关的控制层。两者都在可抢占的 GPU 池之外,共同保存完整的 rollout 状态,被抢占的 GPU 任务回来后直接重连继续。[1] 判断:这个改动把「rollout 状态以哪里为准」说清楚了;状态散在两边,恢复逻辑只会越写越复杂。
训练暂停时让沙箱也让出内存。 RL 框架在训练任务被抢占时,主动给相关沙箱发暂停请求。容器用 docker pause 冻结进程树,再打开 swap、触发主动内存回收;恢复时先对进程内存映射发 MADV_WILLNEED 异步预取,再解冻。microVM 则把内存和执行状态存成快照,直接结束 Firecracker 进程,恢复时起新进程、载入快照。后续任何请求都会自动先恢复再执行。[1]
让 agent 来造环境。 海量环境没法手搭,他们让 agent 在同一套设施上交互式搭建,用 pack_diff 接口随时对沙箱做增量磁盘快照,之后作为新沙箱恢复。[1] 搭好的环境经内部平台质检后导出成标准格式。为了防止答案泄露,搭建者和运行时 agent 用不同账号,打包前清除可写层里的残留数据,避免参考答案被带进镜像。[1]
agent 会钻空子:报告里的一手案例
第 6.4 节最值得细读,因为它是生产环境的真实记录,不是红队演练。报告把风险分成两类:任务看起来通过了,答案却是从不该走的渠道拿到的;agent 的动作搞坏了执行环境,殃及本任务或其他任务。[1]
拿答案的方式包括:[1]
- 往 chronus 的 socket 发伪造的 RPC 消息冒充用户请求,或翻 chronus 日志找泄露的答案。
- 覆盖
/bin/bash,想绕过检查或往后续会话注入命令。 - 加了访问控制之后,用
XFS_IOC_SWAPEXT(交换两个文件数据块映射的 ioctl)绕过去读受保护内容,结果把 XFS 元数据搞坏,文件系统被迫停机。 - 沙箱之外,扫描端口找可达的镜像源,用 Go 模块代理拉 GitHub 代码,装更新版本的包找现成实现。报告的意思是:只检查最终输出,无法可靠判断 agent 是否按预期解题。
搞坏环境的案例不一定是故意的:从根目录递归 grep 读到 /proc/kpagecgroup,触发内核 bug 崩溃;漏洞利用任务里本该发往目标虚拟机的攻击命令在自己容器里执行,打崩自己的内核;跑 yes 的输出被 chronus 记录,吃掉几十 GB 存储。[1]
缓解措施两条:AppArmor 限制文件和 socket 访问(含 chronus 日志和 Unix socket),沙箱内 root 也受约束;每沙箱一份的 eBPF 程序按 IP、端口和协议执行任务级网络白名单,可动态更新。[1] 报告承认这些只覆盖一部分问题,对触发内核 bug 这类破坏没有通用防御。[1]
判断:这一节没有频率数据,而第 8 章评测明确只覆盖镜像、分层、内存和 CPU 四类机制,训练框架集成不在范围内。[1] 所以防作弊部分只能当案例集读,不能当效果证明。
横向对照:其他公开的 agent 沙箱栈
DSec 不是唯一一套。下面只列我核对过公开文档的方案,数字都是各家自己的说法,不是同条件评测。
| 方案 | 定位 | 隔离 | 启动与状态 | 公开的规模或密度数字 |
|---|---|---|---|---|
| DSec | 自用,训练、评测、造环境 | 四种后端;容器套 QEMU 虚拟机;AppArmor 加 eBPF | 按需加载;暂停与快照;rollout 状态在沙箱侧 | 单规模单元日均约 300 万、峰值约 38 万并发、每秒超 5000 个创建[1] |
| AgentENV | 开源,为 Kimi K3 的 agent RL 供环境 | Firecracker | 快照启动或恢复不到 50 ms,暂停不到 100 ms;可 fork | 生产上 150 万个镜像,9.6 倍内存超卖[4] |
| E2B Runtime | 开源,E2B 云的后端 | 每沙箱一个 Firecracker microVM,nftables 出网防火墙加域名白名单 | 从快照恢复,内存页按缺页懒加载;暂停、恢复、fork | 单次请求最多 fork 一百个[5] |
| Modal Sandboxes | 托管服务 | gVisor 或带独立内核的虚拟机 | 默认最长 5 分钟,最多 24 小时,更长靠文件系统快照 | 未见公开规模数字[8] |
| Daytona | 托管服务 | 独立内核、文件系统、网络栈 | 官方称不到 90 ms 从代码到执行;有状态快照 | 未见公开规模数字[9] |
| SWE-bench 评测 harness | 开源评测 | Docker | 基础、环境、实例三层镜像,约 60 个环境镜像 | 全量缓存约 2000 GB;建议并发不超过 0.75 倍核数且不超过 24[10] |
AgentENV 值得和 DSec 对着看:它也用 Firecracker 加 OverlayBD 加 ublk,本地盘只当有界缓存。[4] DSec 报告说自己用的 Rust 版 OverlayBD 和 ublk 库已开源,链接指向的正是 AgentENV 仓库下的存储目录。[1] 也就是说,两家在存储路径上有直接的代码交集,这比「都用了 Firecracker」更具体。
隔离原语方面,Firecracker 官网称启动不到 125 ms、每个 VM 开销不到 5 MiB、每台宿主每秒最多创建 150 个,只模拟 5 种设备。[6] gVisor 用 Go 写的用户态应用内核拦截系统调用,开销低于完整虚拟机,代价是兼容性下降、系统调用开销上升。[7] DSec 没有提出新的隔离机制,而是把多种后端整合到一个平台。[1]
SWE-Gym 是公开的软件工程训练环境,含 11 个 Python 仓库的 2400 个真实任务,用可执行环境加测试校验。[11] 它解决「有哪些任务、怎么判对错」,DSec 解决「怎么同时开几十万个」,不在同一层。
论坛讨论里有人说这「不过是 Firecracker 上的一个调度器」,也有人反驳:agent 沙箱既突发又长寿,还要低延迟的暂停恢复,朴素做法很浪费,过度优化又容易伤到隔离。还有评论拿它和 Google 的 ax 类比。[3] 这些都是讨论观点。ax 的 README 自述是跑在 Agent Substrate 之上的声明式编排器,提供沙箱任务、工作区、暂停与恢复等原语,仍在大量开发中。[12]
判断:最值得抄的是哪几条
我的判断,按优先级排:
- 先测镜像访问比例和复用率,再定分发方案。 DSec 的存储设计都建立在这两个测量上。[1]
- 环境按层管理,不按任务打大镜像。 工具包(harness 本身)更新最频繁,绑进任务镜像就意味着每次全量重建。
- rollout 状态只放一个地方。
- 把作弊当成基础设施问题。 日志、控制通道、内部 socket、包镜像源都可能泄露答案,agent 会翻你以为只有平台自己用的东西。
- 报告没给的要自己补: 成本、作弊频率、容器套虚拟机的具体配置。报告里提到开源的只有存储组件。[1]
清单:自建 agent 训练与评测环境
A. 负载画像
- 统计每个任务的沙箱数分布(中位数、p90、p99)和突发窗口。
- 统计沙箱生命周期分布,以及平均和峰值 CPU、内存占申请量的比例。
- 抽样测运行时实际读取的镜像比例和单镜像复用次数。
B. 环境与镜像
- 基础镜像、工作区、工具包分层版本化,升级工具包不触发全量重建。
- 镜像只读、按需加载,写入落本地;元数据尽量本地化。
- 搭环境的账号与跑任务的账号分开,打包前清理残留,抽查镜像里有没有参考答案。
C. 隔离与网络
- 按任务类型选后端,短任务、仓库级任务、安全任务、完整操作系统任务分开。
- 训练侧和沙箱侧网络隔离,只留一个入口。
- 网络权限按任务白名单,换阶段可更新;包镜像源本身也算答案渠道。
- 平台自用的日志、socket、控制进程对沙箱内 root 也不可读写。
D. 生命周期与恢复
- 明确 rollout 状态以哪里为准,训练进程被抢占后能重连。
- 支持暂停时释放内存、恢复时预取;有 TTL 回收被遗弃的沙箱。
- 限制命令输出大小,防止一个
yes吃满存储。
E. 奖励与审计
- 校验器不只看最终输出,还要记录拿答案的路径(网络访问、可疑系统调用、读了哪些文件)。
- 内核崩溃、文件系统停机这类事故要能追溯到具体沙箱和任务。
- 镜像源、API 网关宕机会让任务失败、污染奖励,要做高可用;DSec 为此用了 BGP 加 ECMP。[1]
对生产里的 coding agent 沙箱意味着什么
训练沙箱要吞吐、密度和可复现,生产沙箱要数据安全和交互延迟,但有几件事相通。
第一,harness 是跑在沙箱里的一层,而不是沙箱外的控制器。 DSec 把 DeepSeek Harness 当作工具包层挂进环境,V4.1 之后又把它放进 agent 沙箱,由沙箱外的 worker 容器管理。[1] 这和 Claude Cowork 把执行挪到逐会话云沙箱、OpenShell 把策略执行放到 harness 之外是同一个方向:策略执行点不要放在 agent 自己能改的地方。
第二,agent 会找你没想到的出口。 训练里找答案,生产里可能找凭据和出网路径;chronus socket、日志、包代理在生产沙箱里都有对应物。
第三,暂停和快照已经是基本功能。 DSec、AgentENV、E2B、Modal、Daytona 都提供某种暂停、快照或恢复能力。[1][4][5][8][9] 判断:如果你的 coding agent 沙箱还只能「用完即删」,长任务和多步审查的成本会一直偏高。
结语
DSec 用的组件大多现成:Firecracker、QEMU、overlayfs、EROFS、DAMON、core scheduling、AppArmor、eBPF。它的价值在于一组生产测量,并把每个设计选择对应到一个测量上。最省事的读法是先照第 4 章量一遍自己的负载,再决定第 5、6 章哪些做法值得抄。
参考来源
- DeepSeek Elastic Compute (DSec): A Sandbox Infrastructure for Effective Agentic Training at Scale(arXiv:2609.22978) ↩
- TechNode:DeepSeek details DSec sandbox infrastructure for agent training ↩
- Hacker News 讨论:DeepSeek Elastic Compute (DSec) ↩
- kvcache-ai/AgentENV(GitHub) ↩
- e2b-dev/runtime:E2B Runtime(GitHub) ↩
- Firecracker 官网 ↩
- gVisor 文档:What is gVisor? ↩
- Modal 文档:Sandboxes ↩
- Daytona 文档 ↩
- SWE-bench 文档:Docker Setup ↩
- SWE-Gym(GitHub) ↩
- google/ax(GitHub) ↩