首页 / 资讯中心 / 文章详情

Rollback课程学习机制:让多轮Agent在错误级联时学会主动回滚

Rollback课程学习机制:让多轮Agent在错误级联时学会主动回滚 ★ FEATURED ARTICLE
我们团队半年前在一次版本演示上翻过车。一个看似普通的多轮交互 Agentic 任务——用户连续提了几个需求中间夹了一次工具调用Agent 在第二个请求上理解错了意图然后带着这个错误一路执行到底输出了一份完全不可用的结果。更郁闷的是模型全程显得特别“自信”每一步都逻辑自洽就是地基从第二步开始就歪了。这类场景做 Agent 的朋友应该都不陌生。当时我们把问题归到工程层面试了各种兜底规则效果都不理想后来转向训练层面折腾出了一个叫“Rollback 课程学习机制”的方案——简单说就是在训练阶段显式教会模型在中间步骤出错时主动回退、重新规划。这篇文章就把这套机制从问题拆解、方案设计、数据构造到训练排查完整梳理一遍给正在做多轮 Agent 训练与落地的朋友做个参考。1. 问题拆解多轮 Agent 为何总是“一步错步步错”1.1 一个典型的“错误级联”现场先还原一下当时我们内部构建的一个演示场景。任务本身不复杂某电商客服系统接到用户提问用户先问“我的订单到哪了”Agent 调用物流查询接口拿到正常结果随后用户追问“那这个订单能改地址吗”Agent 需要先校验订单状态、再判断是否允许修改最后调用修改接口。问题就出在第二步模型把“改地址”理解成了“退换货”于是后续所有工具调用、话术生成全都围绕退换货展开。用户每追问一次错误就被放大一次到最后模型甚至“编”出了一套根本不存在的退换货流程。这在多轮 Agent 场景里有个专门的说法错误级联error cascade。它不是单个步骤的错误而是错误沿着对话轮次和工具调用链不断累积、放大。我们在复盘时统计了内部测试集里的失败轨迹发现有将近四成的失败案例不是“模型不会做”而是“中间某一步做错了但模型坚持把后面的路走完”。1.2 为什么模型不会主动“回头”从训练目标层面看语言模型被训练成“在给定上文的前提下续写最可能的下文”。一旦上文里包含了错误的中间状态模型的下文生成就会沿着错误上下文继续前进。它没有机制去质疑“我前面是不是错了”因为没有哪一种训练目标会显式地奖励“回头”这个行为。从数据层面看常规的指令微调和偏好对齐数据里几乎不会包含“先做错、再纠正、继续完成任务”的正样本。我们翻了内部积累的 SFT 数据干净轨迹占了绝大多数少量失败轨迹在训练时还会被当作负例过滤掉。换句话说模型在训练阶段根本没有见过“犯错之后还能补救”的示范自然也就学不会这个动作。从评测层面看常见的端到端成功率评测只关心最终结果对不对中间步骤的错误被平均值稀释了。模型拿到的反馈是“最终成功”或“最终失败”它无法从这种粗粒度信号里定位到具体哪一步需要修正。三个因素叠加在一起就成了我们熟悉的画面Agent 每一步都自信满满最后交出一份离谱的答案。1.3 常规补救方案为什么不够最初我们想走工程路线写一堆兜底规则检测工具调用失败、检测参数异常、检测用户情绪变化等等。试了一个月规则越写越多覆盖面却始终跟不上。多轮交互的语义错误比如理解错意图、选错分支根本没法靠规则穷举硬写只会让系统变成一个不断打补丁的“屎山”。后来也试过让模型做“自我反思”就是在生成之后追加一轮批判性提示让模型自己检查有没有问题。结果在部分单轮问答场景有效但放到多轮工具调用链上就不太靠谱了。模型往往嘴上承认“我错了”实际行为还是沿着原来的错误路径走属于典型的“语言上认错、行动上不改”。还有人可能会想到推理时搜索比如在多个候选分支里做 beam search 或者树搜索。这种方法效果确实好但代价是推理计算量成倍上涨在线场景根本扛不住。我们当时的判断是既然工程规则和推理时方案都有天花板那就回到训练阶段让“回滚”本身成为一个模型内建的能力。2. 方案设计Rollback 课程学习机制是怎么工作的2.1 核心思路把“回退”变成可学习的动作Rollback 课程学习机制首先要回答一个问题到底怎么让模型学会“回头”我们的做法是在训练阶段扩展 Agent 的动作空间。原本模型在每一轮可以输出的动作包括调用某个工具、生成回复文本、结束任务。在这套机制里我们额外增加了一个显式动作回滚rollback。当模型生成这个动作时它需要同时输出一个“回退目标”指明要回到之前的哪一个状态点——可以是某一次对话轮次也可以是某一次工具调用之前然后从那个状态重新开始规划。为什么要用“显式动作”而不是靠自然语言让模型自我纠正这里有个关键区别自然语言纠正只是改变了表达不改变模型内部的信念状态而显式回滚动作会真正触发状态重置把对话历史与工具执行记录恢复到指定位置。打个比方前者是司机嘴里念叨“我开错路了”后者是司机真的打方向盘掉头。为了让“回滚”能被训练出来我们借鉴了课程学习Curriculum Learning的思路。课程学习的核心思想很简单给模型安排一条由易到难的学习路径。我们把这个思想用在了回滚训练上先教模型在最简单场景下学会回滚再逐步增加回滚的复杂度最后让模型在真实的多轮交互环境中自主判断何时回滚、回滚到哪里。2.2 三级课程的内容安排我们把课程拆成了三个级别每一级对应一种回滚难度。级别训练内容核心目标典型示例Level 1单步回滚学会“错一步退一步”第 2 步调错工具在第 3 步检测到错误回滚到第 2 步之前重新调用正确工具Level 2多步连续回滚学会“连续错两步都退回去”第 2 步理解错意图第 3 步调用了错误接口第 4 步回滚到第 1 步重新规划Level 3分支重选学会在多个可能路径中识别错误分支并切换第 2 步选了 A 分支执行到第 4 步发现 A 分支走不通回滚并切换 B 分支完成目标Level 1 的关键是“错误位置明确、回滚距离固定”。数据里会显式标注错误的步骤模型只需要学会“检测到错误信号就回退一步”。这个级别的任务是建立回滚动作的基本语义。Level 2 的关键是“连续错误”。模型不能只回退一步就完事它需要判断错误的起点在更早的位置一口气退到正确状态再重来。这个级别考验的是模型对整条轨迹的“因果归因”能力。Level 3 的关键是“分支切换”。此时错误不再是简单的“某一步做错”而是整条分支方向就错了。模型需要对比当前分支和备选分支的结果判断是否要放弃当前分支并且知道切到哪一条分支上去。2.3 为什么选课程学习而不是一次性混合训练一开始也有人提过为什么不把三个级别的数据混在一起让模型一起学我们后来意识到混合训练最大的问题是会把“回滚”变成一把乱挥的锤子。如果训练集里既有 Level 1 的简单回滚又有 Level 3 的复杂分支重选模型很容易把“频繁回滚”当成一种万能策略。因为回滚动作在训练早期就很容易拿到正奖励——它总是比“继续沿错误路径走”要好。模型会很快发现这个捷径然后不管三七二十一见到任何不确定信号就先回滚再说。这不是我们要的行为。课程学习的好处在于它给了模型一条清晰的能力发展路径先在低难度课程里建立“回滚动作是有效手段”的认知再在中等难度里学会“回滚需要准确选择目标位置”最后在高难度里掌握“什么时候该回滚、什么时候不该回滚”的判断力。这个顺序很像人学开车先学直线再学倒车最后才学复杂路况下的灵活变道。跳级学习也许能快但稳定性差后面需要花更多时间去修正模型学到的坏习惯。3. 实操落地训练数据构造与奖励设计的关键细节3.1 轨迹数据的拆分与重构数据是我们踩坑最多的地方。光有想法没有数据一切白搭。我们用的数据来源主要有两个一是从真实交互日志里筛出的完整轨迹二是基于模拟环境人工合成的轨迹。两类数据都要经过同一个处理流程拆分、注入干扰、生成回滚标签。具体做法是先从日志里抽出成功的完整轨迹然后随机选择轨迹中的某个位置注入不同类型的错误再让标注人员或者另一个更强的模型生成一段修复轨迹。修复轨迹的特征是先走到某个位置时产生回滚动作回滚到错误起点之前再重新执行剩余步骤完成目标。在数据格式上我们定义了一套结构化的回滚标注方便训练时直接使用。{ task_id: 099x, trace: [ {turn: 1, action: user_query, content: 查询订单状态}, {turn: 2, action: call_tool, content: get_order_status}, {turn: 3, action: call_tool, content: update_address_wrong}, {turn: 4, action: rollback, target: 2, reason: wrong_intent} ], rollback_type: wrong_intent, error_step: 3, rollback_step: 4, rollback_target: 2, restored_success: true }这个字段设计是我们反复调过的。一开始只记录了“有没有回滚”训练出来的模型知道要回滚但不清楚要退到哪一步经常退不到点上。后来加了rollback_target字段模型的任务变得更具体不仅要输出回滚动作还要输出回退位置的索引。效果立刻有了明显提升。数据构造上还有几个注意点。错误类型要覆盖常见的几类意图误解把 A 需求理解成 B 需求、工具调用失败接口报错、超时、参数错误传错订单号、传错日期范围、上下文遗忘忽略了前几轮已经确认过的信息。只覆盖单一错误类型会导致模型的回滚能力迁移性很差换个新场景就不工作了。3.2 奖励塑造怎么让模型“愿意”回滚训练这套机制我们用了策略梯度类的强化学习框架内部实验用的是 PPO奖励设计是整个方案的心脏。奖励如果给不对模型学到的东西会完全跑偏。我们的奖励函数由三部分构成r_total 恒定向导奖励 回滚行为奖励 任务终止奖励基础导向奖励r_step每完成一个有效步骤给 0.1 分。这个奖励让模型保持“继续推进任务”的倾向而不是呆在原地不动。回滚行为奖励r_rollback当模型正确识别出当前轨迹需要回滚时给 1.0 分当回滚到的目标位置恰好是错误起点之前时额外给 0.5 分。这个部分是最关键的它直接定义了我们“想要”的行为。注意这里有两个维度一是“要不要回滚”的判断二是“回滚到哪”的准确性。任务终止奖励r_terminal最终任务成功给 5.0 分失败给 -2.0 分。任务成功奖励要足够大否则模型会觉得“反正回滚也能拿分最终目标完不完成无所谓”。我拿一个具体例子算一下奖励。假设一条轨迹一共 5 步第 1 步用户提问第 2 步模型意图理解错误第 3 步走了一步错误路径第 4 步模型检测到问题并回滚到第 1 步第 5 步重新执行正确路径并最终完成任务。奖励计算过程基础导向奖励有效步骤是 1、3、5 这 3 步但第 3 步是错误步骤我们只给第 1 步和第 5 步计分共 0.2如果设计得更严格错误步骤还可以倒扣。回滚行为奖励第 4 步正确触发回滚给 1.0回滚目标位置第 1 步正确额外给 0.5。任务终止奖励最终成功给 5.0。合计0.2 1.0 0.5 5.0 6.7 分。这个数字不是随便定的。我们后来为了压“过度回滚”专门把回滚行为奖励从 1.0 降到了 0.3再把“没有错误时不要回滚”做成隐式惩罚这部分会在后面的踩坑章节详说。3.3 回滚粒度的选择退到“哪一轮”比“要不要退”更难回滚机制里最有意思的问题是回滚的粒度。所谓“回滚”到底是回到哪一层是回到之前的对话轮次还是回到某一次工具调用之前还是干脆把整个对话历史重置我们实验了三种粒度。最粗糙的是“整段回滚”即回到任务起点重新开始。这种方案实现简单但代价是丢掉所有已完成的有效信息。比如说用户已经确认了收货地址模型因为一次工具调用失败就整段重来用户肯定要疯。中间粒度是“按轮次回滚”回到某一轮对话之前的全部状态。这种粒度比较好训练因为对话轮次是天然的分隔边界。但它处理不了“同一轮内意图理解就错了”的情况。我们最终采用的是“按动作索引回滚”把对话历史和工具调用记录统一编号模型输出回滚时指定action_index状态管理模块把数据恢复到该动作执行之前。这个粒度最灵活也最难学——模型需要知道“错误发生在哪一步”这本质上是在训练一种定位能力。实际训练中头几个 epoch 模型经常把回滚目标定位到错误步骤本身而不是错误之前的位置。我们加了一个小技巧在标注数据里把rollback_target统一转换成“错误动作的前一个动作索引”让目标注释口径一致。如果错误发生在 action 3回滚目标就是 action 2 完成后的状态。这个细节看似很小但统一口径之后模型的学习难度明显下降定位准确率提升很快。4. 实验配置训练流程、超参数与课程调度策略4.1 三阶段训练流程整套训练流程我们分成了三个阶段。第一阶段是监督微调SFT。在拼接了回滚轨迹标注的数据集上让模型先学会基本的行为模式看到错误痕迹就输出回滚动作、指定回退目标、重新规划。这个阶段不追求模型有多强的泛化能力只求它“知行合一”能够在分布内的样本里稳定复现回滚动作。第二阶段是强化学习微调RL。我们用策略梯度方法在回滚数据上继续训练重点是优化奖励信号。这个阶段模型开始学会权衡什么情况下回滚是值得的什么情况下继续推进更有利。第三阶段是课程调度。把三级课程的数据按顺序送进训练管道每一级课程内部单独设置一个评估集只有当当前级别的成功率稳定超过某个阈值时才把下一级别的数据加进来。整个流程看起来不复杂但每一步之间都有紧耦合。比如 SFT 阶段如果做得不够扎实模型没有学会输出结构化的回滚动作RL 阶段就无从谈起。我们第一次训练时 SFT 只跑了 2 个 epoch 就急着进入 RL结果模型在动作格式上频频出错RL 阶段的大部分时间都在纠正格式问题效率惨不忍睹。4.2 模型选型与关键超参数实验用的基座模型是一个 7B 参数规模的开源基座模型。选它的原因很现实我们当时的 GPU 资源有限7B 在单机多卡环境下可以做较快的迭代验证。一开始也有人建议直接用更大的模型但我们判断这套机制的核心价值在训练方法而非模型规模用小模型跑通方法论、验证数据构造和奖励设计的合理性再考虑放大这样迭代成本低得多。超参数取值说明SFT 学习率2e-5偏保守避免破坏基座模型原有能力SFT epoch3在小型回滚数据集上不宜过量训练RL 学习率1e-6强化学习阶段更小防止灾难性遗忘PPO KL 系数0.05控制策略偏移幅度rollout 数量4096 条/训练步保证优势函数估计的方差可控GAE λ0.95平衡偏差与方差折扣因子 γ0.99多轮任务偏长需要较远的视野训练 batch size128按显存上限调整几个参数的取值逻辑说一下。RL 学习率定在 1e-6 是因为我们担心策略变化太大会把 SFT 阶段学到的回滚格式丢掉。KL 系数 0.05 是一个安全范围内的值太小则策略偏离参考策略过远容易不稳定太大会限制策略探索空间。rollout 数量 4096 是我们试了 1024 和 2048 之后调到 4096 的数量太小时优势估计的噪声太大训练曲线一直在抖动。4.3 课程难度切换的调度策略课程学习的关键在“什么时候把更难的数据加进来”。我们一开始用的是固定步数切换Level 1 训练 500 步不管效果如何直接切到 Level 2。结果不出意外地翻车了——Level 1 的成功率只有 60% 出头就升级Level 2 数据一进来模型直接招架不住整体指标反倒比单一级别还要差。后来改成了自适应调度每个级别维护一个 EMA 评估窗口只有当当前级别的成功率超过 80%并且连续三个评估批次没有出现明显下降才把下一级别的数据混合进来。而且不是一次性替换是逐步混合——新级别的数据占比每 50 步提升 10%给模型一个缓冲期。这个调度逻辑用伪代码写出来大概是这样if ema_success_rate(level) 0.8 and not declining(level, 3): if level 3: level 1 mixing_ratio 0.1 # 新级别数据从 10% 起步 else: wait_or_recover() if level 1: mixing_ratio min(0.5, mixing_ratio 0.1) # 逐步提升到 50% 封顶自适应调度的好处是让模型在每个级别上都“站稳”了再往前走。代价是训练时间变长有时候一个级别要卡很久。我们那会儿平均每个级别要卡一两周才能达到切换条件中间还有好几次成功率不升反降不得不回滚到之前的 checkpoint 重新爬坡。5. 踩坑记录训练过程中遇到的典型问题与排查方法5.1 问题一模型学会了“疯狂回滚”第一个大坑是模型学会了回滚技能之后开始过度使用它。具体表现是在完全正常的轨迹里模型也频繁触发回滚。我们统计过有一段时间训练出来的策略在简单任务上的回滚频率超过了 30%——也就是说每三条轨迹里就有一条含有多余的回滚动作。诊断下来根因在奖励设计。回滚行为奖励给得太高模型发现“回滚一下就能拿分”比“继续努力完成任务再拿分”来得轻松得多。这就好比一个学生学会了举手问问题结果每道题不管会不会都先举手再说。解决办法分两步一是把回滚行为奖励从 1.0 降到 0.3降低它对模型的诱惑力二是在奖励函数里加了一条隐式惩罚——如果模型在无错误轨迹中触发回滚在终止奖励里额外扣 0.5 分。两步做完回滚频率从 30% 降到了 8% 以下同时任务成功率重新回到上升轨道。5.2 问题二低难度课程过拟合第二个坑是 Level 1 上训练得很好一上 Level 2 就拉胯。前期训练时Level 1 数据集上的准确率很快就刷到了 95% 以上我们当时还挺高兴觉得模型已经学会了单步回滚。结果 Level 2 数据一混合进来Level 1 的准确率立刻掉到 85%Level 2 的成功率更是只有 30% 出头整个训练曲线呈“过山车”形状。问题的本质还是数据分布太单一。Level 1 数据里错误模式相对简单固定模型学到的是“看到类似的错误信号就回滚”的浅层匹配而不是“真正理解错误在哪儿”的深层能力。一旦错误模式变了样模型就完全不会玩。我们的解决方法是给 Level 1 数据注入干扰样本。具体做法是从 Level 2 和 Level 3 的数据里挑一些相对“简单”的样本打折混进 Level 1 的训练集比例大概控制在二成左右。同时在 Level 1 的评估环节除了原有的单步回滚场景还额外加了少量需要两步回滚的“彩蛋”样本用来监控模型有没有形成对回滚机制的真正理解。调整之后模型在 Level 2 上的表现明显更稳了。5.3 问题三训练过程不稳定loss 震荡、reward 尖峰第三个坑是训练稳定性的问题这个坑一度卡了我们将近两周。现象是loss 曲线在正常下降过程中突然出现周期性尖峰reward 也时不时冲到一个异常高的值然后迅速回落训练直接失去收敛趋势。我们按顺序排查了好几个因素。先怀疑是 reward scale 太大把终止奖励从 5.0 调到 2.0尖峰频率有所下降但没有完全解决。再怀疑 KL 系数不合适试着从 0.05 调到 0.02结果策略偏离参考模型太远又冒出新的不稳定。最后发现真正的问题出在 rollout 数量上——之前为了加速训练把 rollout 数量从 4096 降到了 2048导致优势估计的方差变大训练波动随之加剧。把 rollout 数量恢复回去之后尖峰基本消失训练曲线重新变得平滑。这个排查过程给我的教训是当训练出问题时先别急着调这个调那个按“奖励尺度 → KL 约束 → 数据采样量”的顺序一个个试每次只动一个变量才有可能定位到真正的病根。我们一开始同时动了三个参数结果根本分不清是哪个起的作用白白浪费了好几天时间。6. 效果观察三类任务上的提升与一个意外发现6.1 三类内部评测任务的结果机制跑通之后我们在内部评测集上对三个任务场景做了评估。评测集是从真实交互日志里抽出来、经过人工标注的轨迹每个任务各抽了 500 条覆盖了多种错误类型。任务场景基线成功率加入回滚机制后提升幅度多轮客服系统56.8%74.0%17.2 个百分点数据分析助手61.2%74.0%12.8 个百分点网页导航 Agent58.6%74.0%15.4 个百分点三个任务场景都有提升但提升的方式不太一样。多轮客服场景的提升主要来自“错误意图的及时发现”——模型在用户第二次追问时就能察觉理解偏了主动回滚到之前的意图确认轮次。数据分析助手的提升则更多来自“工具调用链上的回滚修复”——查询参数传错了模型会回滚到参数设置那一步重新构造查询。网页导航 Agent 的提升来自“分支路径的重新选择”——发现当前页面路径越走越偏时回退到较早的导航分支点。表格里的数据是在某个内部模拟项目 X 的评测集上测出来的绝对数值不一定有普适性但趋势上能说明套机制的可行性它不是在某个特定场景里偶然奏效而是跨场景稳定带来了正向收益。6.2 一个意外发现模型学会了“预测性回滚”评测过程中我们发现了一个有意思的现象部分成功轨迹里模型的回滚动作并不是发生在“错误已经被工具执行结果证实”之后而是发生在“错误刚刚露出苗头、还没有造成实际影响”的时候。举个例子在数据分析助手场景里用户要求统计“上个月”的销售数据模型在构造查询时把日期范围设成了上上个月。按常理这个错误要到工具返回结果后才能被发现。但训练后的模型在构造查询参数的那一刻就触发了回滚重新读取了一遍用户原话中的日期表述然后修正了参数再继续执行——整个过程看起来就像是模型产生了“预测性回滚”。这个现象背后的机制我们还没有完全搞清楚一个比较合理的推测是课程学习的多级难度训练让模型形成了对“哪一步容易出错”的敏感性。在 Level 2 和 Level 3 的训练里模型见过太多“错误前缀 回滚修复”的样例学会了在错误发生更早的阶段就识别出风险信号。这个发现让我们的思路打开了新的方向回滚机制不只能作为“错误修复工具”还可能作为“不确定性管理手段”——当模型对某个决策的置信度偏低时主动回滚到更早的确定性状态重新规划而不是等错误坐实之后再补救。现在团队正在沿着这个方向做一些初步实验目前看结果还挺有潜力的。如果让我总结这套机制最核心的价值我不会说它只是让 Agent 学会了“认错”。更准确的说法是它把人的直觉——走错路要及时折返——转化成了可训练、可度量的技能。这条路我们走了好几个月踩的坑比预想多但收获也超出预期。如果你们也在做多轮 Agent 产品我建议别一开始就在太大的模型上动手先用一个小模型把回滚的数据构造和奖励逻辑跑通再考虑规模放大。这套机制目前能处理的还主要是单智能体场景多智能体协作下的回滚问题涉及多个 Agent 之间的状态同步和信念修正会是一个更复杂的挑战。
阅读完成 · 觉得有帮助?
咨询建站