1. 从一次训练中断说起为什么沙箱调度值得单独拎出来讲做过 Agent 训练的人大概都经历过这种场景凌晨两点训练任务跑到第 3700 步突然某个容器里的工具调用卡死整个 rollout 批次全部挂起日志里只留下一句agent execution terminated due to error。你盯着屏幕心里清楚这一晚上又白干了。更让人头疼的是重启之后发现镜像拉取要重新走一遍环境状态全丢之前积累的中间结果一个不剩。这就是DeepSeek DSec想要解决的核心问题。DSec 是 DeepSeek 在大规模 Agent 训练实践中沉淀出来的一套沙箱基础设施它管三件事沙箱怎么调度、镜像怎么加载、状态怎么恢复。听起来像是三个独立的工程问题但真正跑过万级并发 Agent rollout 的人会明白这三件事是咬合在一起的——调度策略决定了镜像分发的拓扑镜像加载速度决定了沙箱的冷启动延迟而状态恢复机制则直接决定了训练任务能不能在故障后接着跑而不是从头再来。这篇文章适合两类人看。一类是正在做 Agent 训练或 Agent 开发的工程师你可能已经在用 DeepSeek 的 API 做 tool calls或者自己在搭 Agent 框架想搞清楚大规模 rollout 时沙箱层到底该怎么设计。另一类是负责 AI 基础设施的运维和平台同学你需要理解 Agent 训练负载和传统推理负载在资源模型上的本质差异。不管你是哪种我都会尽量把设计取舍和实操细节讲透让你看完能直接对照自己的场景做决策。需要提前说明的是DSec 目前并没有完全开源网上能查到的公开资料也比较有限。下面涉及具体实现的部分我会基于大规模 Agent 训练场景下的常见工程实践做合理推演并明确标注哪些是推测、哪些是行业通用做法。核心目的是帮你建立一套可复用的分析框架而不是照搬某个具体系统的配置。2. 沙箱调度不是简单的容器编排问题2.1 Agent 训练负载和普通推理负载的本质差异很多人第一反应会觉得沙箱调度不就是 K8s 调度 Pod 那套东西吗把容器跑起来就行了。但 Agent 训练的负载特征和普通推理服务完全不同直接套用会踩大坑。普通推理服务的请求是短平快的一个请求进来模型前向计算几百毫秒返回结果结束。资源占用曲线是平稳的扩缩容逻辑也简单——看 QPS 就行。但 Agent 训练里的 rollout 完全不是这么回事。一个 Agent 任务可能包含几十轮工具调用每一轮都要在沙箱里执行代码、读写文件、访问网络。这意味着单个沙箱的生命周期可能从几十秒到几十分钟不等而且资源占用是脉冲式的模型推理时吃 GPU工具执行时吃 CPU 和内存等待外部 API 返回时几乎不占资源但沙箱不能销毁。更麻烦的是批量同步的问题。Agent 训练通常是 batch rollout一个 batch 里几百上千个 Agent 同时启动。如果调度器按传统方式逐个分配资源光是调度延迟就能把训练吞吐拖垮。DSec 这类系统必须做到批量预分配 快速绑定在 rollout 开始前就把沙箱资源池准备好而不是等任务来了再临时调度。2.2 调度策略的三种典型模式与取舍在大规模 Agent 训练场景下沙箱调度大致有三种模式各有各的适用场景。第一种是集中式调度用一个中心调度器维护全局资源视图所有沙箱请求都经过它分配。优点是全局最优、资源利用率高缺点是调度器容易成为瓶颈而且单点故障风险大。这种模式适合集群规模在几百节点以内、对资源利用率极度敏感的场景。第二种是分层调度把集群按机架或可用区划分成多个域每个域有自己的子调度器中心调度器只做域间协调。这是 DSec 这类系统比较可能采用的方案因为它能在调度延迟和全局效率之间取得平衡。Agent 训练的 batch 通常有局部性特征——同一个 batch 的 Agent 往往访问相似的工具集和数据集把它们调度到相近的物理节点上能显著减少网络开销。第三种是去中心化调度每个节点自己维护资源状态通过一致性协议做分布式决策。这种模式扩展性最好但实现复杂度极高而且容易出现资源碎片。除非集群规模到了万节点级别否则不太推荐。实际选型时我建议重点看两个指标调度延迟的 P99和资源碎片率。Agent 训练对调度延迟极其敏感因为 batch 内所有 Agent 必须同步开始最慢的那个决定了整个 batch 的启动时间。如果 P99 调度延迟超过 500ms训练吞吐就会明显下降。2.3 资源池化与预热把冷启动藏起来调度层面还有一个关键设计是资源池化。DSec 大概率会维护一个热资源池里面是已经创建好但还没绑定任务的沙箱实例。当 rollout 请求到来时直接从池子里取省去容器创建和运行时初始化的时间。这个池子的大小需要动态调整。池子太小请求来了没资源可用退化成冷启动池子太大闲置资源浪费成本。常见的做法是基于历史负载做预测性扩缩容同时保留一个最小安全水位。比如根据过去 5 分钟的 rollout 请求速率预测未来 1 分钟需要多少沙箱提前把池子扩到对应规模。预热还有一层含义是运行时预热。Agent 沙箱里通常要跑 Python 解释器、加载常用库、初始化工具链。这些操作如果每次冷启动都做一遍单个沙箱的启动时间可能从 200ms 涨到 3 秒以上。DSec 应该会采用类似 checkpoint 的技术把初始化好的运行时状态保存下来新沙箱直接从 checkpoint 恢复跳过重复初始化。注意资源池化会带来状态污染的风险。如果池子里的沙箱被前一个任务用过但没清理干净新任务可能读到脏数据。必须确保池中沙箱在归还时经过完整的清理流程包括文件系统重置、环境变量清除、网络连接关闭。3. 镜像加载被低估的启动瓶颈3.1 镜像分层与按需加载Agent 沙箱的镜像往往很大。一个完整的 Agent 运行环境可能包含 Python 生态、Node.js 运行时、各种命令行工具、预训练模型权重镜像体积轻松超过 10GB。如果每次启动沙箱都要完整拉取镜像网络带宽根本扛不住。解决思路是镜像分层 按需加载。把镜像拆成基础层、运行时层、工具层、数据层启动时只加载基础层和运行时层工具层和数据层在真正用到时再懒加载。这需要文件系统支持比如用 FUSE 做用户态文件系统拦截文件访问请求触发对应层的下载。DSec 在镜像加载上可能还做了层去重和共享。同一个 batch 里的 Agent 往往用同一个基础镜像这些层只需要在节点上存一份多个沙箱共享挂载。这样节点上的实际存储占用远小于镜像体积乘以沙箱数量。3.2 P2P 分发把镜像拉取变成局域网传输集中式镜像仓库在大规模场景下必然是瓶颈。一千个沙箱同时启动如果都从中心仓库拉镜像仓库的出口带宽瞬间打满。DSec 这类系统通常会引入 P2P 分发机制让节点之间互相传输镜像层。具体做法是第一个拉取某层的节点从中心仓库下载后续节点优先从同机架或同可用区的邻居节点获取。这样中心仓库的压力被分散到整个集群而且局域网传输速度远高于跨区域网络。BitTorrent 协议或者类似的自研协议都可以用关键是要做好分片校验和断点续传避免传输过程中出错导致镜像损坏。实测数据上P2P 分发能把大规模并发拉取的时间从分钟级降到秒级。假设 1000 个节点各拉 10GB 镜像中心仓库出口带宽 10Gbps串行拉取需要 8000 秒用 P2P 后中心仓库只需要上传一份其余在节点间并行传输总时间取决于最慢节点的局域网带宽通常能控制在 100 秒以内。3.3 镜像缓存淘汰策略节点上的镜像缓存不能无限增长必须有淘汰策略。常见的做法是 LRU最近最少使用但 Agent 训练场景下 LRU 不一定最优因为镜像的使用有明显的批次聚集性——某个 batch 用的镜像可能在下个 batch 就完全不用了。更合适的策略是基于 batch 生命周期的淘汰。当一个 batch 的所有沙箱都结束后标记该 batch 用到的镜像层为可淘汰但保留一段时间比如 10 分钟以防有重试任务。超过保留期后按 LRU 顺序清理。这样既能及时释放空间又能避免频繁的镜像重新拉取。实操心得镜像缓存淘汰的阈值设置很关键。如果节点磁盘使用率超过 85% 才开始淘汰可能来不及清理就写满了。建议在 70% 时启动淘汰留出足够的缓冲空间。同时监控缓存命中率如果命中率低于 60%说明缓存策略需要调整。4. 状态恢复让训练任务能接着跑4.1 状态恢复的三个层次Agent 训练中的状态恢复不是单一维度的它至少包含三个层次。第一层是沙箱进程状态。沙箱里的进程可能正在执行代码、等待 IO、持有锁。如果沙箱崩溃这些状态全部丢失。要恢复的话需要定期对进程做 checkpoint把内存、文件描述符、寄存器状态保存下来。这层恢复的粒度最细但实现难度也最大通常只有对状态一致性要求极高的场景才做。第二层是文件系统状态。Agent 在沙箱里读写的文件、生成的中间产物、下载的数据这些都需要持久化。DSec 可能会用 overlayfs 或者类似的联合文件系统把可写层单独存储崩溃后重新挂载可写层就能恢复文件状态。第三层是任务级状态。Agent 执行到第几轮工具调用、已经完成了哪些子目标、下一步该做什么这些是任务逻辑层面的状态。这层状态通常由训练框架自己管理沙箱层只需要提供持久化存储接口。实际系统里三层恢复的优先级不同。任务级状态最重要因为它决定了训练能不能继续文件系统状态次之影响的是恢复后的执行效率进程状态最不重要大多数情况下重新执行比恢复更快。4.2 Checkpoint 频率与开销的平衡做状态恢复就绕不开 checkpoint 频率的问题。checkpoint 太频繁开销大影响训练速度checkpoint 太稀疏崩溃后丢失的工作量大恢复成本高。一个实用的经验公式是checkpoint 间隔 可接受的最大重算时间 / 单步执行时间。比如你能接受崩溃后最多重算 5 分钟的工作单步 Agent 执行平均耗时 10 秒那 checkpoint 间隔就是 30 步。当然这只是一个粗略估算实际还要考虑 checkpoint 本身的耗时。对于 Agent 训练我建议采用异步 checkpoint不阻塞主执行流程在后台把状态写到持久化存储。这样 checkpoint 的开销被隐藏在执行时间里对训练吞吐的影响最小。代价是崩溃时可能丢失最近一次未完成的 checkpoint但通常可以接受。4.3 故障检测与自动恢复流程状态恢复的前提是能快速检测到故障。DSec 应该会维护沙箱的心跳机制每个沙箱定期向调度器汇报状态。如果连续几个心跳周期没收到汇报就判定为故障触发恢复流程。恢复流程大致是这样的调度器标记故障沙箱从持久化存储读取最近一次 checkpoint在新的节点上重建沙箱恢复文件系统和任务状态然后通知训练框架从 checkpoint 点继续执行。整个过程对训练框架应该是透明的框架只需要知道某个 Agent 重启了不需要关心底层怎么恢复的。这里有个容易踩的坑恢复后的沙箱可能和原沙箱不在同一节点网络拓扑变了之前缓存的连接可能失效。所以恢复流程里必须包含网络重连和缓存失效的逻辑否则 Agent 恢复后会因为连接问题再次失败。注意故障恢复要考虑雪崩效应。如果大量沙箱同时故障比如某个机架断电恢复流程本身可能压垮调度器和存储系统。需要做恢复限流比如每秒最多恢复 N 个沙箱避免恢复风暴。5. 三者的协同DSec 的整体架构推演5.1 调度、镜像、恢复如何互相影响单独看调度、镜像、恢复每个问题都有成熟解法。但 DSec 的价值在于把三者协同起来让整体效率大于部分之和。举个例子调度器决定把某个 batch 的沙箱集中调度到同一组节点上这不仅减少了网络开销还让镜像分发可以走局域网 P2P同时让状态恢复时的 checkpoint 存储可以就近访问。反过来如果镜像加载太慢调度器就需要调整策略把沙箱分散到已有镜像缓存的节点上哪怕牺牲一些网络局部性。再比如状态恢复如果 checkpoint 存储和沙箱在同一节点恢复速度最快但节点故障时 checkpoint 也丢了。所以 checkpoint 必须异地存储但异地存储又带来恢复时的网络延迟。DSec 需要在恢复速度和数据可靠性之间找平衡点常见的做法是本地存一份热 checkpoint 用于快速恢复同时异步同步到远程存储做冷备份。5.2 一个可能的请求生命周期让我用一个具体的请求生命周期来串起这三个环节。假设训练框架发起一个 batch rollout包含 500 个 Agent 任务。调度器收到请求后先查资源池发现池子里有 300 个热沙箱还差 200 个。调度器触发扩容从镜像缓存命中的节点上创建新沙箱。镜像加载模块检查本地缓存发现基础层和运行时层已缓存工具层需要拉取于是启动 P2P 下载。同时调度器为这 500 个沙箱分配任务 ID初始化状态存储路径。沙箱启动后Agent 开始执行。每执行 N 步状态恢复模块触发一次异步 checkpoint把任务状态写到本地 SSD 和远程对象存储。执行过程中某个沙箱因为工具调用超时崩溃心跳检测发现后调度器从远程存储读取最近 checkpoint在另一个节点重建沙箱恢复任务状态通知训练框架继续。整个 batch 结束后沙箱归还到资源池镜像缓存标记为可淘汰状态存储清理临时数据。调度器更新资源视图准备下一个 batch。这个流程里三个模块的协同点非常多调度决策影响镜像加载路径镜像加载速度影响沙箱启动时间状态恢复策略影响调度器的故障处理逻辑。DSec 的设计难点就在于把这些协同点处理好而不是单独优化某个模块。5.3 和主流 Agent 框架的对接方式DSec 作为基础设施需要和上层的 Agent 框架对接。目前主流的 Agent 框架不管是开源的还是自研的通常都提供工具调用接口和状态管理接口。DSec 需要做的是实现这些接口的沙箱化版本。比如工具调用框架说执行这段代码DSec 就在沙箱里执行返回结果。框架说保存这个状态DSec 就写到持久化存储。框架说恢复到这个 checkpointDSec 就重建沙箱并加载状态。对接的关键是接口语义要清晰特别是错误处理和超时语义否则框架层很难做正确的重试和恢复决策。如果你正在自研 Agent 框架我建议把沙箱层抽象成独立的接口不要和训练逻辑耦合。这样将来换沙箱实现比如从自研换成 DSec时只需要改接口实现不用动训练代码。6. 实操中容易踩的坑与排查思路6.1 沙箱启动慢的排查路径沙箱启动慢是最常见的问题。排查时按这个顺序走先看镜像加载耗时如果超过 1 秒说明镜像缓存没命中或者 P2P 传输有问题再看容器创建耗时如果超过 500ms可能是节点资源不足或者运行时初始化太慢最后看网络配置耗时如果超过 200ms检查 CNI 插件和 DNS 解析。我遇到过一种情况是镜像层数太多每层都要单独挂载导致启动时文件系统操作成为瓶颈。解决办法是合并镜像层把不常变动的层压缩成一层。另一个坑是镜像里的启动脚本做了太多事情比如检查更新、下载依赖这些都应该在镜像构建时完成而不是启动时做。6.2 状态恢复失败的常见原因状态恢复失败通常有几个原因。一是 checkpoint 不完整写到一半崩溃了恢复时读到损坏数据。解决办法是 checkpoint 写入用原子操作先写临时文件再重命名。二是版本不匹配checkpoint 是用旧版本代码存的恢复时用新版本代码读格式对不上。需要在 checkpoint 里记录版本号不兼容时拒绝恢复。三是依赖缺失恢复后的沙箱里缺少某些文件或环境变量导致任务执行失败。这要求 checkpoint 不仅保存任务状态还要保存环境快照。6.3 资源泄漏的检测与清理Agent 训练跑久了容易出现资源泄漏沙箱没正常销毁、文件句柄没关闭、网络连接没释放。这些泄漏积累起来会拖垮整个集群。检测资源泄漏的办法是定期做资源审计对比调度器记录的沙箱数量和实际运行的容器数量对比分配的存储空间和实际占用。如果差异超过阈值就触发清理流程。清理时要小心不能误杀正在运行的沙箱最好先标记再观察确认是泄漏后再回收。实操心得资源泄漏往往在训练任务异常退出时发生。建议在训练框架里加一个 finally 块不管任务成功还是失败都调用沙箱清理接口。同时调度器侧也要有兜底清理防止框架层没清理干净。问题现象可能原因排查方法解决措施沙箱启动超过 5 秒镜像未缓存检查节点镜像缓存命中率预热镜像或调整调度策略批量 rollout 启动时间波动大调度延迟 P99 过高查看调度器队列深度扩大资源池或优化调度算法恢复后 Agent 行为异常checkpoint 不完整校验 checkpoint 文件完整性改用原子写入并增加校验节点磁盘写满镜像缓存未淘汰检查缓存淘汰策略降低淘汰阈值并增加监控大量沙箱同时故障节点或机架故障查看故障沙箱的物理分布增加故障域隔离和恢复限流7. 从 DSec 看 Agent 训练基础设施的演进方向Agent 训练对基础设施的要求和传统深度学习训练很不一样。传统训练是计算密集型瓶颈在 GPUAgent 训练是交互密集型瓶颈在沙箱的创建、销毁和状态管理。这意味着基础设施的设计重心要从把 GPU 喂饱转向让沙箱流转得更快。DSec 体现出来的思路是把沙箱当成一等公民来对待而不是当成容器的简单封装。调度器要理解 Agent 任务的语义镜像系统要针对 Agent 环境的特征做优化状态恢复要覆盖 Agent 执行的完整生命周期。这种专门化的设计比通用容器平台直接套用要高效得多。另一个趋势是训练和推理的基础设施融合。Agent 训练里的 rollout 本质上就是推理只不过结果要用于训练。如果能把推理服务的弹性扩缩容、请求路由、缓存这些能力复用到训练场景能省下大量重复建设。DSec 这类系统未来可能会和推理基础设施做更深度的整合。对于正在做 Agent 开发的团队我的建议是如果你的规模还在几十个并发以内用现成的容器平台就够了没必要自研沙箱调度。但当并发上到几百甚至几千沙箱层的效率就会成为训练吞吐的决定因素这时候值得投入精力做专门优化。优化的优先级是先做镜像缓存和 P2P 分发再做资源池化和预热最后做状态恢复。这个顺序是按投入产出比排的前两项能带来最直接的收益。最后分享一个我在实际项目中验证过的技巧把沙箱启动时间纳入训练框架的调度决策。训练框架在分配任务时优先把任务分配给启动快的沙箱而不是简单地轮询。这样能让整个 batch 的完成时间更接近最快沙箱的完成时间而不是被最慢的拖累。实现上只需要在沙箱注册时上报启动耗时调度器维护一个按启动速度排序的沙箱列表即可。这个改动很小但在大规模场景下能带来可观的吞吐提升。