ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

异步RL架构全拆解:三台可扩容机器如何重构Agent训练循环

异步RL架构全拆解:三台可扩容机器如何重构Agent训练循环 最近这套“小米 MiMo-V2.6 全异步 RL”架构在 Agent 训练相关的讨论里反复出现标题里的“每小时 3 万美元”先抓眼球但真正值得研究的是它把传统 RL 里那种“跑一步等一步”的 Agent 训练循环改成了三组可以单独水平扩容的机器集群让经验采集、模型训练、评估加工三条流水线互不阻塞地转起来。这对做 Agent 开发、Agent 框架选型、RL 训练和 AI 基础设施的团队来说都是一套能直接抄的架构思路。我拆这个标题不是要复现小米的原始代码而是从可落地的工程角度把异步 RL 到底异步在哪、三台“可放大的机器”各自干什么、怎么用队列和存储把它们串起来以及实际跑的时候会遇到哪些坑一条条讲清楚。你不需要一上来就有几十张卡理解了这套循环的拆分逻辑之后先用两台机器甚至一台机器做最小验证后面再按瓶颈逐步横向扩容这是最务实的路径。1. 这个标题背后到底在拆什么1.1 一句话说清 MiMo-V2.6 做了什么先别被“3 万美元”带走注意力。标题核心三个关键词全异步、Agent 训练循环、三台可放大的机器。把这三个词串起来理解就是一件事过去训练一个 Agent 模型常常是“环境采样、模型学习、评估验证”串在一起跑采样完了等模型更新模型更新完等下一批样本评估又要中断整个训练。MiMo-V2.6 这类全异步 RL 方案的做法是把这条串行链路拆成三个独立循环每个循环跑在不同的进程甚至不同的机器集群上相互之间通过队列和存储通信。经验采集器一直在采学习器一直在学评估器一直在抽检三条流水线各管各的转速谁慢了就单独扩谁。这个思路本身在分布式训练里不算全新概念类似 actor-learner 异步架构在强化学习里早就存在。但放到大模型 Agent 训练场景难点会放大很多倍Agent 的推理过程本身就要跑长上下文甚至多轮工具调用采样端比传统强化学习重得多模型参数量又大权重同步成本高再加上评估维度复杂不是简单看个 reward 分数就完事。所以“拆成三台可放大的机器”不是随意的而是顺着数据流的三个强约束点来切。1.2 “每小时 3 万美元”是怎么算出来的很多人好奇这个数字怎么来的。我们不用把它当成官方报价把它当成一个量级估算就行假设你租了一大批高性能 GPU 跑在线 RL单卡每小时折算价格大概在 2 到 3 美元之间同时手上跑了上万张卡一小时几万美元是很正常的。也就是说标题用“3 万美元/小时”这种量级在提醒你在这种烧钱速度下任何一个环节的同步等待都在浪费钱。我遇到过不少团队算成本只算“GPU 单价 × 数量 × 时长”却不算“GPU 有效利用率”。同步循环里最典型的浪费就是agent 和环境交互时训练卡没事干模型更新时采样卡闲着。异步拆分之后虽然总 GPU 数量未必变少但同样的卡能产出的有效训练样本变多了单位有效样本的成本就降下来了。换句话说不是异步让“每小时 3 万”变便宜了而是异步让这 3 万花得更值。1.3 谁最该认真看这套拆解如果你是纯搞算法、只想调 prompt 的 Agent 开发者这套东西可能离你有点远但你迟早会碰到“为什么我的 agent 在测试集上一直提升不上去”的问题那时候你会发现问题往往不在模型结构而在数据怎么采样、怎么练。如果你做 Agent 基础设施、训练平台或者大规模在线 RL那这套异步拆分就是你绕不开的架构课。而如果你只是技术负责人需要评估“我们的训练集群到底卡在哪、要不要再加卡”这个拆解也能帮你把决策点找出来。2. 同步训练循环为什么越跑越亏2.1 一个最朴素的 Agent 训练循环长什么样先看一个最原始的伪代码while True: # 1. 采集让 agent 与环境交互产生一批轨迹 trajectories collect_trajectories(agent) # 2. 学习用轨迹做 RL 更新更新权重 train_step(agent, trajectories) # 3. 评估跑一下 benchmark看 agent 行不行 score evaluate(agent)这段代码跑在小规模实验里没什么问题。循环次数少、环境简单、模型更新快等待带来的损耗可以被忽略。但到了生产级 Agent 训练循环里的每一步都会变得极慢而且互相等。这个“等”是同步架构最本质的问题。不光是时间上的浪费更麻烦的是它把所有环节耦合在一起你根本分不清当前系统瓶颈到底在采样、在训练还是在评估。2.2 三个拖慢速度的等待点第一个等待点是交互采样。Agent 每轮决策都要走大模型推理而且不是简单生成一句话可能要调用工具、看返回结果、再决定下一步。一个轨迹跑下来可能会来回十几轮一次采样慢则几十秒甚至几分钟。同步循环里这段时间训练卡全部空转。第二个等待点是训练更新。大批量轨迹攒起来之后模型要做一轮或多轮优化。这个阶段的耗时跟模型大小、序列长度、batch size 强相关经常一次更新跑几分钟。采样端就得停在那儿等新权重。第三个等待点是评估。你以为评估就是拿个测试集算准确率在 Agent 场景里评估可能是真实跑一遍任务流程可能要执行代码、访问 API、人工校验结果一次评估慢得吓人。同步循环里评估期间整个训练就冻结了。这三个等待点只要有一个存在整个流水线就以这个最慢环节的节奏运行。等你真的把一个复杂 Agent 任务跑下来会发现大部分时间不是在“学”而是在“等”。2.3 同步方案的工程代价同步方案另一个隐蔽代价是调试困难。一旦训练效果不好你很难判断是采样分布有问题、模型过拟合了还是评估逻辑不合理。因为所有状态都是紧耦合的改一个参数可能引起另一个环节的连锁反应排查一个训练事故要同时翻三套日志。扩容也很尴尬。同步架构里你很难单独加几台机器提速某个环节。想加速采样就得把整个循环都轮流迁到新集群上每次迁移都是一次大手术。而且同步分布式训练通常依赖 AllReduce 这类集合通信加机器要先解决通信拓扑、网络带宽、同步超时一堆问题扩容的线性收益很低。所以同步方案适合验证想法不适合规模化生产。一旦你认真做 Agent 模型的 RL 训练异步化几乎是必然选择。3. 三台可放大的机器各自干什么3.1 第一台机器Rollout Worker经验采集器这台机群的核心职责只有一个尽可能快地生产训练样本。它跑一个完整的 Agent 交互循环把 prompt、工具定义、环境接口组装好调用底层 LLM 做推理然后在你的 Agent 框架里编排多轮动作最后把整条轨迹序列化投递到经验队列里。别把 Rollout Worker 理解成简单调一下模型 API它在生产环境里是重负载。因为要支撑大量并发 Agent 交互需要在推理侧做批处理把多个请求拼成一个 batch 送进 vLLM 或 SGLang利用 KV Cache 复用上下文来减少重复计算。很多团队在异步 RL 里遇到“推理速度跟不上训练速度”就是没在这一层认真做推理优化。Rollout Worker 通常是整套架构里最容易扩展的组件因为它基本无状态。你可以只记录当前用的模型版本号其他状态都放外部存储。一旦 Agent 任务并发数上来直接横向加机器就行。3.2 第二台机器Learner Worker权重更新器Learner 负责真正意义上的“学”。它不直接跑 Agent 环境而是从经验队列里不断拉取轨迹组装成训练批次执行 PPO、GRPO 之类的 RL 目标更新或者做偏好优化、SFT 增强。它在迭代里不依赖外部环境核心依赖是经验和当前权重。这台机群的一个关键设计是更新批次的组装策略。异步场景下经验队列里的数据来自不同时间点、不同模型版本直接混在一起训可能会造成分布偏移。所以 Learner 通常会维护一个经验缓冲按时间窗口或者按采样优先级来抽 batch。有的实现还会做 KL 约束防止策略更新太猛导致样本质量崩塌。Learner 扩容相对复杂一些因为它涉及多卡并行训练模型同步、梯度通信、学习率调度这些都要重新设计。但它比 Rollout 好扩因为不需要跟外部环境同步本质上是个吞吐型计算任务。3.3 第三台机器Evaluator / Data Curator评估与数据加工器第三台机器最容易被人忽略但它往往决定了整个项目的天花板。它的职责是接住来自 Learner 的新权重快速评估出当前 Agent 在真实任务上的表现并把结果反馈给策略选择、数据调度甚至 Learner 的训练目标。在大模型 Agent 场景里评估器经常不止跑分数还承担数据加工。比如代码生成任务里它要实际执行生成的代码判断是否通过测试用例做工具调用的任务里它要模拟用户和环境交互把结果回填成新的训练样本。这也解释了为什么很多实现把 Evaluator 和 Data Curator 合并成一个角色评估的过程本身就在产生更高质量的训练数据。这台机器可扩容性很强因为评估任务天然可以拆成独立 job 跑。关键是评估结果要写回一个同步机制让 Learner 能知道当前模型表现如何从而调整经验采样比例或学习率。3.4 三台机器之间的通信和存储设计三台机器不能各自闷头跑得有一套协作通道。经验数据从 Rollout 流向 Learner权重从 Learner 流向 Rollout 和 Evaluator评估结果从 Evaluator 流回 Learner这三条通道是异步架构的血管。生产里常用的做法是两条路并行短时高频数据走消息队列比如 Redis Stream、Kafka长时稳定数据和模型权重走对象存储或共享文件系统。经验数据不一定全量进队列可以先落盘再按需订阅避免堆积。权重更新按“版本号 检查点文件”管理Rollout 或 Evaluator 定期检查最新版本号按需拉取而不是靠 Learner 主动推。通信是这个架构里最容易漏水的地方。一旦带宽打满或者队列积压三台机器之间的节奏就会脱节。所以每一层通信都要设计好推荐、批量和超时机制明确“多久没拉到新权重算失败”这类边界条件。4. 核心细节与实操要点4.1 经验缓冲区的容量和淘汰策略经验缓冲区设计直接决定训练稳定性和节奏。缓冲区太小Learner 可能吃不到足够的样本训练震荡缓冲区太大样本太旧模型学到的分布跟不上当前策略。我自己实践下来的经验是缓冲区大小不要设成“越大越好”而是围绕一个目标来设——让 Learner 在一个更新窗口内看到的数据尽量来自同一代的策略分布。具体做法可以按迭代数分桶每个桶对应一个模型版本产生的样本训练时优先采样当前版本桶其次是最近一两个旧版本桶更老的数据直接丢弃或按极低概率采。淘汰策略也要配套。常见的是先进先出简单但容易把高质量长尾样本丢掉更好的是按 reward 或按任务完成度优先保留那些能提供更多学习信号的样本。注意这里不要过度淘汰否则会放大模型 bias。4.2 权重异步传递的版本管理异步架构里最容易被忽略的问题是Rollout 还在用旧权重Learner 已经更新好几版了两边版本差距大到一定程度训练数据就全是“过时数据”了。传统分布式 RL 可能觉得差一两个版本无所谓但大模型 RL 里一次更新可能就改变整体行为过时权重产生的轨迹对训练有害。解决办法是设一个“最大过时步数”。比如 Learner 最多允许 Rollout 落后 2 个权重版本超过这个阈值就强制采样端切到最新检查点。这也意味着 Learner 不能每次小步更新都立刻推全量权重而是走检查点快照和拉取模式。快照文件放共享存储Rollout 不用关心 Learner 内部细节只需要定时访问版本清单。在实际部署里我见过不设这个阈值导致训练崩溃的案例采样端一直用几十个版本之前的模型产出的轨迹质量越变越差Learner 拿着坏数据越训越偏最后整个策略直接崩掉。把这个阈值写死并加监控曲线是很便宜却非常有效的保护手段。4.3 模型更新时的通信和计算配比异步 RL 的系统性能取决于三台机器之间的吞吐是否平衡。一个常见失衡是Learner 更新太快Rollout 跟不上导致经验队列取空Learner 空转或者 Rollout 产出了海量经验Learner 消费不完队列积压数据存储压力巨大。解决思路是动态地调整采集和训练的比例。如果队列积压可以降低 Rollout 并发或者调低采样 batch如果队列长期为空增加采样并发或向 Rollout 发“多采一点”的控制信号。这个比例千万不要拍脑袋写死因为训练初期模型探索需求大后期需要更多高质量数据动态调整才能保持稳定。有一个相对实用的参考配置如果你把 Learner 更新频率设为固定秒级间隔那么经验产出速率应该稳定在“一次更新所需样本量”的 2 到 3 倍以上。这样缓冲区不会空也不会积压得太旧。当然这个比例要根据模型规模和任务难度微调。5. 实操过程从零搭一套最小异步 RL 管线5.1 最小架构选型真实复刻 MiMo-V2.6 这种大规模方案需要很多机器但你可以先用单机多进程把架构跑通。一个最低配置是这样组合Rollout Worker用 Python 进程加载 vLLM 推理引擎内部实现一个简单的 Agent 循环每次交互把轨迹写到 Redis Stream。Learner Worker一个训练进程从 Redis Stream 读取轨迹用 LoRA 或全参微调做小步更新每次更新完写一个检查点文件到本地或者 NFS。Evaluator Worker一个评估进程定期读最新检查点跑几个简单任务把结果写回数据库或消息队列。协调层Redis 同时承担经验队列、任务队列和轻量状态存储NFS 或 S3 放权重版本文件。这套方案不需要引入特别重的训练框架完全可以用 Ray 或 Celery 把三个进程编排起来。核心是先验证“三条循环是否能并行推进”而不是追求性能。5.2 跑通流程的检验步骤第一个检验目标是确认数据流没有断。启动三个 Worker 后先跑一小批任务观察 Redis Stream 里有没有轨迹Learner 有没有消费轨迹并产生 lossEvaluator 有没有输出评估分数。任何一个环节卡住都说明消息格式或版本号对不上。第二个检验目标是确认异步更新真的生效。连续跑几个训练周期记录 Rollout 采样时的权重版本号和 Learner 当前版本号。如果两者始终一致说明异步还没真正建立你需要检查是否因为数据量太小导致一边等另一边。第三个检验目标是确认评估结果在影响训练。理想情况下Evaluator 分数低时Learner 会自动提高近期样本的采样权重或降低学习率。这一步不一定在第一版就实现但至少要留出数据通道否则第三台机器就只是个“旁观者”没有真正的控制闭环。5.3 参数推荐和调优顺序先给一组保守的初始值经验缓冲区容量 4096 条轨迹每批次训练样本 128 条Learner 每 10 秒更新一次最大过时步数 3 个版本KL 约束系数 0.1。这个配置不是最优而是稳。调优顺序应该从下往上。第一步只调采样并发把 Rollout 的吞吐提上去直到队列不空。第二步再调 Learner 的更新频率和 batch size观察 loss 和 reward 曲线。第三步才去碰评估端的检测频率和样本权重因为前两步没稳定时评估信号本身就没意义。我踩过不少坑最大的教训是不要同时调多个参数。异步系统本来就有时间延迟你同时改采样批大小和 KL 系数看到效果变差时根本不知道是哪个参数引起的。5.4 我建议的最小可用版本一台机器也能跑通如果你连多台机器都没有也可以在一台机器上模拟。把三个 Worker 当作三个进程跑通过本地 Redis 通信效果一样。这里唯一的风险是资源共享导致互相抢占 CPU 和显存所以最好把 Rollout 的推理引擎和 Learner 的显存需求错开比如推理用小显存模型学习用 LoRA 轻量更新。在小规模复现时不要迷信异步就一定快。同步逻辑在小规模下可能更简单、更稳定。你的目标应该是“把异步架构的骨架搭起来后续再上机器”而不是为了异步而异步。6. 常见问题与排查技巧实录6.1 训练不收敛或者越训越差这是异步 RL 最经典的坑。先看队列里的数据分布如果数据全部来自旧版本策略采样端和训练端可能已经严重脱节。立刻检查过时步数阈值把 Rollout 强制切到新权重。还有一种可能是经验缓冲区淘汰策略太激进高质量样本被丢掉模型反复在低质量子集上过拟合。把淘汰策略调回先进先出看 reward 曲线是否恢复。如果还没恢复检查 KL 约束系数异步训练里策略变化往往比同步更猛适当加大 KL 约束能防止跑偏。6.2 队列积压或者长期为空队列积压最好办要么降 Rollout 并发要么升 Learner 吞吐。但长期为空时别急着加卡先看是不是训练端消费太快、经验生产端样本生成失败率太高或者 Agent 交互因为环境 API 超时而拿不到结果。很多时候不是机器不够而是环境侧响应太慢把采样链路卡死了。我遇到过最隐蔽的一个是因为工具调用接口返回了异常格式Rollout 解析失败直接把整个轨迹丢弃导致大量辛苦采集的数据被白白扔掉。后来在 Rollout 侧加了异常数据处理逻辑凡是失败轨迹只要保留原始 prompt 和错误信息也写入队列作为难例样本训练数据量和训练效果都明显提升。6.3 通信带宽打满训练反而变慢异步架构的部分开销是进程间通信。如果权重文件和轨迹数据都走网络传输随着集群规模扩大带宽就是最稀缺的资源。实战里建议轨迹先压缩再投递权重检查点用增量快照而不是全量传输纯文本字段做序列化优化。还有一个技巧不要每条轨迹都单独发消息按小批次打包。比如每 16 条轨迹打包成一个消息Redis Stream 或 Kafka 的吞吐会明显提升也能减少网络往返次数。6.4 检查点恢复和重启问题异步系统一挂就是一大片要有能力恢复到最近一致状态。设计思路是经验数据落一份到对象存储权重检查点存到共享存储协调层的队列可以从最近位置消费。重启时先恢复权重再恢复近期经验不要从零开始。为了快速翻车恢复建议把检查点写入操作做成幂等。Checkpoint 文件用版本号加递增时间戳同一个版本重复写入不会造成错误。返回连接时也先查一下新旧版本差异不要盲目追所有历史数据。6.5 一个容易踩的隐形坑评估端拖后腿不少人以为加了评估器就高枕无忧结果整个训练被评估卡死。原因是评估任务没有做异步抽检每次评估都要把完整 benchmark 跑一遍而 Agent 任务评估又特别慢导致 Learner 长时间等评估结果。解决思路很简单评估不用每次全量跑可以按任务类型分层抽样高频轻量测试做快速反馈低频重型测试做定期全量验证。反馈回路要快精度可以低一点异步系统里时效性比一次精确评估重要得多。结语这套异步 RL 架构真正打动我的地方不是一个惊天动地的算法革新而是它把工程组织的思路用得非常到位把一条强依赖链路切成三个可独立调优和扩容的单元。我在实践中的体会是做 Agent 训练不能只盯着模型 loss你要把目光放到整条数据流水线上。什么时候经验队列不健康、什么时候权重版本过期、什么时候评估反馈太慢这些系统层面的指标往往比单次训练指标更能决定项目能不能走远。如果你现在正准备搭自己的 Agent 训练系统我的建议是从最小异步版本起步先把三个环节跑通再按瓶颈扩容。别一上来就想着三台机器全都挂满卡先把调度和通信逻辑验证清楚后面扩机器只是加资源的问题。这套架构后续还能继续往外扩比如加上奖励模型服务、让评估结果自动调整数据采样权重、把经验库做成更智能的难例挖掘管线每一块拆出来都是可以独立打磨的方向。先把这个循环拆对了后面的事都好说。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进