
做Agent应用开发的人十有八九动过蒸馏的念头把大模型的能力迁移到小模型上省token、省延迟。单轮问答场景里这条路已经被验证过很多次。但一旦进入多轮Agent我发现同一套蒸馏流程会越跑越不对劲——训练日志上的loss还在下降回放环境里的成功率却开始回头下跌继续蒸下去甚至比一开始的基线还差。不管你是用LangChain、Dify、CrewAI这类现成框架还是自己搭了一套agent harness和编排层只要把训练目标切到教师的软标签上多轮场景里几乎都会碰见这个现象。这个现象背后藏着一个经常被忽略的技术问题agentic OPD在线策略蒸馏在长周期决策中的失效。这篇文章就把这个问题拆开讲清楚。我会先解释OPD到底是什么、它和普通蒸馏有什么区别再剖析多轮Agent越蒸馏越差的三个核心机制然后用一次完整的复现实验展示定位问题的排查链路最后给出我在工程里验证过的几个止血方案。1. 从单轮蒸馏到agentic OPD看起来顺理成章实际跨了一条鸿沟1.1 单轮任务里蒸馏这条路一直被验证得很顺单轮任务比如给一段文本分类、根据用户输入生成一条固定格式的回复蒸馏的流程非常简单用一个能力强的大模型在静态数据集上生成软标签再用小模型去拟合这些软标签。静态数据集意味着输入分布是固定的teacher模型在这个分布上通常有足够覆盖和较高的准确率所以teacher给出的标签是可靠的。Student只要老老实实拟合就会一步步逼近teacher的能力很少出现越学越差。我当时也理所当然地认为多轮Agent不过是一串单轮任务的拼接蒸馏无非是把单轮变成逐轮蒸馏。结果现实给了我一记重拳。多轮任务根本不是单轮的叠加那么简单它在状态空间的结构和因果链上和单轮任务完全不是一回事。单轮任务里student怎么输出都不会改变下一道题的输入分布。你这一轮答错了下一轮用户还是会照常提出新问题teacher面对的输入还是那些熟悉的分布。但多轮Agent中student的每一步动作都会改变环境状态对话历史会累积工具调用的返回值会变化下一轮Agent看到的状态完全是上一轮自己行为的函数。这个本质差异是所有后续问题的源头。1.2 OPD的初衷与多轮Agent带来的新变量先解释一下OPD。On-Policy Distillation在线策略蒸馏它和传统离线蒸馏最大的区别在于训练轨迹不是从一份固定的数据集里拿而是由student模型自己当前策略在环境中实时交互采集然后由teacher对这批轨迹上的状态产出软标签student再拟合这些标签。设计初衷很朴素student部署的时候就是靠自己的策略交互那训练时就应该在自己会看到的状态上学习而不是在一堆teacher风格的数据上学习。这个逻辑在单轮任务上基本成立因为输入分布和student的输出无关不管student怎么答下一道题还是那个分布teacher对它的判断始终靠谱。但多轮Agent直接把输入分布变成了一个会随student行为改变的东西。这还不是全部多轮Agent还引入另外两个新变量状态空间是组合爆炸式的对话历史和工具返回值的组合几乎没法提前穷举同时奖励是回合级的中间步骤没有天然的单步监督信号。这两个变量加上前面说的输入分布可变共同把OPD推入了一个它并不安全的区域。OPD原本想解决的是student部署时的分布与训练分布不一致的问题但它有一个隐含前提teacher必须能够覆盖student整个可达状态空间。单轮任务满足这个前提多轮Agent不满足。一旦student探索到teacher覆盖之外的区域整条链就开始失控。2. 为什么多轮Agent会越蒸馏越差三个相互纠缠的机制2.1 机制一协变量漂移——student的行动改写了teacher的考题协变量漂移这个词听着拗口换成生活里的说法就是老师准备了一肚子教案结果学生把课堂带到了老师没备过课的地方。在模仿学习框架下teacher产生的训练轨迹服从teacher策略诱导的状态分布。如果全程都用teacher的轨迹来教studentstudent学到的是teacher在teacher自己的状态下会怎么做。问题是student部署后用的是自己的策略两个策略哪怕只有很小的动作差异经过几轮环境反馈后student访问到的状态分布也会和teacher显著不同。OPD就是为这个问题而生的它让student在自己策略诱导的状态分布上学习。但OPD只解决了student该在哪里学的问题却没有解决teacher在这些地方是否会教的问题。多轮Agent的状态空间是组合式的student一旦在某一步偏离主流路径比如工具调用顺序颠倒、输出了一个格式错误的参数、在错误上下文里追问用户环境就会进入一个在teacher训练数据中几乎不存在的异常分支。teacher在这个分支上的输出不再代表标准答案只能算是硬着头皮给一个看似合理的建议。我在实际项目里观察这个现象时最直接的证据是状态重合率的快速下滑。我统计过student轨迹和teacher轨迹在关键状态上的Jaccard重合度训练前三轮还在0.6左右到第六轮就跌到0.3以下。这意味着student主要学习的那些状态已经有一大半不是teacher的本行了。一个很典型的情况是旅行预订场景里student在查询航班后过早选择了一个低价但需要中转的选项环境进入一个已经带着错误预定信息继续对话的上下文teacher在这个复杂上下文里给出的推荐基本可以判定为编造。2.2 机制二单步模仿与回合目标脱钩误差开始滚雪球如果说协变量漂移解释了teacher教的东西不靠谱那误差累积解释了即便teacher每步都教得不错学生也可能在长链条里逐步滑向失败。蒸馏的loss设计得非常朴素student在状态s上的输出分布去拟合teacher在状态s上的输出分布。它优化的是当前这一步和teacher像不像不是一个回合能不能成功。这在单轮任务里没问题因为单轮任务的输出就是最终目标但在多轮Agent里任务成功与否取决于整条轨迹中间任何一步的微小偏差都会被环境逐轮放大。可以算一笔账。假设student每步动作与teacher完全一致的概率是1-ε一个需要N轮交互的任务理想情况下成功率的下界是(1-ε)^N。这个公式很残酷ε0.05时5轮任务成功率还有77%10轮任务就只剩60%一旦ε因为蒸馏过程被带到0.1010轮任务的成功率直接掉到35%。这还没考虑偏差的方向性问题——如果student的偏差不是随机噪声而是系统性往某个错误方向走损失会更严重。这类问题在做序列生成的人那里有个熟悉的名字exposure bias暴露偏差。训练时用的是teacher forcing每一步都用标准答案作为下一步输入部署时用的是自回归生成错误会被自己当作输入继续放大。多轮Agent本质上也带着这个毛病只是环境反馈让状态空间的放大效应比普通文本生成更猛烈。更麻烦的是多轮Agent的信用分配是滞后的。中间状态的好坏必须等回合结束才能知道而蒸馏在中间状态下提供的软标签完全没有回合级信息。于是loss可以和成功率脱钩student在错误分支上越是熟练地模仿teacher的临场发挥单步KL下降得越漂亮任务成功率反而一路下滑。我在实验日志里见过最刺眼的一幕就是loss创新低的那天正好是成功率创了新低。2.3 机制三置信度回声——teacher在OOD状态上的伪标签越带越偏前两个机制叠加起来已经很麻烦但还有个更隐蔽的放大器softmax过自信。teacher模型在训练数据分布内时它的输出分布是可靠的置信度和正确率大致相关。可一旦进入OOD状态teacher并没有能力承认自己不知道。softmax无论输入多离谱都会输出一个概率分布而且这个分布经常是低熵的——也就是看起来信心满满。我实测过很多场景teacher在完全不熟悉的状态上给出的置信度甚至能接近0.8。它不是真的会只是结构上不允许自己说不会。多轮Agent的状态空间组合爆炸teacher在无数个OOD分支上的输出几乎就是编造但它会用很高的置信度把这个编造的答案递给学生。这就形成一个噩梦般的正反馈循环第一轮student在某一步出现偏差teacher在偏差状态上给了一个自信但不靠谱的软标签。student学了这个标签进一步偏离。第二轮student更容易进入这种偏差状态teacher继续用不靠谱的高置信度标签回应student对这些状态越来越熟练。这就是我所说的置信度回声——teacher说过一次错话被student放大后teacher在下一轮还会在类似状态继续说错话而且越来越坚定。这个机制在长回合、多工具调用的Agent场景里尤其明显。回合越长中间步骤越多student探索到OOD分支的概率越大工具状态越复杂teacher见过的组合越少编造的空间就越大。如果你的Agent动辄需要10轮以上的对话才能完成任务同时还要调用多个外部工具那几乎必然会踩中这个循环。3. 一次真实复现实验的完整排查链路loss在降、成功率却在跌理论讲完还是要落到实证上。我把这个现象放在一个受控实验中完整复现了一遍这里记录完整的排查链路给大家一个可以直接抄的定位方法。3.1 实验配置与指标设计环境我用的是一个简化的旅行预订工具调用任务。Agent需要完成读取用户需求、查询航班、选择航班、查询酒店、确认订单、提交支付表单整个过程大概6到10轮对话中间穿插3到4个工具调用。环境内置规则比如价格不能超过预算、日期不能冲突最终订票成功且不违反规则才算回合成功。Teacher是一个较大的对话模型Student是一个参数量小很多的模型。蒸馏方式采用标准OPD每轮让student在环境中跑32条轨迹再让teacher对轨迹上的每个状态生成软标签用KL散度更新student一共迭代10轮。我同时记录了四个指标蒸馏KL loss、回合成功率、student轨迹与teacher关键状态分布的Jaccard重合率、teacher在student轨迹状态上的平均置信度。前两个是常规监控指标后两个是为了定位分布漂移单独加的探针。3.2 现象记录第4轮之后出现loss与成功率脱钩结果非常典型数据贴在下面迭代轮次KL loss回合成功率状态重合率 Jaccardteacher平均置信度第1轮2.3131%0.620.81第2轮1.8743%0.600.79第3轮1.5252%0.580.77第4轮1.2851%0.490.66第5轮1.0943%0.380.58第6轮0.9436%0.320.54第8轮0.8134%0.270.50第10轮0.7633%0.250.48前三轮一切都好loss下降成功率上升重合率和置信度都在高位。从第4轮开始loss还在继续降但成功率调头向下。到第6轮以后成功率稳定在33%左右恰好比最开始的基线31%只高一点点等于白折腾。3.3 逐层排疑从优化器到分布最终锁定teacher的OOD软标签看到这个结果我的第一反应是怀疑训练过程出了问题做了一轮常规排查。先排除过拟合student在验证集上的loss一直在同步下降没有出现训练集下降、验证集回升的分叉过拟合不成立。再排除超参数我换了一组更保守的学习率和batch size重跑现象完全复现优化器背不了锅。最后排除环境随机性固定随机种子跑三遍曲线几乎一致说明这不是运气问题。确认稳定复现之后我开始用那两支探针定位。状态重合率从第3轮的0.58一路跌到第10轮的0.25teacher平均置信度从0.77跌到0.48两项指标和成功率下降高度同步。接着我对student轨迹做了降维可视化结果很直观成功轨迹集中在几个主流簇失败轨迹散落在边缘小簇从第4轮开始student产生的轨迹越来越多进入边缘小簇而这些小簇恰恰是teacher置信度最低的区域。我在置信度最低的几个小簇里采样了若干状态用人工检查teacher的软标签质量发现了明显的编造现象虚构工具返回结果、生成不存在的确认编号、在规则冲突时强行给出承诺。这些状态在teacher训练数据里几乎不可能出现teacher只是在硬编。到这里根因已经锁定不是蒸馏没效果而是student在探索过程中把轨迹推进了teacher覆盖范围之外的OOD状态teacher在这些状态上给了大量高置信度的错误软标签student越学越偏。为了验证这个结论我加了一组对照实验每一轮改用teacher策略在环境中rollout的轨迹去蒸馏studentstudent自己不再产生训练轨迹。结果成功率一路涨到58%状态重合率也回升了。这说明问题的根源确实在student自采样的轨迹分布而不是蒸馏算法本身。4. 工程侧如何止血四个经过验证的缓解策略定位到根因之后接下来就是怎么止血。下面这四个策略我都实际跑过单独用有效果组合用更稳。4.1 黄金轨迹回放把teacher的脚印混进student的训练最简单的思路是不让student完全沉浸在自己的错误轨迹里。在训练batch中混入由teacher策略提前生成的黄金轨迹相当于给小马配了一批老马走过的路让它知道自己选的偏离路不是唯一的路。具体实现上维护一个固定大小的轨迹缓冲池比如1000条teacher产生的完整轨迹按回合奖励排序。训练时从缓冲池和student实时轨迹中按比例抽样我实践下来前期teacher轨迹占比可以到50%甚至70%随着student能力提升逐渐衰减到20%左右。这样既保留了OPD在student分布上学习的长处又不会让student彻底失去对标准分布的感知。有一点要提醒黄金轨迹不要只放成功轨迹最好也放一部分中低质量的轨迹。如果buffer里全是满分轨迹student会学到一个很窄的输出分布一旦上线遇到稍微偏一点的状态就懵。保持一定的轨迹多样性比追求buffer整体质量更重要。4.2 置信度门控让teacher在没把握时闭嘴既然问题出在teacher的OOD软标签不可靠那最直接的做法就是让teacher在没把握的时候不发言。实现起来非常轻量student每到一个状态先让teacher输出软标签同时记录最大概率值只有当置信度超过预设阈值时才把该状态计入蒸馏loss。def compute_distill_loss(state, student, teacher, threshold0.7): teacher_probs teacher.predict(state) confidence teacher_probs.max() if confidence threshold: return 0.0 student_logits student.predict(state) return kl_divergence(student_logits, teacher_probs)阈值的选择有点讲究。0.9太严会丢掉大量本来有效的学习信号0.5太松OOD状态下常见的0.5到0.6置信度照样混进训练。我在不同数据集上试下来0.7到0.75通常是一个不错的区间。实际操作时可以先统计一下teacher在正常轨迹上的置信度分布再选择能保留80%正常状态的那个分位数作为阈值。还有一个细节被过滤掉的OOD状态不要直接什么都不做可以用环境规则或简单验证器给一个基础标签或者干脆标记为无效样本。我在旅行预订实验里对低置信度状态直接跳过成功率的回退幅度立刻减小。4.3 温度软化与策略正则防止student被误导性软标签带崩置信度门控是在样本维度上筛数据温度软化和策略正则是在优化目标维度上降低坏标签的破坏力。先看温度。teacher输出的分布经过温度T缩放后再作为软标签T越大分布越平坦。平坦的分布意味着teacher其实也没那么肯定student从中学到的就不是一个武断的错误答案而是一个带不确定性的参考。实践里T取2.0到3.0比较合适太大会让标签过于平均失去指导意义。再看策略正则。在蒸馏loss之外再加一项student当前输出与上一轮自身策略的KL散度防止单次更新被个别坏标签推得太远。完整loss的形式是loss KL(student_logits || teacher_soft_labels_T) λ * KL(student_logits || student_previous_logits)其中λ一般取0.1到0.5等于给每次更新加了一个不要突变得太离谱的限制。这个正则本身不直接解决OOD问题但它能削弱坏标签单次生效的伤害给前面的过滤机制留出误差缓冲。4.4 回合级奖励筛选把模仿绑定到做得对前几个策略都是状态级或者优化级的手段最后一个更粗暴也往往更有效用回合级的真实反馈来筛选训练轨迹。Agent环境通常有内置规则或延迟奖励可以在每轮OPD结束后对整条轨迹打个分比如是否成功完成预订、是否违反预算规则然后只保留得分靠前的轨迹进入蒸馏。这样做的好处是即使teacher在某些状态上给错了软标签只要整条轨迹最终成功了说明大多数指导大概率是对的坏标签只占少数student学了不至于跑偏。反过来整条轨迹都失败了即使里面某几步teacher软标签看着很合理也可能是带偏路上的合理还不如不学。回合级筛选的实现成本通常很低。很多Agent环境里本身就有验证器不需要额外训练奖励模型。我在实验里发现光是加入这一层筛选成功率就能稳定回升10个点以上是四件套里性价比最高的一个。4.5 怎么组合使用针对不同团队和环境的条件我给一张按资源量排序的推荐表资源/约束推荐配置理由环境反馈便宜能拿到回合级结果回合级奖励筛选 黄金轨迹回放最少训练改造效果最直接只有teacher和student没有环境规则置信度门控 温度软化纯离线侧控制不依赖环境项目有条件做反复调参四件套全上稳定性最高但需要多花时间观察曲线token预算紧张teacher调用有限置信度门控 黄金轨迹回放少量用最少的teacher调用保住主流分布我在旅行预订实验里最终用的是四件套组合跑完10轮OPD成功率从33%回升到了54%虽然还没到teacher全量rollout对照组的58%但已经很接近而且student的推理开销远低于teacher。如果你没有那么多调参的时间我建议先上一套回合级筛选 置信度门控多数项目到这一步就已经能止住下跌了。最后再分享一点个人的体会。遇到多轮Agent越蒸馏越差很多人第一反应是换模型、调超参数、加数据但真正的问题往往是训练分布被student自己改写teacher在OOD状态上给出了不可靠的软标签然后这个错误又被蒸馏过程本身放大。与其盲目增大训练量不如花时间把分布探针加进去状态重合率、teacher置信度、成功率这三根曲线能帮你很快判断是否掉进了这个坑。多轮Agent的蒸馏不是把单轮蒸馏跑几轮那么简单它本质上是一个需要同时控制数据分布和数据质量的学习过程。谁在这一点上偷懒迟早会在部署环境里还回来。