大型语言模型的智能体训练,往往不是模型训练本身有多难,而是“一批智能体同时跑起来”这件事,能把一个普通开发机折腾到怀疑人生。我在把多个DeepSeek驱动的智能体放出去做环境交互、工具调用和多轮自我博弈时,第一波遇到的就是资源冲突、环境串扰、数据污染和不可复现。折腾了几个月之后,我逐渐把一套适合大规模智能体训练的基础设施固化下来,也就是这篇博文的主题:DSec,一个面向DeepSeek智能体训练的弹性计算沙箱基础设施。它能解决什么问题,适合谁,我会在正文里用实际经验和踩坑记录来讲明白。
1. 大规模智能体训练的痛点与DSec的设计思路
1.1 为什么普通开发机撑不住智能体训练
先说个直观感受。我刚开始做智能体训练的时候,是在一台本地工作站上跑的,配置不算低,双路GPU、128G内存,按理说够用了。但智能体训练和传统模型训练有一个本质区别:它不是一个批次数据喂进去算梯度就完事,而是无数个智能体并行地去执行任务、调用工具、和环境交互,并且每个智能体的执行路径都不可预知。
举个具体例子。我要训练一个能自己写代码、跑测试、改代码的编程智能体,一次实验要开20个并行样本,每个样本对应一个独立的文件系统目录、一个Python解释器、一组环境变量、一个可以执行的shell。20个环境同时跑,任何一个环境里出现一个死循环、一次写爆磁盘、一个端口冲突,就能把整轮训练搞挂。
更麻烦的是智能体训练里的“环境交互依赖”。智能体在训练中会按照环境反馈调整策略,如果环境本身不稳定,训练出来的策略也是歪的。比如一个智能体在环境A里学到了“等到超时就重试”,换到环境B发现超时时间不同,策略就不work了。所以训练基础设施的第一需求是:环境要稳定、一致、可复现。
还有一个很隐蔽的问题:数据污染。如果多个智能体共享同一个文件系统,一个智能体写坏了某个配置文件,另一个智能体读到的就是坏数据。智能体本身又是基于上下文学习的,一次污染的上下文,可能让整个训练批次都学到错误行为。这种污染很难从训练日志里定位,很多时候只能靠隔离来防。
1.2 DSec的核心设计目标
针对上述痛点,我给DSec定了四个设计目标,这四个目标也对应了智能体训练基础设施的四个核心能力:
- 强隔离:每个智能体训练任务跑在彼此隔离的沙箱里,文件系统、进程空间、网络栈互相不可见。隔离不是可选项,是基础要求。
- 弹性调度:训练过程中智能体的数量是动态变化的,某个任务崩了要能自动重启,某些任务吃不满资源要能收缩,资源池要像出租车调度一样按需分配。
- 环境快照与回滚:训练是一步步试出来的,改了环境配置后跑挂了,要能一键回到上一个可用状态。这个在调试训练策略的时候极其重要。
- 可观测性:任何一个智能体在任何一个沙箱里的行为都要能被记录、追踪、回放。智能体训练调bug,本质上是环境行为观测能力的比拼。
这四个目标看起来简单,但真正落地的时候会发现,它们之间有互相制约的地方。比如要强隔离,最简单是用虚拟机,但虚拟机启动慢、资源开销大,训练大量短期任务时不划算;要弹性,容器是最佳载体,但容器的隔离粒度又比虚拟机弱。DSec的选择是:以容器为隔离载体,用Linux命名空间和cgroup做资源强管控,用叠加文件系统做环境快照,用一套调度器统一管理。
提示:做这一类基础设施的时候,不要一开始就去追逐Kubernetes之类的大而全方案,那个是给在线服务准备的,训练场景下很多能力是用不上的,反而增加心智负担。先把手动流程跑通,再把重复步骤自动化,是更务实的路径。
1.3 这套设施的服务对象
DSec这类基础设施,主要服务三种人:
第一种是算法工程师,他们需要大规模并行跑智能体训练实验,验证不同训练策略、不同提示词模板、不同环境反馈设计的效果。对他们来说,DSec要解决的是“怎么一次跑100个环境且保证结果可靠”。
第二种是AI Infra工程师,他们关心的是资源利用率、任务吞吐量、调度延迟这些指标。DSec的弹性计算能力可以直接支撑他们做资源池管理、多租户配额控制。
第三种是研究型开发者,他们做的是一些探索性的智能体实验,比如多智能体社会模拟、智能体进化搜索,这些任务的特点是任务形态千奇百怪,环境配置五花八门。他们需要的是能快速搭建自定义沙箱的能力,而不是被基础设施限制住。
2. DSec弹性计算方案的整体架构拆解
2.1 控制面、数据面、调度面三分离
DSec的架构,我拆成三个部分来讲,这样各自职责清楚,出了问题也好排查:控制面负责接收训练任务、维护环境状态;数据面负责具体的沙箱实例和训练执行;调度面负责把任务分配到最合适的沙箱资源上。
控制面的核心是一个任务队列加状态数据库。训练任务提交进来后,会被解析成标准化的任务描述,包含镜像地址、资源配额、环境变量、启动命令、超时时间等字段。状态数据库记录每个任务的当前状态,从pending、scheduling、running到finished、failed,整个生命周期可追踪。
数据面是实际的沙箱实例。这里的关键决策是用容器做沙箱,而不是直接用裸进程。容器带来的好处是文件系统隔离、进程隔离、网络隔离一应俱全,而且创建销毁的代价很低,一个沙箱的冷启动可以控制在几百毫秒到一两秒的水平。DSec在数据面上做了一层封装,把容器和训练逻辑解耦:容器只负责提供隔离环境,训练逻辑通过挂载的数据卷和注入的启动脚本来实现。
调度面是我花时间最多的地方。智能体训练任务有个特点是执行时长高度不确定,有的任务几秒就结束了,有的任务可能跑几个小时。如果按照传统批处理调度器的思路,提前排队、按序执行,资源的浪费会非常严重。DSec的调度器用的是实时协商机制:任务提交时先预估资源,调度器根据当前资源池的实时状态决定是立刻启动、排队等待还是分配降级配置。
2.2 沙箱的形态选择:为什么是容器而非虚拟机
关于沙箱形态,我和不少人讨论过,很多人第一反应是虚拟机更安全。但训练场景和在线服务场景不一样,这里我详细对比一下,你就明白为什么容器是这张场景下的合理方案。
| 维度 | 容器沙箱 | 虚拟机沙箱 |
|---|---|---|
| 启动速度 | 亚秒级到秒级 | 十几秒到分钟级 |
| 资源开销 | 基本无额外开销 | 每台虚拟机都要固定消耗内存和CPU |
| 隔离强度 | 内核级隔离,同内核可逃逸但成本高 | 硬件级隔离,更安全 |
| 镜像管理 | 分层镜像,增量拉取 | 完整磁盘镜像,体积大 |
| 快照能力 | 叠加文件系统,秒级快照 | 快照依赖存储后端,开销大 |
智能体训练的任务特点是大量短小任务、频繁构建销毁环境、需要频繁快照回滚,这些需求全打在虚拟机的短板上。而容器方案在这些维度上都非常贴合。安全性方面,如果训练任务都是自己团队的代码,容器隔离已经足够;即使要运行不可信的外部代码,通过seccomp、AppArmor再加一层限制,也能把风险降到可控范围。
不过容器方案也有一个必须正视的弱点:共享内核。某个沙箱里的恶意代码发起针对宿主内核的攻击,理论上可能影响其他沙箱。针对这个风险,我在DSec里保留了两种增强模式:一是给高危任务用gVisor之类的用户态内核做额外隔离,二是对确实需要极强隔离的任务提供虚拟机沙箱选项。默认走容器,特殊任务走强隔离,这是务实的组合。
2.3 弹性伸缩是怎么实现的
弹性伸缩这个词被用烂了,但智能体训练里的弹性伸缩,和常见的Web服务自动扩缩容压根不是一回事。Web服务扩的是无状态实例,流量大了加机器就行。智能体训练里,每个训练任务是有状态的,而且状态跟沙箱环境深度绑定。
DSec的弹性伸缩分两个层面。第一个层面是任务级弹性:一个训练任务内部,智能体数量可以动态变化。比如策略评估阶段,可能需要开50个智能体并行试跑,评估完就砍到10个。这个弹性由训练框架通过调度器API动态申请和释放沙箱来实现。第二个层面是资源池级弹性:整个沙箱集群的规模可以根据待处理任务的积压量自动调整,任务多了自动在空闲机器上扩容沙箱节点,空闲了自动回收。
实现弹性伸缩的关键前提是沙箱实例的标准化。如果每个任务都把环境搞得很特殊,调度器根本无法预测资源需求,也就谈不上弹性。DSec在实践中推开了一套环境模板机制:大部分训练任务都基于几个标准镜像模板,需要自定义环境时在启动脚本里做“增量修改”,而不是从零构建镜像。这样既保留了灵活性,又让调度器的资源预估模型可以正常工作。
3. 沙箱搭建与训练准备:实操级教程
3.1 基础环境准备
下面进入实操部分。我假设你已经有一台Linux服务器,最好是多核CPU加至少32G内存,有GPU更好。第一步是安装容器运行时。以Ubuntu 22.04为例,安装Docker或者containerd都可以,我个人推荐直接用containerd,因为它在资源管控和性能上更干净,Docker更适合交互式使用。
# 安装containerd apt-get update && apt-get install -y containerd.io # 安装nerdctl,作为containerd的命令行工具 wget https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-full-1.7.6-linux-amd64.tar.gz tar -C /usr/local -xzf nerdctl-full-1.7.6-linux-amd64.tar.gz # 验证安装 nerdctl version这里有个容易踩坑的地方:默认的containerd配置里,systemd cgroup驱动常常没有开启,这会导致容器内无法正确管理cgroup,资源限制形同虚设。修改/etc/containerd/config.toml,确认以下配置:
[plugins."io.containerd.grpc.v1.cri"] systemd_cgroup = true改完重启containerd服务,然后跑一个测试容器,进去看一下cgroup是否生效。用cat /proc/self/cgroup检查输出路径,如果路径里包含system.slice那基本没问题。
3.2 基础沙箱镜像的制作
沙箱镜像是一切的基础。我建议你不要直接拿公共镜像凑合,而是做一个团队内部的基础镜像,里面按智能体训练的需求预装好常用依赖。以DeepSeek智能体训练为例,基础环境至少要包含Python运行时、代码解释器、Git、常用命令行工具,以及一些会被智能体反复调用的工具库。
下面是一个Dockerfile示例,我在里面内嵌了Python环境和一个最简单的工具函数库。重点在于:把训练中几乎必然会用的依赖打进镜像,避免每个任务启动时都重复在线安装。
FROM ubuntu:22.04 ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y \ python3 python3-pip git curl vim jq \ build-essential ca-certificates \ && rm -rf /var/lib/apt/lists/* RUN pip3 install --no-cache-dir \ requests pydantic pyyaml numpy \ openai deepseek-api RUN mkdir -p /workspace /opt/tools COPY tools/ /opt/tools/ ENV PATH="/opt/tools:$PATH" WORKDIR /workspace CMD ["/bin/bash"]镜像做出来后,有两点必须验证。第一是启动速度,从容器冷启动到能执行命令,时间要控制在2秒内,如果超过5秒就要检查是不是镜像太臃肿。第二是可重复性,同一个镜像启动10次,环境一致性要有保证。我把这两个验证做成了一个自动检查脚本,每次改动基础镜像都会跑一遍,防止基础镜像悄悄变“脏”。
3.3 资源限制与隔离配置
沙箱的资源限制是DSec的核心功能,也是智能体训练可控性的保障。资源限制做不好,一个失控的智能体就能把整个训练集群搞崩。我采用的办法是给每个沙箱实例设置四道防线:CPU限额、内存限额、磁盘限额、进程数限额。
# 启动一个CPU限制为2核、内存限制为4G的沙箱 nerdctl run -d --name agent-task-0001 \ --cpus 2 \ --memory 4g \ --memory-swap 4g \ --pids-limit 256 \ -v /data/task-0001:/workspace \ agent-base:latest这里尤其要注意--memory-swap参数。如果不设置这个参数,容器可以无限使用swap,内存限制形同虚设。我见过一次事故:一个智能体任务因为环境bug不断申请内存,把swap耗尽后整个节点陷入假死状态,所有其他任务一起遭殃。设置--memory-swap等于告诉内核:物理内存加swap总量就这么多,超了直接杀进程。
磁盘限额也容易被忽略。容器默认的磁盘空间是共享宿主机的,一个任务写几十GB垃圾文件就能撑爆节点磁盘。DSec在挂载训练数据卷时,强制加上project quota或者子目录配额,具体实现可以用quota工具或者btrfs子卷配额,这里给一个用XFS project quota的示例:
# 假设/data/trains是XFS文件系统 xfs_quota -x -c 'project -s -p /data/trains/task-0001 task0001' /data xfs_quota -x -c 'limit -p bhard=10g task0001' /data配置完资源限制,还要注意一个细节:容器内看到的CPU数量。如果你不给容器设置CPU限额,容器内nproc看到的是宿主机的总CPU数,有些程序会根据这个数字自动开线程池,导致资源竞争失控。设置--cpus 2之后,配合正确的cgroup配置,容器内的lscpu和nproc就能正确反映限额。
3.4 环境快照与回滚机制的实现
快照回滚是我在调试智能体训练策略时最依赖的能力。智能体训练经常要做“环境假设验证”:假设把提示词里加一段约束,智能体的成功率会提升。改了环境之后跑一轮训练,发现效果反而变差,这时候必须快速回到修改前的状态,重新调整。如果没有快照机制,只能手动把环境文件一个一个倒回去,效率极低。
DSec的快照机制基于叠加文件系统,实现起来分三步:
第一步,把所有训练环境的持久化数据统一放到一个可快照的目录结构里。我用的是/data/snapshots/{task_id}/{version}/这样的层次组织。 第二步,用overlayfs把基础镜像和当前修改层叠加起来,生成一个可运行的沙箱视图。 第三步,每次启动训练前,自动打一个快照标注版本号;训练结束后,可以根据需要标记某个版本为“已验证”。
实际命令如下:
# 创建空的快照工作目录 mkdir -p /data/snapshots/task-042/001/{lower,upper,work,merged} # 把基础镜像目录作为lower层 mount -t overlay overlay \ -o lowerdir=/data/base/env-v2,upperdir=/data/snapshots/task-042/001/upper,workdir=/data/snapshots/task-042/001/work \ /data/snapshots/task-042/001/merged这样操作之后,智能体在merged目录里做的任何修改都只会落到upper层。要回滚时,直接换一个空的upper层重新挂载即可。整个快照过程不需要复制任何大文件,秒级完成。
这里有个实践上的建议:快照不要只做文件系统层面的,还要同步记录环境元数据,比如当前依赖的包版本、环境变量、启动参数。最好用一个JSON文件把每次快照对应的完整环境描述存下来,后面排查问题的时候,光有文件系统快照没有元数据,很多问题是看不出来的。
4. 智能体训练的具体运行与调度策略
4.1 从单机任务到并行任务编排
环境准备好之后,进入真正的训练编排环节。我先说最基础的:怎么在单个节点上并行跑多个智能体任务。DSec定义了一套任务描述文件,YAML格式,描述一次训练的完整信息,这样同一个任务可以在不同机器上复现。
# train-task.yaml task_id: agent-train-20241123-001 base_image: agent-base:v2 replicas: 16 resources: cpu: 2 mem: 4Gi pids_limit: 256 timeout: 3600 model: provider: deepseek model_name: deepseek-chat api_base: http://model-gateway.internal:8000 training: strategy: ppo max_steps: 100 env_snapshot_version: 001 entrypoint: - /opt/tools/run_training.sh - --config - /workspace/train_config.yaml有了这个任务描述文件,DSec控制面就会根据replicas字段一次性创建16个沙箱,每个沙箱分配独立的编号,把/workspace挂载到对应的任务目录,然后执行同一个entrypoint。16个任务之间通过一个共享的事后结果队列来进行信息汇总,不直接通讯。
这个设计的好处是,单个智能体任务的执行路径安全可控,就算某个任务彻底崩溃了,也只是影响它自己的沙箱,其他任务继续跑。我见过很多自己搭并行训练的开发者,喜欢用共享数据库或者共享内存来让智能体之间协作,这在实验探索阶段可行,但到了大规模训练阶段,耦合度太高,一个任务的失败往往会连锁带崩一片。DSec的默认模式是:通信通过外部存储,执行通过独立沙箱,失败通过自动重启解决。
4.2 动态调度需要关注的关键指标
调度器是整个系统里最容易出现性能瓶颈的组件。智能体训练的调度,我总结有三个关键指标,直接决定系统的吞吐和质量。
第一个是调度延迟,指一个任务从提交到实际在沙箱中开始执行的时间。这个时间越短,智能体单位时间内可以尝试的样本就越多。DSec的目标是把P50调度延迟控制在500毫秒以内,P99控制在2秒以内。达到这个目标的关键是沙箱预热:大部分任务用的都是同一个基础镜像,预先在节点上启动好一批“空闲沙箱池”,任务到达时代替创建等待。
第二个是资源碎片率。不同任务对CPU和内存的需求比例不一样,有的任务吃CPU多内存少,有的反之。调度器如果只按“还剩多少核”来决定分配,很容易出现某台机器CPU耗尽但内存还有一大堆空闲,另一台正好相反的情况。DSec采用多维资源匹配的调度算法,把CPU、内存、磁盘同时纳入候选评分,并且支持主动搬移一些轻量沙箱来为重型任务腾出位置。
第三个是任务失败率。这个指标可以直观反映沙箱环境的健康状况。DSec对失败任务做了自动分级:如果是训练代码自身的逻辑错误,重启也没有意义,应该把日志打出来供分析;如果是环境问题,比如依赖丢失、配置错误,重启前会自动重置环境到初始快照。自动重启加上重置环境这套组合,可以把偶发失败率从5%左右降到0.5%以下。
4.3 与DeepSeek模型服务的集成方式
DSec沙箱本身不直接跑模型推理,它是智能体的运行环境,智能体通过API调用DeepSeek的服务获取推理结果。这样一来,模型推理和智能体执行被拆到了两个独立的弹性层,各自扩缩容互不干扰。
在DSec里,我把模型调用封装成了一个统一的Gateway组件,沙箱内的智能体不需要知道背后接的是DeepSeek开源模型的本地部署服务还是官方API,只需要用统一的SDK去调用。这个设计在后面切换模型版本、做灰度验证的时候特别方便。
# 沙箱内智能体的模型调用示例 from dsec_sdk import AgentClient client = AgentClient(gateway_url="http://model-gateway.internal:8000") response = client.chat( model="deepseek-chat", messages=[ {"role": "system", "content": "你是一个代码审查智能体。"}, {"role": "user", "content": "请审查这段代码是否有内存泄漏问题。"} ], temperature=0.3, max_tokens=1024 ) print(response.text)这里有个实际踩坑的细节:智能体训练时的推理调用往往是非常短小的大量请求,每次几十到几百token不等。如果每个请求都新建一个TCP连接,Gateway很容易被打满连接数。DSec在Gateway里做了连接池复用和请求合并,同时把相同前缀的prompt缓存打上去,训练吞吐量提升了近3倍。
模型服务本身的扩容策略和沙箱不同。沙箱的任务生命周期很短、创建销毁频繁,而模型服务实例是长驻的,加载一个DeepSeek模型需要几十秒到几分钟不等。DSec的模型服务弹性策略是:预测式扩容,根据训练任务提交的预估推理量,提前预热若干模型推理实例,而不是等推理压力上来再去拉起实例。
5. 常见问题排查与踩坑实录
5.1 沙箱启动失败的排查路径
智能体训练中遇到最多的问题,第一大类就是沙箱启动失败。我列一个自查表,基本覆盖了90%的情况:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 容器创建超时 | 镜像不存在或仓库不可达 | 先nerdctl pull手动拉取镜像验证 |
| 容器启动后立即退出 | 启动命令错误或依赖缺失 | 看容器日志,检查entrypoint路径存在性 |
| 报资源不足(cannot allocate memory) | 节点内存碎片化或swap耗尽 | free -h查看内存,用cgroup清掉异常容器 |
| 挂载卷失败 | 目录不存在或权限不足 | 检查宿主机目录是否存在,属主是否匹配 |
| 容器内网络异常 | overlay网络配置错误 | 用nerdctl exec进入容器内,curl测试外网连通性 |
有一个特别隐蔽的问题:基础镜像里的动态链接库版本和宿主机内核不兼容。比如镜像是用新版本glibc编译的,宿主内核太旧,运行时会报奇怪的段错误。这个问题在容器方案里不太容易出现,但如果用了某些精简版基础镜像就会踩中。排查时用ldd检查主要二进制文件的依赖,确保都来自镜像自身。
另外还有一个体会:沙箱启动失败这件事,要用代码去自动化恢复,不要靠人工盯着。DSec里写了一层事件监听,沙箱创建失败时自动触发健康检查逻辑,区分“环境问题”和“任务问题”,环境问题就直接重建沙箱,任务问题就进入失败队列等待人工分析。自动化恢复机制上线后,训练集群的可用性从95%提升到了99.6%。
5.2 训练任务不稳定与上下文污染
第二类常见问题是训练过程中的不稳定,表现是同样的训练参数,跑出来的结果忽好忽坏。我排查过很多次,最后发现大概率出在上下文污染上。
举个例子:智能体在执行任务时,会在工作目录生成临时文件,这些文件如果留在沙箱里没清理,下一轮任务启动时会读取到旧的临时文件,行为被带偏。更危险的是环境变量污染,某个智能体在运行时修改了环境变量,沙箱回收后环境变量没有重置,下一个任务继承了坏的环境配置,整个逻辑就歪了。
DSec的应对方案是双层清理:每次训练任务结束,沙箱进入回收流程,第一层重置叠加文件系统,把任务期间的写操作全部丢弃;第二层重置环境元数据,把环境变量、启动参数恢复到初始快照状态。这两个清理过程都需要在调度器里登记状态,确保回收完成的沙箱才能被重新分配。
另外,语境污染也值得说道说道。DeepSeek这类大语言模型驱动智能体,它的“记忆”都在上下文窗口里。一次会话里如果前面几轮的对话出了偏差,后面无论怎么纠正,都很难完全拉回来。DSec在任务设计上强制了“分段会话”策略:一个长任务切分成多个短的子任务,每个子任务开始前都清理上下文,只保留必要的摘要信息。这样能显著减少一个偶然偏差在长链路中被放大的概率。
5.3 性能监控与观测的最佳实践
最后说观测性建设。智能体训练比传统模型训练更需要观测投入,因为模型的决策轨迹本身就是一个复杂系统,没有充分的观测数据,训练失败几乎无从排查。
DSec的观测体系分三层。第一层是沙箱级监控,记录每个沙箱的CPU、内存、网络、磁盘IO等指标,按秒级粒度采集。第二层是行为级日志,记录智能体每次调用了什么工具、拿到什么结果、做了哪些决策分支。第三层是训练级指标,比如任务成功率、每步耗时、策略奖励曲线。
这里我特别想说一个容易被忽视的点:行为日志和性能指标的关联分析。早期我的系统只有性能指标,问题是:看到某个沙箱CPU飙升,但完全不知道智能体当时在做什么,是写了个死循环还是真的在算复杂逻辑,根本区分不了。后来我把行为日志和性能数据打上同一个时间轴,统一存储到日志系统里,排查问题的效率提升了一大截。
实践中我给DSec配了一套简单的观测看板,核心就三张图:一张是集群维度资源使用率和任务积压量的趋势图,一张是某个具体训练任务的沙箱资源热力图,一张是所有行为日志里报错频率的排行。这三张图配起来,基本可以快速定位大部分训练异常。
关于观测数据的存储,有两点建议:第一,行为日志一定要结构化,用JSON格式直接落库,这样后续做数据分析时可以直接跑查询,不用做复杂的解析转换;第二,日志要设置保留周期和采样策略,全量永久保留很快会把存储撑爆,合理的做法是保留最近30天的完整数据和更久周期的采样数据。
训练基础设施建设的持续演进
折腾完这套DSec沙箱基础设施,我个人最大的感触是:智能体训练的效率瓶颈,往往不在模型推理速度上,而在基础设施对“试错循环”的支持速度上。你的沙箱创建够不够快、回滚够不够快、并行度够不够高、排查问题够不够轻松,这些直接决定了同样一块GPU一天能跑多少有效样本。DSec的这套思路,核心就是把环境稳定性、资源弹性和可观测性做到极致,让算法工程师可以专心在训练策略上而不是和基础设施搏斗。
最后分享一个工作中的小经验:不要指望第一版就把所有功能都做全。我的演进路径是先把单机多沙箱跑通,再逐步加入调度器和快照机制,最后才完善观测和自动恢复。每一步都比上一步在真实训练任务里用起来,发现问题再迭代。这样看起来慢,实际上比一开始就设计一个大平台然后在真实场景里四处碰壁要稳妥得多。如果你也在做类似的智能体训练基础设施,按这个节奏走,大概率能比我当年少走一些弯路。