Step Rejection Fine-Tuning: Squeezing More Signal from Noisy Agent Trajectories

TL;DR · AI 摘要
Step Rejection Fine-Tuning (SRFT) 是一种新方法,通过保留失败轨迹中的有效步骤,提高大语言模型代理的训练效率。
核心要点
- SRFT 保留失败轨迹中的有效步骤,避免浪费高质量数据。
- SRFT 使用“critic”机制过滤有害步骤,提升模型性能。
- SRFT 在 DL4C 工作坊中被接受,适用于复杂任务训练。
结构提纲
按章节快速跳转。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- Step Rejection Fine-Tuning (SRFT)
- 传统方法的问题
- 丢弃失败轨迹
- 浪费高质量数据
- SRFT 的实现
- 保留有效步骤
- 使用 critic 过滤有害步骤
- 实验结果
- 提升模型性能
- 被 DL4C 接受
金句 / Highlights
值得收藏与分享的关键句。
在复杂任务中,代理失败频繁,但许多步骤仍可能是正确的。
SRFT 使用“critic”机制过滤有害步骤,避免模型学习坏习惯。
SRFT 在 DL4C 工作坊中被接受,适用于复杂任务训练。
步骤拒绝微调:从嘈杂的智能体轨迹中提取更多信息 - JetBrains 博客
JetBrains 研究
研究对于进步和创新至关重要,这也是为什么在 JetBrains,我们对科学和市场研究都充满热情。
关于 JetBrains 研究
研究
步骤拒绝微调:从嘈杂的智能体轨迹中提取更多信息
Igor Slinko
如果你想直接深入了解技术细节,可以在这里阅读我们的完整论文。
想象一下你正在指导一位初级开发人员。如果他们在 100 行脚本的第 42 行犯了一个逻辑错误,你会不会把整个文件扔掉并告诉他们他们什么都没学到?当然不会。你会指出具体的错误,并认可他们做对的地方。
然而,在训练大型语言模型(LLM)智能体时,标准做法却恰恰相反:如果最终结果不完美,我们就会选择丢弃整个尝试。在复杂任务中,智能体经常失败,这意味着我们一直在不断地丢弃大量潜在有价值的数据。为什么这些数据如此有价值?即使智能体未能解决任务,其中的许多步骤——例如探索目录结构、阅读相关文件和编写初始测试脚本——都是完全正确的。通过丢弃整个运行,我们丢弃了所有这些高质量的正确行为示例。
为了整顿这种低效,JetBrains 研究团队开发了步骤拒绝微调(SRFT)。这是一种简单实用的技术,可以帮助模型从失败的尝试中学习,而不会养成不良习惯。我们介绍这项工作的论文已被接受发表于 Deep Learning 4 Code(DL4C)研讨会,该研讨会将于今年七月在韩国与 ICML 同时举行。
在本文中,我们将:
- 解析传统的 LLM 智能体训练,并了解为什么标准方法会浪费数据。
- 揭示不成功轨迹中的隐藏价值。
- 介绍 SRFT,并解释它是如何使用“批评者”来屏蔽有害步骤的。
- 分享我们的实验结果,展示 SRFT 如何提升性能。
完美轨迹的问题
训练基于 LLM 的智能体主要有两种方法。第一种是强化学习,最常见的是使用 Group Relative Policy Optimization(GRPO)等算法实现。在这种方法中,模型通过试错学习。如果整个轨迹导致成功解决,它会收到奖励;如果失败,它会被惩罚。
第二种方法是从更强的教师模型中进行知识蒸馏。在这里,一个强大(通常昂贵)的模型生成解决方案,而一个较小的学生模型学习模仿其行为。在使用蒸馏方法时,标准做法是拒绝采样微调(RFT)。你从教师模型生成大量轨迹来解决任务,丢弃那些失败的轨迹,然后仅在成功的轨迹上训练你的学生模型。
为了让你有个大致概念,一条轨迹本质上是代理在解决问题时的完整对话历史。它由一系列步骤组成,代理在这些步骤中进行推理、采取行动(例如运行命令或编辑文件),并从环境中接收观察结果。在复杂的编码任务中,平均一条轨迹包含数十个这样的步骤。关键的是,我们通常只能在轨迹的最后阶段确定其是否成功,因为典型的轨迹以生成代码补丁作为结束。在标准基准测试中,会运行预先编写的测试套件,以验证这个最终的补丁是否解决了原始问题。因此,虽然我们可以对整个轨迹的成功与否获得完整、二元的反馈,但我们缺乏有关代理采取的具体步骤中哪些是有帮助的、哪些导致了错误补丁的测试级信息。
下面是一个逐步标记的轨迹在实际中的示例。在第三列中,SP 表示系统提示,UP 表示用户提示(包含问题描述),标有字母 A 和数字的行表示 AI 助手的步骤,而标有字母 O 和数字的行表示相应的输出。
在这个示例中,助手步骤 #3(A3)被标记为不必要的,因为代理查看了一个与问题描述中引入的错误无关的文件。步骤 #4(A4)被标记为错误,因为代理在重现错误之前就开始修复代码,这直接与系统提示(SP)中的指令相矛盾。此外,步骤 #7(A7)被标记为“恢复”,因为它纠正了代理在尝试重现错误时在步骤 #5(A5)中犯下的错误。我们选择不将步骤 #5 标记为错误,因为在该步骤中创建的复制脚本在其他方面是完全正确的,只有其中一行包含错误。
值得注意的是,这条特定的轨迹之所以成功,是因为它最终正确地解决了错误,尽管是通过一种次优的方式。虽然即使成功的轨迹并不总是完全没有错误,但不成功的轨迹总是包含一些有害的步骤,我们可能识别并将其标记为错误。
由于标准的 RFT(Reinforcement from Feedback)只使用成功的轨迹,它丢弃了大量数据。例如,最近的 SWE-Bench 项目生成了一个大规模的代理轨迹数据集,用于软件工程任务。该数据集随后被用来训练一个代理模型。由于他们使用了标准的 RFT,他们不得不丢弃大约 61% 的所有收集到的运行数据用于训练。这是一大笔潜在有信息的数据,仅仅因为最终结果不够完美就被丢弃了。
不成功轨迹的隐藏价值
我们的核心假设是,这些不成功的轨迹并非完全错误——相反,它们通常由正确的、有用的步骤组成,这些步骤中穿插着错误。
为了验证这一点,我们对 SWE-Bench 数据集中 20 条失败的轨迹进行了手动分析。
我们发现,即使在完全失败的运行中,最多只有 24% 的步骤实际上可以被归类为朝着错误方向发展。其余 76% 的步骤包括有成效的探索、代码库导航或无害的工具操作。
要理解这些未成功轨迹为何有价值,我们首先需要了解为什么蒸馏(RFT 是其中的标准实践)能够奏效。当我们使用教师模型的轨迹来训练学生模型时,性能的提升来源于两个不同的方面:
- 学习“聪明”的 token:学生从一个更加聪明、能力更强的模型中学习。它吸收了更优的推理方式、任务理解方式以及使用所提供工具的方法。
- 学习通向成功的路径:通过仅筛选成功轨迹(如标准 RFT 所做的那样),我们使模型倾向于选择那些确实能解决任务的动作。
如上所述,标准 RFT 会丢弃未成功的轨迹,因为它们缺乏第二个提升来源。换句话说,它们会教模型去模仿导致失败的错误。
那么,如果我们仅使用由强大教师模型生成的未成功轨迹进行训练,是否能提升模型的性能呢?
在回答这个问题之前,让我们先介绍我们的实验设置。为了简化,我们将在实验初步介绍之后,直接展示包含所有结果的完整表格,然后我们将逐步引导你了解每个实验,从回答这个问题开始。
我们在 SWE-bench Verified 上测试了我们的方法,这是一个具有挑战性的基准,它要求 AI 代理解决真实世界中的 GitHub 问题,涉及大型 Python 仓库。它全面测试了代理导航代码库、编辑文件和运行测试的能力。
在训练数据方面,我们使用了 SWE-smith 数据集中的轨迹,对 Qwen2.5-Coder-32B-Instruct 模型进行微调,所有实验均在 SWE-agent 架构上运行。为了过滤掉单次运行的随机噪声并确保结论的可靠性,我们对每个实验重复了七次。有关方法的更多细节,请参见我们的论文。
下表显示了我们实验的结果。训练数据列表示使用了 SWE-smith 数据集的哪一部分对模型进行微调;每个子集均来自 5,000 条已解决、未解决或未解决(掩码)轨迹的池,可以单独使用或组合使用。已解决列显示了在 500 个 SWE-bench Verified 任务中解决率的平均值,以及七次连续运行的标准差。实验按照这个主要指标的升序排列。因此,Δ vs. Prev. 列表示与上一行相比,主要指标的提升。
现在,让我们看看结果,以回答我们关于是否在未成功轨迹上训练确实有助于提升模型性能的问题。
结果表明,是的!由于第一个提升来源(学习“聪明”的 token),即使未成功的轨迹也能显著提升模型的性能!如上表所示,当仅使用未成功轨迹进行训练(实验 #2)时,解决率从基础模型的 7.0% 提升到了 27.7%。即使失败运行的最终补丁未能解决问题,学生仍然在学习如何使用像聪明教师那样的工具。
好的,我们使用仅未解决的轨迹达到了 27.7%。但我们还有已解决的轨迹可用。如果我们把它们也加入训练数据中,会发生什么呢?
如你在实验 #3(Naïve Distillation)中所见,仅仅将 5,000 条未解决的轨迹和 5,000 条已解决的轨迹合并,就能将解决率提升至 28.5%(仅提升了 0.8%)。虽然有小幅提升,但这种额外的收益非常有限。
现在来看实验 #5(RFT,即 Rejection-sampling Fine-Tuning),我们在该实验中仅使用 5,000 条已解决的轨迹对模型进行训练。该方法达到了 30.9%,优于与未解决轨迹混合训练的效果。这正是标准 RFT 的核心理念:你应当只使用成功且高质量的轨迹进行训练,丢弃那些不成功的轨迹,因为将失败的尝试重新加入训练数据实际上会降低模型的性能。
然而,我们显然可以看出,那些不成功的轨迹仍然蕴含着巨大的潜力。它们确实教会了模型一些有用的技能,如实验 #2 所示的显著提升所证明的那样。有没有办法从失败的运行中提取这些有价值的信息,同时避免引导模型去犯错误?
答案是肯定的!这正是实验 #6(SRFT)所要解决的问题。从表中可以看到,SRFT 的表现优于标准 RFT(32.2% 对比 30.9%),而它所依赖的技巧却异常简单。
Step Rejection Fine-Tuning(步骤拒绝微调)
那么,我们如何在不使模型学习到错误部分的前提下,提取失败尝试中的有用部分?
我们的解决方案是 Step Rejection Fine-Tuning(SRFT)。具体来说,我们使用另一个大型语言模型(LLM)作为“批评者”来逐步分析不成功的轨迹。批评者的任务是诊断每一步操作,并标记出哪些步骤实际上是有害的(例如引入了错误或走上了完全错误的路径),哪些步骤是有效的。
与最初生成代理轨迹所需的大量计算和 API 成本相比,使用批评者模型对这些步骤进行标注的成本非常低廉。这是因为批评者只需一次遍历即可分析整个轨迹(只需一次模型调用),并且其输出极为简洁——仅仅是一组带有相应标签(good、unnecessary、mistake 或 recover)的步骤编号。
现在我们已经为每一步都标注了标签,接下来我们该如何实际使用这些标签?
理论上,有几种处理方式。我们可以只取轨迹的前缀,即仅对初始的有益步骤进行训练,并在第一次出现错误时停止。或者,我们可以通过完全删除错误步骤来修改和转换轨迹,从而生成合成的“干净”轨迹。
但有一种更简单、更优雅的方法:我们只需跳过对错误步骤的训练损失计算。
为什么这种方法更优越?首先,我们不会生成任何合成数据,这意味着我们避免了发明从未实际发生的虚假场景。其次,模型仍然可以看到完整的轨迹,并从完整的上下文中学习,但我们只是不训练它去预测错误步骤中的 token。
这意味着模型可以看到错误的发生,但它不会被训练去重现这些错误。此外,如果代理在轨迹的后续部分成功地从错误中恢复,模型实际上会学习如何执行这种恢复!
从技术角度来看,在训练过程中,我们会对这些错误步骤中的标记进行“屏蔽”,使其不参与训练损失的计算。如果你熟悉标准的下一个标记预测训练,屏蔽是一种非常常见的技术。例如,用户的消息(提示)通常会被屏蔽,以防止模型学习预测它们,而助手的响应则不会被屏蔽。我们在这里并没有做任何过于复杂的事情;我们只是将这种标准的屏蔽技术应用到助手的特定有害步骤上。在训练过程中,我们对这个特定的错误步骤的损失进行屏蔽,而其他步骤则保持不变。
回到我们上面的例子轨迹,这意味着虽然第4步(A4)不会计算其损失,但它仍然会在模型计算后续第5、第6、第7、第8和第9步的训练损失时保留在上下文中。
还需要注意的是,即使你只将这种屏蔽方法应用于未成功轨迹,它也能非常有效地发挥作用。这使我们来到了表格中我们尚未讨论的最后一个实验:实验#4(未解决的屏蔽)。
如你所见,仅在5,000条未解决的轨迹上进行训练,其中错误步骤被屏蔽,可以实现29.7%的解决率。这实际上比简单地将5,000条未解决的轨迹和5,000条已解决的轨迹混合在一起进行训练(28.5%)还要好!这意味着你可以仅使用纯粹的未成功轨迹,通过一个批评者进行筛选,仍然可以显著提高性能。当然,如果你已经有了成功的轨迹,你当然应该将它们包含在训练数据中。但看到我们的步骤屏蔽方法即使在仅包含失败运行的情况下也能取得如此强大的效果,这确实令人鼓舞。
结论
步骤拒绝微调(SRFT)提供了一种实用的方法,可以从你的训练数据中提取更多价值。我们不需要因为这些轨迹没有完美解决任务就将它们丢弃,而是可以使用一个批评者来过滤掉噪声,并从信号中学习。
查看我们的论文
当然,确切的好处取决于你的具体任务、你拥有的成功与未成功轨迹的比例,以及你的批评模型识别有害步骤的能力。你的批评者的严格程度是一个需要权衡的关键因素:
- 如果批评者过于宽松,你可能会在训练数据中保留有害的步骤,这会降低模型的质量(类似于天真混合方法)。
- 如果批评者过于严格,你可能会丢弃太多潜在有用的步骤,从而失去包含未解决轨迹的最初优势。
这种严格程度通常由批评者的提示决定。或者,你可以让批评者输出其判断的置信度分数,并根据特定的阈值筛选步骤。无论如何,这种平衡需要针对每个特定的数据集进行调整。但总体而言,一旦调整好,它是一种简单直接的技术,可以显著提高代理的性能。
代理训练
步骤拒绝微调
- 分享
上一篇帖子
2026年开发者生态系统调查 – 参与全球最大规模的开发者研究之一