尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

解耦式RL后训练调度:从作业级到阶段级的协同调度之道

发布时间:2026/9/6 12:11:59

资讯中心
01
ARTICLE

解耦式RL后训练调度:从作业级到阶段级的协同调度之道

解耦式RL后训练调度:从作业级到阶段级的协同调度之道
做后训练系统做了两年多我越来越觉得调度才是真正的隐形瓶颈。预训练时代把集群喂饱就行到了 RL 后训练阶段一堆策略模型、奖励模型、 rollout worker、评估任务在同一个集群上互相抢资源GPU 时而排队时而空转随便一个环节卡住整条流水线就得停滞。所以看到 OSDI26 这篇 Weave 的题目时我第一反应是终于有人把“后训练的调度”当成一个正经研究问题了。它不是又一篇堆算力的训练框架而是面向解耦式 RL 后训练、把“协同调度”作为核心设计目标的系统论文。对于正在搭推理模型训练平台、或者被 agentic RL 的多阶段任务搞得焦头烂额的工程师来说这篇论文值得认真读。这里我结合自己对后训练系统的理解把 Weave 的核心设计思路、关键技术点和落地价值拆开聊聊。重点不放在复述论文而是讲清楚为什么要这么设计解决的是哪些真实痛点。1. 后训练为什么成了调度的新战场1.1 预训练和后训练的“性格”完全不同如果只用一句话概括预训练和后训练的区别我会说预训练是“同构、长稳、好规划”后训练是“异构、短爆、难预期”。预训练任务本质上就是在一个超大集群上重复执行同样的前向反向计算输入输出格式固定计算图稳定模型结构不变资源需求几乎恒定的。调度它就像调度一条流水线只要把 GPU 按固定的拓扑分配好剩下的事情就是等训练收敛。Kubernetes 或者 Slurm 这种传统批处理调度器就能干得很好因为它们面向的就是这种长期运行、资源形状固定的作业。后训练完全不是这个节奏。以最典型的 RLHF 流程为例整个过程被拆成四个反复迭代的环节从 prompt 数据集采样、让当前策略模型生成 response、用奖励模型给 response 打分、基于打分结果做强化学习更新策略。这里 rollouts采样生成通常跑在 CPU 或者低端 GPU 上而训练更新必须用高端 GPU两个阶段的计算密度差了好几个数量级。更关键的是rollout 的耗时是动态的——如果策略模型正在探索新的生成方式response 可能变得非常长或者某条 prompt 触发了特别复杂的推理链导致某一段 rollout 突然从几秒钟膨胀到几十秒原有的资源分配立刻失效。这就是后训练调度难的第一层原因同样是“一个训练任务”内部由多个资源画像完全不同的子任务组成而且每个子任务的负载随时间剧烈波动。你没有一套静态的分配方案能同时满足所有子任务。1.2 “解耦式”架构让调度问题浮出水面Weave 标题里有个关键词叫“解耦式 RL 后训练”这背后其实是近几年后训练系统设计的一个明显趋势不再把整个 RL pipeline 当作一个紧耦合的单体作业而是把各个阶段拆开让每个阶段可以独立扩缩容、独立调度、独立容错。为什么大家会往这个方向走直接原因是效率。紧耦合的方式里如果 rollout 慢了训练侧就只能干等着GPU 空转或者训练侧更新参数太频繁rollout 侧生成的一大批旧策略样本就作废了。解耦之后你可以让 rollout 和训练用不同的速率运行中间用 buffer 缓冲谁快谁慢互不拖累集群利用率会高很多。但解耦并非没有代价它把原本藏在单体作业内部的一些问题给暴露出来了。最直接的就是阶段之间有了显式的数据依赖各自所需的资源也不再是一体的这时候由一个全局调度器来统一协调就显得尤为重要。否则就会出现一种很尴尬的局面——资源管理系统只看到若干个互不相干的作业有的作业在排队等 GPU有的作业在 CPU 上疯狂产出数据而因为缺乏协同资源被白白浪费掉。这就引出了 Weave 想解决的核心问题当后训练被拆成多个可独立扩缩容的阶段后调度器怎么才能让它们协同工作既满足每阶段对资源的动态需求又不让整个集群的资源利用率往下掉。1.3 agentic RL 会让调度压力再上一个台阶最近 agentic RL 这个概念非常热大家开始用强化学习训练 agent 去执行多步推理、调用工具、跟环境交互。这类任务放到后训练调度场景里麻烦程度是成倍增加的。传统 RLHF 里一次 rollout 就是让模型生成一段文本耗时模型也就是 tokens 数量可预估性比较强。但 agentic RL 的一个 rollout 可能是一整条行动轨迹模型决定调用某个工具等待工具返回结果再根据结果决定下一步动作。这条轨迹的长度完全不可预测取决于 agent 的决策过程和环境响应速度。有些轨迹可能三步就结束了有些可能要交互几十轮。这意味着 rollout 阶段的任务粒度从“分钟级”变成了“不确定时长级”每个 agent 会话占用资源的时间方差极大。调度器如果只按固定时长预估任务很容易出现大量资源被一个漫长轨迹霸占、其他短任务排队等待的场景。另外 agentic RL 的训练通常还涉及搜索过程比如在树状结构里并行探索多个分支然后用探索结果做策略优化。这种模式天然会生成大量动态子任务子任务的产生和消亡依赖于前一步的结果不可能提前静态规划好。Weave 这类面向动态协同调度的系统正是冲着这个方向去的——它的设计目标就是让调度器能感知阶段间的动态反馈并快速响应用资源形状的变化。2. 解耦式后训练调度到底难在哪2.1 任务之间的依赖不再是简单的 DAG很多人一听到“多阶段任务调度”第一反应是“这不就是一个 DAG 调度问题吗我拓扑排序一下按层分配资源不就行了”实际上后训练调度的依赖关系远不是静态 DAG 能描述的。最典型的问题就是 rollout 和训练之间是循环依赖训练需要 rollout 产出的样本而 rollout 又依赖训练产出的最新模型参数。这个循环意味着调度器不能像处理批处理作业那样把任务分成几个清楚的 wave一个 wave 跑完再跑下一个。在这个循环里阶段间的数据流向是双向的而且速率必须动态匹配。训练快的时候rollout 侧的生产速度跟不上训练就饿肚子训练慢的时候buffer 里堆了大量样本又可能因为策略更新太快而过期产生“样本陈旧性”问题。调度器需要根据每个阶段的实时吞吐动态调整资源比例这比静态 DAG 的依赖调度要复杂得多。更麻烦的是有些阶段之间还存在隐性的资源竞争。比如强化学习评估阶段通常会在验证集上跑多个 checkpoint这个任务和 rollout 任务可能用的是同一批 CPU 资源池但评估任务的优先级在临近里程碑节点时会突然变得特别高。调度器如果意识不到这些阶段之间的软依赖和优先级关系很容易在关键时刻把资源分错了方向。2.2 异构程度从“硬件异构”升级到了“任务异构”传统调度器所说的异构通常指的是 GPU 型号不同、显存大小不同、CPU 核数不同。到了后训练阶段异构变成了更细粒度的事情同样是“用 GPU”rollout worker 跑的是低精度推理对算力要求不高但对吞吐敏感训练器跑的是大 batch 训练对显存和卡间带宽要求极高而奖励模型打分可能只需要轻量的计算。这种任务异构带来的直接后果是一个简单的“所有任务按 GPU 数量平均分配”策略根本没法用。你可能会遇到一台 A100 机子上同时在跑推理型 rollout 和训练型任务前者只需要 2GB 显存后者把整机显存吃满了造成资源碎片化。即便硬件本身能凑合跑任务间的干扰也会让吞吐变得极其不稳定。调度器必须有能力识别任务对资源的需求类型是需要“海量并发小请求”还是需要“独占大 GPU”或者是 CPU 密集型的采样任务。然后把这些需求映射到合适的资源域里同时做到合理隔离。这个能力在预训练时代并不重要因为所有任务都是大 GPU 训练但在后训练时代就非常关键了。2.3 在线和离线混合让优先级变得复杂后训练集群上跑的不只是离线任务还有一堆在线服务。我自己就吃过这个亏模型在训练过程中偶尔需要加载最新的 checkpoint 做在线评测或者在 demo 环境里跑一轮人工体验。这类在线请求对延迟非常敏感一旦被调度器扔进一个长队列里排队用户体验立刻崩掉。这里就出现了一个典型的混合优先级难题离线任务希望最大化吞吐在线任务希望最小化延迟离线任务遇到在线任务抢占时应该让位但不能因此频繁重启导致开销过大。Weave 这类协同调度器需要能够区分任务类型并采取不同的调度策略——比如在线任务用抢占式调度离线任务用等待式调度。还有一个容易忽略的问题不同阶段在不同时间点对资源的需求优先级完全不同。比如在探索初期你可能希望给 rollout 分配更多资源去采集多样性样本到了训练末期你可能更希望快一点完成训练把更多资源倾斜给 trainer。这种“阶段性优先级”的表述传统资源队列很难表达清楚但 Weave 这类面向阶段级协同的系统就能天然支持。3. Weave 的设计思路拆解3.1 核心思路把调度粒度从“作业”下沉到“阶段”读完 Weave 的整体设计我做了一个简单概括它做的最核心的事情就是把调度和管理的基本单位从传统意义上的“作业”job下沉到了“阶段”phase。这是什么意思呢传统调度器里你提交一个训练任务是作为一个整体提交的资源需求基于整个任务的最大值来申请。比如你的 RL pipeline 需要 32 张 GPU 做训练64 张做 rollout那你就得一次性申请 96 张 GPU哪怕训练的利用率只有一半也得霸占着否则资源随时可能被别的任务抢走。这对集群资源是巨大的浪费。Weave 不一样它把 RL pipeline 拆分成若干个阶段每个阶段可以独立提交、独立调度。当一个阶段暂时不需要资源时比如 buffer 已经堆满不需要继续 rollout调度器可以把这些资源释放给其他作业。阶段内部的扩缩容也不需要重建整个作业只对特定阶段进行操作。这个设计的直接收益是资源利用率上了一个台阶。你可以想象一个极端场景某个 RL 任务的 rollout 已经产出了足够多的样本但训练还在慢慢消化这时候如果 rollout 还霸占着 64 张 GPU就纯属浪费。有了阶段级调度调度器可以自动把 rollout 缩容把释放出来的 GPU 分配给其他排队的高优任务等 buffer 里的样本快消耗光了再扩回来。3.2 两层调度逻辑资源与物理资源解耦Weave 的另一个关键设计点是两层调度架构。上层是一个逻辑调度器面向租户和作业负责判断某个阶段当前应该分配多少资源也就是算“需求量”下层是一个物理调度器根据逻辑层下发的资源需求在真实节点上完成资源分配和回收也就是算“供给量”。为什么要把这两层分开因为它们的优化目标完全不同。逻辑调度层关心的是当前 RL 作业处于什么状态各阶段的 buffer 水位如何模型版本是否新鲜该扩展还是收缩。它的判断依据是 RL 训练的状态指标比如 rollout 吞吐、训练步数、buffer 容量。这一层一定要离训练逻辑足够近否则感知不到动态变化。物理调度层关心的是集群上哪个节点有空闲 GPU哪些节点之间可以搭建高速互联如何放置任务能够最大化带宽、最小化碎片。这一层需要跟硬件拓扑打交道必须和集群管理深度集成。把这两件事混在一个调度器里做通常会导致两个后果要么调度器离硬件太近、感知不到训练语义要么它太懂训练语义、但对于硬件放置完全不敏感。Weave 用两层结构把它们拆开让每一层都能专注自己的核心问题我觉得这是它最务实的一个决策。3.3 可组合的协同策略调度逻辑不再写死在系统里我们在自研后训练平台时遇到一个特别头疼的问题调度策略没法灵活调整。想让训练阶段优先就得改代码想让某个低优阶段的资源让给高优阶段又得改代码。每改一次调度策略就是一次发布流程遇到线上问题还得回滚。Weave 的策略抽象方式让我眼前一亮它允许用户用可组合的方式描述“在什么样的状态下对哪个阶段做什么操作”。比如可以指定当 rollout buffer 的填充率低于 30% 时将 rollout 阶段的资源配额提升 50%当训练阶段的平均排队时间超过 5 分钟时被占用资源可以抢占其他低优先级作业。这种策略不再是调度器内部写死的一段逻辑而是作为动态可配置的输入让每个租户都能表达自己的细分需求。实际落地的时候这个能力意味着你没有必要为了满足一个新场景去改调度器主程序只需要调整配置即可。对于调度系统这种要保证高稳定性的基础组件来说这个设计带来的工程价值非常大。4. 核心机制与实操要点4.1 阶段状态与预期吞吐的量化做调度系统最难的一件事就是“判断当前资源够不够”这件事并没有一个标准答案。对于 RL 后训练我认为最有效的判断方法是围绕“预期吞吐”来做计算。拿 rollout 阶段举例。假设当前训练侧每秒钟需要消费 100 条样本每条样本平均 2000 tokens那么 rollout 侧的期望吞吐就是每秒 20 万 tokens。如果 rollout 侧当前只有每秒 15 万 tokens 的能力那么 buffer 会持续缩小如果 buffer 已经见底就需要立刻扩容 rollout 资源。这个计算本身不复杂难在 DAG 依赖那部分如果要扩容 rollout资源从哪来只能从其他任务抢或者从共享池子里拿。这时候就得依赖策略层来判断优先级是优先保障当前训练的推进还是保留资源给更重要的其他租户Weave 的价值恰恰在于它把“预期吞吐”建模成了调度器的核心输入而不是让调度器仅仅根据“已经排了多少个任务”来做判断。4.2 动态扩缩容与反向压力有了量化的吞吐目标动态扩缩容就不再是一句空话了。具体的操作流程可以拆成这么几步监控每个阶段的关键指标包括 buffer 水位、生成速率、消费速率、排队长度每隔一个决策周期比如 10 秒把这些指标带入预定义的策略规则中计算资源需求如果在某个阶段连续几个周期都处于资源不足状态就触发扩容指令向物理调度器申请更多资源反之如果阶段进入空闲状态主动释放资源。这个机制里有一个特别容易踩的坑震荡。当你根据 buffer 水位做扩缩容时如果阈值设置得太敏感很容易出现扩完立刻又要缩、缩完又发现不够用的循环。每次扩缩容都涉及资源重新分配频繁操作会让整个集群调度开销变大甚至导致训练任务来回迁移。我自己的经验是一定要给扩缩容加“滞回区间”。也就是说扩容和缩容用不同的阈值中间留一个缓冲区间。比如 buffer 填充率低于 30% 才扩容高于 70% 才缩容这样能显著降低抖动概率。论文里虽然没有细讲这块的超参调优但从工程实践角度这是必不可少的一步。4.3 抢占与优先级如何不伤训练协同调度必然会涉及抢占否则高优任务永远要等低优任务跑完。但在后训练场景下直接杀掉一个正在运行的 rollout worker 倒还好最多损失一些未完成样本可如果抢占的是 trainer代价就大了因为训练任务的状态通常很大频繁打断可能导致 checkpoint 不一致甚至丢失多轮更新。所以我们做抢占时需要区分可抢占和不可抢占的负载。rollout 这种无状态任务可以随时被杀、随时重启恢复属于“友好可抢占”训练器则应该用“优雅降级”的方式比如先停止下发新 batch等当前 batch 跑完写一个临时 checkpoint 再释放资源而不是硬杀进程。Weave 这类协同调度框架正是通过明确不同阶段的抢占语义以及提供优雅退出机制来避免抢占对训练过程造成严重伤害。如果你在自己搭后训练平台建议把“抢占时的行为”作为阶段注册信息的一部分配置明白这会让你后续运维省很多心。4.4 容错设计与血缘追踪资源调度系统一旦管到了阶段粒度就面临一个新问题怎么保证数据依赖和血缘关系的可靠性。举一个实际场景某个 rollout 任务产出了一批样本写入了共享存储随后因为优先级被抢占而中断。这批样本可能是完整的也可能只有一半。如果没有明确的血缘记录训练侧拉取数据时可能拿到不完整的文件造成训练崩溃或者静默的脏数据。在 Weave 的设计体系下每个阶段产出的数据都应该附带版本标识和完整性元数据。调度器在资源分配时也需要感知到哪些数据已经完整消费、哪些还在生产中避免出现消费者跑到生产者前面去的场景。这其实已经超越了传统资源调度的范畴变成了一个数据和计算协同调度的问题但它恰好是解耦式后训练必须具备的基础能力。5. 从 Weave 到你的平台落地建议5.1 最小化改造从作业级调度到阶段级调度如果你目前的后训练平台还是作业级调度也不用急着推倒重来。我建议分三步渐进改造。第一步先把 RL pipeline 的各个阶段显式声明出来。你在代码里定义阶段 Asampling阶段 Btraining阶段 Cevaluation。每个阶段有独立的资源请求和独立的 checkpoint 路径。这一步甚至不需要改调度器只需要改训练框架让它可以分阶段单独提交。第二步在调度器里为每个阶段引入独立的优先级和资源配额。这个阶段通常可以用 Kubernetes 的朋友实现比如给每个阶段创建不同的 Deployment 和 HPA 策略让它们在共享集群上独立扩缩容。第三步再引入阶段间的协同逻辑。比如通过一个 controller 监测 rollout 的生产速率和训练的消费速率动态调整 HPA 的目标副本数。做到这一步你就已经有了一版简化版的 Weave核心原理是相通的。5.2 对现有基础设施的适配Weave 不是一个架空的设计它的物理调度层是可以适配多种底层资源管理系统的。如果你已经在用 Kubernetes 管理集群那么物理调度层可以抽象成对 node 资源的精细管理逻辑调度层作为 Operator 运行在 K8s 之上。和 Slurm 这类传统批处理系统结合时主要问题在于 Slurm 对动态扩缩容和抢占的支持不如 K8s 灵活。一个可行的折中方案是保留 Slurm 做长期训练作业的调度然后用一个轻量级 K8s 集群专门跑 rollout 等短期弹性任务两个集群之间通过共享存储和消息队列协同。还有一个经常被忽略的适配点数据平面。后训练阶段之间的数据转移量非常大调度器在做资源放置决策时必须把数据位置考虑进去。如果 rollout 产出的数据存在节点 A 的本地盘而 trainer 被调度到了节点 B且 B 到 A 的网络带宽很差这个训练效率就会非常令人着急。所以你得在调度里加入数据亲和性约束让 trainer 尽量落到离数据近的位置。5.3 避免过度设计最后想提醒一句不是所有后训练场景都需要 Weave 这种复杂度的调度器。如果你的业务里模型规模和并发都有限现有框架就能满足不要为了用新技术而引入不必要的麻烦。我们内部曾经在某个小规模项目里硬套了一整套协同调度体系结果每天光处理调度器本身的报警就花掉不少时间最终收益反而为负。合适的用法是当你发现集群资源利用率持续较低或者 RL 任务的训练时常因为资源协调不当而频繁停滞再考虑引入阶段级的协同调度。Weave 解决的是“规模化之后的调度复杂性”小规模场景里传统方案往往已经够用了。6. 常见问题与排查思路实录这里整理了一些我们在实际构建类 Weave 系统时遇到的问题以及对应的排查思路供大家参考。现象可能原因排查手段rollout 扩展后吞吐没有明显提升资源虽增加但数据写入存储成了瓶颈检查存储带宽和写入队列长度确认不是磁盘/网络打满训练任务频繁等待样本buffer 消费速率大于生产速率扩容策略不敏感检查 buffer 水位曲线适当降低扩容阈值或扩大单次扩容幅度扩缩容频繁震荡阈值区间过窄没有滞回空间拉大扩容和缩容的阈值间距增加冷却时间抢占后训练断点恢复失败训练器被硬杀未写入正确 checkpoint对训练器实施优雅退出机制确保阶段退出前完成状态持久化两个阶段互相等待死锁调度策略中资源优先级配置矛盾清理阶段的资源依赖循环给数据流定向规定明确的生产-消费契约在线评测任务延迟过高在线任务和离线任务共用一个队列将在线任务放入独立优先级队列支持立即抢占6.1 优先级死锁的典型案例举一个非常典型的死锁场景作业 A 的训练阶段依赖 rollout 生产的数据但 rollout 的资源配额被作业 B 的评估任务占用了作业 B 的评估任务又需要作业 A 的训练产出一个 checkpoint……这样一来就形成了一个资源依赖环无论调度器怎么调配总有一个阶段在饿肚子。排查这类问题核心是必须画出阶段之间的资源依赖和数据依赖图谱然后给关键路径上的阶段设置更高的不可抢占维度。我一般会做一个规则如果某个阶段的停滞会导致整条流水线停摆那它在调度器里就应该被标记为“核心阶段”不能被普通任务抢占。6.2 资源悬挂问题资源悬挂是分布式调度里特别隐蔽的一个问题某个阶段因为异常退出但它申请的资源没有被正确释放调度器认为该阶段还在运行于是这些资源就变成了“幽灵资源”。解决方法是定期做资源对账。调度器周期性地向物理资源层查询某个阶段的资源占用情况跟逻辑层的记录进行比对发现不一致就强制回收。这个机制虽然朴素但在长时期运行中能避免大量资源浪费。6.3 调度器的可观测性真的建议所有做调度系统的团队把可观测性当成第一优先级来做。不要只看 CPU 利用率这类基础设施指标你得让每个阶段的决策记录都留痕为什么扩容、为什么缩容、为什么抢占了这个任务、被抢占的任务当前在什么状态。后训练调度里很多问题都不是突发的而是长期积累的只靠看实时曲线很难定位根因。我甚至会把调度器每次决策的理由以结构化日志输出到数据仓库里当业务方反馈某个任务变慢时直接查调度日志就能还原当时发生了什么。这个投入产出比非常高。6.4 调度器性能本身如果一个集群规模达到几千张卡调度器本身可能成为瓶颈。每次状态变更都触发一次全量重调度计算开销会非常可观。Weave 这类系统采用分层调度本身就有助于缓解性能压力——逻辑层和物理层各自处理自己范围内的问题不需要一个中心节点掌握所有的全局信息。想把它做得更稳建议多采用增量调度而不是全量重排。只有事件发生时比如阶段状态变更、节点故障、扩缩容请求才触发局部调整尽量不要做周期性的全集群重规划。这样能大幅降低调度器的 CPU 开销和决策延迟。7. 一点个人体会回到 Weave 这个名字我觉得它传递了一个很有意思的视角后训练系统不只是一堆模型训练程序的简单拼装而是一块需要被精细编织起来的织物。调度器就是那根穿针引线的梭子它不是配角而是决定整个 fabric 强度和质感的核心。对于正在跟进 OSDI26 论文的同学我建议读 Weave 时重点抓住两个主线一是它如何用阶段级抽象重新定义了后训练的调度粒度二是它如何用分层架构把“训练状态感知”和“物理资源分配”解耦开来。你自己规划后训练平台时哪怕不直接抄它这两个设计思想也值得深入消化。如果你现在已经开始在跑 agentic RL 的 workload或者正准备从预训练转后训练调度切换是一个很重要的决策点。与其继续背着传统作业调度器过日子不如趁早把阶段级协同调度的理念引入到你的平台设计中。等到 workload 真的大规模跑起来你会感激当初提前做对了这件事。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。