2011 年的 DAgger 被搬回来训 SWE 智能体,4B 模型干翻一票 8B 系统

核心摘要

这一年 SWE 智能体的训练几乎被三类配方瓜分:SFT 蒸出来的模仿,GRPO 这类带验证奖励的 RL,以及最近大热的在线蒸馏 OPD。每一类都各自踩坑:SFT 训练态干净到不真实,部署时一旦走错一步就回不来;RL 奖励稀疏到长程任务里几乎不传梯度;OPD 又被冷启动卡住,弱学生自己跑根本到不了正例轨迹。这篇 arXiv 2605.12913 把 Ross 等人 2011 年的经典模仿学习算法 DAgger 直接挪进多轮 LM 智能体的 post-training,做法朴素得让人不太敢相信会 work:rollout 时每一轮按一个概率 \(\beta\) 让 teacher 接管,全程在每个访问到的状态上都向 teacher 询问一个动作标签,然后拿 cross-entropy 训学生。SWE-Bench Verified 上,4B 学生跑到 27.3 分超过一众已发表的 8B SWE 智能体,8B 学生跑到 29.8 分压过 SWE-Gym-32B,离 32B 旗舰也只差不到 5 分。我的判断是:这不是新算法,但它把 2011 年那篇 paper 的核心 insight 重新校准到 LLM 长程交互这个新场景里,干净到几乎没有 trick,结果反而最有说服力。


论文信息

  • 标题:Revisiting DAgger in the Era of LLM-Agents
  • 作者:Changhao Li, Rushi Qiang, Jiawei Huang, Chenxiao Gao, Chao Zhang, Niao He, Bo Dai
  • arXiv:2605.12913
  • 提交:2026 年 5 月 13 日
  • 任务:SWE 智能体 post-training,benchmark 用 SWE-Gym Holdout 和 SWE-Bench Verified

一、你训出来的 SWE Agent 为什么一上线就跑偏

先说一个让人有点头疼的现象。

SFT 训出来的 SWE 智能体,在训练集上看损失曲线一切正常,挪到 SWE-Bench Verified 上跑几次你就会发现:模型经常在第几轮干了一件错误的事,之后就再也回不来了。错的不是模型不会写代码,而是它从某个 turn 开始进入了一段它训练时从来没见过的上下文,接下来每一步都是在错误的状态分布上做决策,越滚越偏。

这件事在模仿学习教科书里有个干净的名字:covariate shift,再加上 multi-turn 的 compounding error。Ross 等人 2011 年那篇 DAgger 论文给过一个非常漂亮的理论结果——纯 behavior cloning 的误差随 horizon 呈二次增长,而把训练数据收集在学生自己的状态分布上、用专家在那个状态下的动作做监督,误差可以压回线性。

但这两年 LLM agent 火起来之后,整个社区基本上跳过了这条线索,大家拥抱的是另外两条路:

方法 它做对了什么 它的真问题
SFT 密集的 token 级监督,训练超稳 只在 teacher 走过的状态上训,部署时 covariate shift
RL with verifiable rewards 在学生自己的 rollout 上学,分布对齐 奖励是稀疏的 0/1,长 horizon 信用分配几乎没信号;group sampling 又贵又容易 advantage 塌缩
On-Policy Distillation 在策略状态加密集 teacher 监督,看起来兼得 冷启动直接劝退,弱学生 rollout 早期全是失败前缀,teacher 监督到的都是死局

论文真正想问的问题就一句话——

有没有一种方法,能同时拿到密集监督、在策略状态覆盖,又不被冷启动卡死,还顺便兼容 black-box teacher?

读到这里我的第一反应是:这不就是 DAgger 吗?只是 LLM 这个圈子集体忘了它而已。作者其实就是这个意思,他们把这套思路重新搬回多轮 LLM 智能体场景,没有炫技、没有花里胡哨的 loss,把工程上能干净落地的部分钉死。


二、方法:让学生开车走,但每一步都让老师告诉你正确动作

2.1 一句话讲清核心 idea

学生自己走轨迹,但每访问一个状态,都让 teacher 在同样的上下文里给一个动作标签出来,拿这个标签训学生。少数 turn 直接换成 teacher 接管,把学生从死局里拽回来,让训练数据里始终有走向成功的轨迹片段。

这就是关键。状态分布对齐由学生 rollout 提供,密集监督由 teacher 的逐 turn 标签提供,冷启动问题由 teacher 偶尔接管来兜底。三件事一个机制全解了。

2.2 两种 rollout 协议

文中给了两种 mixing 方式,逻辑都不复杂。

DAgger-style:turn 级伯努利切换。 每一轮独立按 \(\beta_i\) 决定是 teacher 出手还是学生出手。\(\beta_i\) 随训练迭代衰减——前几轮 teacher 介入多一点保证轨迹能走到正例,后面慢慢交给学生让分布逼近部署态。

形式上,每个 turn 的指示变量 \(b_t \in \{0,1\}\) 独立采样:

\[p_i^{\mathrm{turn}}(b_{1:T_{\max}}) = \prod_{t=1}^{T_{\max}} \beta_i^{b_t}(1-\beta_i)^{1-b_t}\]

实验里他们用的衰减是 \(\beta_i = \max(0.6, 1.0 - 0.2(i-1))\),5 轮训练,从 1.0 衰减到地板 0.6。

AggreVaTe-style:轨迹级切换。 给一条轨迹采样一个学生前缀长度 \(\kappa \sim \rho_i\),从 0 到 \(T_{\max}\),前 \(\kappa\) 轮学生自己跑,后面 teacher 直接补完。

\[p_i^{\mathrm{traj}}(b_{1:T_{\max}} \mid \kappa) = \prod_{t=1}^{\kappa} \mathbb{I}\{b_t=0\} \prod_{t=\kappa+1}^{T_{\max}} \mathbb{I}\{b_t=1\}\]

实验中 \(\rho_i\) 设为 0 到 40 的均匀分布,因为他们观察到学生 rollout 一般 40 turn 之内就结束了。

2.3 监督信号怎么收

这块是整个方法最干净的地方,也是和 OPD 最本质的差别。

不管这一轮最终是谁执行的,在每个访问到的状态 \(s_t\) 上,都额外去查询一次 teacher 的动作 \(\tilde{a}_t \sim \pi_e(\cdot \mid s_t)\) 作为训练标签。

也就是说,learner 学的是「在这个我(学生)真实会遇到的上下文里,teacher 会怎么操作」。然后训练目标是标准的 token 级交叉熵:

\[\mathcal{L}_i(\theta) = \mathbb{E}_{(s_t, \tilde{a}_t)\sim \mathcal{D}} \left[ \sum_{t=1}^{T} \ell_{\mathrm{CE}}(\theta; s_t,\tilde a_t) \right]\]

OPD 也在学生 rollout 上训,但它用的是 teacher 在学生轨迹上的 logits 做 reverse-KL 蒸馏——这就要求 teacher 是 white-box,对 GPT、Gemini 这种纯 API 模型直接不可用。DAgger 这里 teacher 只需要能在任意状态下给出一个动作(token 序列),black-box 完全没问题。

2.4 一个统一的视角

作者很贴心地把 SFT / RL / OPD / DAgger 全部写进一个统一的 update 框架:

\[\theta_{i+1} = \arg\max_\theta\ \mathbb{E}_{s\sim p_s, a\sim p_a}\left[w(s, a)\log \pi_\theta(a\mid s)\right]-\lambda \Omega_i(\theta)\]

四种方法的差别就压缩到「状态分布 \(p_s\)、动作分布 \(p_a\)、权重 \(w(s,a)\)」三个轴上:

方法 状态分布 \(p_s\) 动作分布 \(p_a\) 权重 \(w(s,a)\)
SFT / BC \(d_{\pi_e}\)(teacher 走过的状态) \(\pi_e\) 1
RL (Policy Gradient) \(d_{\pi_\theta}\) \(\pi_\theta\) advantage \(A(s,a)\)
OPD \(d_{\pi_\theta}\) \(\pi_\theta\) \(-\log \frac{\pi_\theta}{\pi_e}\)
Ours (DAgger-style) \(d_i^{\rm turn}\)(学生-教师 turn 混合分布) \(\pi_e\) 1
Ours (AggreVaTe-style) \(d_i^{\rm traj}\)(学生前缀+教师补完) \(\pi_e\) 1

这个表看下来你会有一种「啊原来如此」的感觉——DAgger 在这套语言里是把状态分布换成了学生-教师混合分布,但动作分布和权重保持和 SFT 一致。换言之,DAgger 是 SFT 的状态分布修正版。简单到不像一个新算法,但正因为简单,它继承了 SFT 全部的训练稳定性,没有 PPO 那种 ratio clip 的 trick,也不需要 group rollout 的算力开销。


三、实验:4B 学生干翻 8B 系统,8B 学生顶上 32B

3.1 主表

实验设置先说清楚。Teacher 是 Qwen3-Coder-30B-A3B-Instruct,学生是 Qwen3-4B-Instruct-2507 和 Qwen3-8B。训练数据 SWE-Gym 2338 个任务,留出 100 个做 holdout。所有方法都用 OpenHands 这个 SWE 智能体框架做 rollout,scaffold 完全对齐——这一点对公平性来说很关键,避免不同方法之间的 prompt 工程差异污染数据。

Method SWE-Gym Holdout SWE-Bench Verified
Qwen3-4B baseline 5.0 11.2
Qwen3-4B + GRPO 8.0 11.6
Qwen3-4B + SFT 15.0 22.9
Qwen3-4B + OPD 16.0 23.4
Qwen3-4B + DAgger-style 17.0 27.3
Qwen3-4B + AggreVaTe-style 16.0 24.5
Qwen3-8B baseline 2.0 7.7
Qwen3-8B + GRPO 4.0 8.2
Qwen3-8B + SFT 12.0 23.4
Qwen3-8B + OPD 16.0 26.2
Qwen3-8B + DAgger-style 19.0 29.8
Qwen3-8B + AggreVaTe-style 17.0 27.3
SkyRL-Agent-8B-v0 -- 9.4
SWE-smith-LM-7B -- 15.2
R2E-Gym-7B-Agent -- 19.0
SWE-Gym-32B -- 20.6
R2E-Gym-32B-Agent -- 34.4
SWE-Dev-32B -- 36.6

几个数字读下来感受很直接。

4B 学生在 SWE-Bench Verified 上跑到 27.3,比同一份训练数据、同一份 scaffold 下的 OPD 多了 3.9 个点,比 SFT 多了 4.4 个点。再看下半部分 published 系统,27.3 已经超过 SkyRL-Agent-8B-v0、SWE-smith-LM-7B 和 R2E-Gym-7B-Agent 这些 7B/8B 级别的 SWE 智能体。

8B 学生 29.8,比 OPD 多 3.6 个点,关键是它压过了 SWE-Gym-32B 的 20.6 整整 9 个点,距离 R2E-Gym-32B-Agent 也只差 4.6 个点——后者用了 R2E-Gym 自己更大的训练数据,scaffold 也不完全一样。

我自己看到这个数会想一个问题:published 32B 系统的训练数据和 trick 都不一样,这种跨系统对比的可比性其实有水分。但作者的诚实之处在于,他们在主表上半部分做了「同初始化、同数据、同 scaffold」的 head-to-head 对比——OPD 是同期最强的 post-training baseline,DAgger 干净地比 OPD 高 3 到 4 个点,这部分对比是没什么水分的。

3.2 数据扩展的稳定性:DAgger 同时治冷启动和后期偏移

这张图我觉得是全文最值得品的一张。

Scaling on SWE-Gym Holdout

四条曲线:DAgger-style(蓝实线)、AggreVaTe-style(橙实线)、SFT(绿虚线)、OPD(粉点线)。横轴是 effective training samples,纵轴是 SWE-Gym Holdout 的解决率。

看 3K 样本那个点。OPD 才 9,SFT 10,AggreVaTe 已经 13,DAgger 12。这正是冷启动效应——OPD 早期学生 rollout 大量失败前缀,supervisor 监督到的都是没价值的状态;DAgger 因为 teacher 偶尔接管,早期就拿到了能走到成功的轨迹片段。

再看 9K 那个点。DAgger 17,SFT 15。这是 covariate shift 的影响——SFT 已经把 teacher 的状态分布学完了,但它学的从来不是部署时学生自己会遇到的状态。DAgger 在后期 \(\beta\) 衰减之后,训练数据状态分布越来越靠近 deployment,监督依然密集。

Scaling on SWE-Bench Verified-100

OOD benchmark 上更夸张。SFT 在 7K 处达到 20 然后掉到 19,这是非常典型的 over-imitation 表现——继续在 teacher 状态上喂数据,反而损害了对真实部署状态的泛化。DAgger 一路涨到 26。

一个算法同时治了 OPD 的冷启动 和 SFT 的后期偏移,这件事在我看来比绝对数字更值钱。

3.3 Reverse KL:直接量了一下「学生在自己的轨迹上离 teacher 有多远」

Reverse KL of policies

这张图度量的是 \(D_{\mathrm{KL}}(\pi_\theta \| \pi_e)\) 在学生 rollout 状态上的平均值,越低说明学生在自己部署时会遇到的状态分布上越靠近 teacher。

SFT 那条绿色虚线特别戏剧化:先从 0.27 跌到 0.10,然后从某个点开始反弹回 0.126。这是 covariate shift 的直接证据——SFT 早期学生还在 teacher 状态附近,divergence 低;训得越久学生策略变化越大,自己 rollout 就跑到 teacher 训练集没覆盖的地方了,KL 反弹。

DAgger 和 AggreVaTe 两条线下到 0.10 之后基本水平,没有反弹。OPD 稳定在 0.11 到 0.12 之间,介于 SFT 和 DAgger 之间。

这个 reverse-KL 实验非常聪明。它把「covariate shift」这个偏理论的概念翻译成了一个可以测的标量,并且实验结果直接对应了主表上的性能差距。

3.4 失败模式分析:DAgger 把 agent 推向了「更难的失败」

Method Resolve Submission Syntax/Runtime Context Overflow Budget Exhaustion
Qwen3-4B baseline 11.2 52.1 6.6 29.4 49.2
+ GRPO 11.6 53.4 2.8 28.1 48.9
+ SFT 22.9 97.6 20.3 55.1 13.9
+ OPD 23.4 98.5 17.6 15.4 40.3
+ DAgger 27.3 97.9 15.9 57.5 19.3
+ AggreVaTe 24.5 97.2 17.9 60.1 16.2

注:百分比读法见原表,Syntax/Runtime 在 submitted-but-unresolved 里算,Context Overflow 和 Budget Exhaustion 在 no-submission 里算。

我读这张表读了好几遍才理顺。几个观察:

GRPO 几乎没改变什么。submission rate 53.4,跟 base model 的 52.1 几乎一样。多数 no-submission 失败是 budget exhaustion,说明 agent 大量 rollout 跑到 turn budget 用完了还没干完活。这其实是 sparse reward 的典型副作用——模型不知道该收尾,因为它没有任何 step-level 信号说「该 finish 了」。

SFT 和 OPD 都学到了「该提交」,submission rate 飙到 97.6 和 98.5。但 SFT 的 syntax/runtime 错误率 20.3 是所有训练方法里最高的,OPD 在 no-submission 里 repetitive-loop 占 44.3——它会陷入重复操作的死循环。

DAgger 的 syntax/runtime 降到 15.9,repetitive-loop 也低;它的主要失败模式变成了 context overflow(57.5)。这个表述方式我挺欣赏的:DAgger 把 agent 推向了「更难的失败」——不是不会做、不是工具用错、不是死循环,而是任务太复杂、上下文窗口不够装。这个 bottleneck 不是算法问题,是模型 context window 的物理限制。

AggreVaTe 的 wrong-file rate 是所有方法里最低的 15.7,作者推测是因为它有更长的 teacher 连续轨迹,teacher 能完整演示如何在仓库里定位文件。这是一个很自然的解释:turn-level 切换可能在「找文件」这种需要连续几步连贯操作的子任务上不如轨迹级切换。


四、我的判断:朴素,但是干净

读完整篇我有几个比较强的判断。

它不是新算法,它是新视角下的老算法。 DAgger 的核心 idea 2011 年就在那里了,状态分布对齐 + teacher 标签。这篇论文真正的贡献是在 LLM agent 这个新场景下把它做干净——选对 benchmark、选对 baseline、把 OPD 这个最强对手钉死在主表里、把统一框架那张表写出来。这种工作不会拿 best paper,但它会改变下一拨 SWE 智能体训练的默认 recipe。

它压住了 OPD 这个最强对手,是真有说服力的。 同期 NVIDIA、Anthropic、Qwen3 报告都在押 OPD,这篇直接在同初始化、同数据、同 scaffold 的设置下比 OPD 多 3 到 4 个点。OPD 还要求 teacher 是 white-box,DAgger 不需要——意味着你拿 GPT 或 Claude 当 teacher 也可以做。这是工程上很大的便利。

32B 系统对比那一块要打个折扣。 R2E-Gym-32B 用了完全不同的训练数据和 scaffold,SWE-Dev-32B 也是。所以「8B 接近 32B」这个 narrative 你别完全照单全收,但「8B 在同样数据和 scaffold 下显著超过 32B 的 SWE-Gym-32B」这个判断是 solid 的。

最值得追问的两个 limitation。 第一,teacher 是 Qwen3-Coder-30B-A3B,本身就是个 black-box 的 LM,它在「错误状态」下给的标签是不是真的「正确」?经典 DAgger 假设有 oracle expert,但 LLM teacher 本身就有犯错的可能,teacher error 会不会复合?论文没正面处理。第二,整个研究只测了 SWE 一个领域,scaffold 也只测了 OpenHands。Web navigation、agentic RAG、math-with-tools 这些其他长程任务上是不是一样 work,作者自己在 conclusion 里也承认是 future work。

对工程的启发挺直接的。 如果你正在训 SWE 智能体或者类似的长程工具调用 agent,从 SFT 切到 DAgger-style 的成本极低——rollout pipeline 加一个伯努利切换、一个 teacher 标签查询,loss 不变。试一下完全没成本。我会赌它在大多数场景下能给你几个点的提升。

还有一个 meta 层面的观察。 LLM 这个圈子这两年的算法进展其实大量来自于「把以前 RL/IL/控制领域踩过的坑重新踩一遍」——RLHF 之后 GRPO 出来,说到底是 policy gradient 的现代化;OPD 是 distillation 的某种变体;这篇 DAgger 又把 covariate shift 这个老问题翻出来。这倒不是说 LLM 圈在重复造轮子,更像是新场景倒逼大家把以前不被重视的工具重新拿出来对齐。下一个被重新发现的可能是什么?我赌的是 model-based 那套——给 LLM agent 加一个 world model,让它能 plan 之后再 act。


五、一个工程上的小细节

我重读 method 部分时注意到一个挺重要的实现细节:训练时不是每个 (state, action) 对单独算 loss,而是把同一条轨迹里共享前缀的 transition 打包到一个 forward 里,用 loss mask 来保证梯度等价于逐对独立更新。

这件事看着平淡,但对训练效率影响极大。SWE 任务的 context 经常 32K+,每个 turn 重新 forward 一遍 prefix 是不可承受的开销。这种 packing 实现差不多是 LLM agent 训练 pipeline 的标配,但它对正确性的影响不小——尤其是当某个 turn 是学生动作时,你需要在这个 turn 之后断开 chunk,不能让 teacher label 条件在反事实的轨迹上。论文这块只写了一行字("applying a loss mask to ensure the gradient remains equivalent"),但实际工程上是需要小心处理的。

如果你打算复现这套方法,建议先把 packing 和 loss masking 的逻辑画清楚再写代码。这是这套方法的隐藏陷阱。


六、收尾

把 2011 年的 DAgger 拿回来对齐 LLM 智能体,看起来朴素,但当你把方法放在「OPD vs SFT vs RL」这个三方角力的语境里看,它解决的恰好是三方都没解决的问题——同时给你密集监督、在策略覆盖、冷启动鲁棒、black-box 兼容。

这种工作的价值不在于震撼,而在于干净。它没有 hack、没有花哨的目标函数、没有难调的超参,五轮迭代、\(\beta\) 从 1 衰减到 0.6,整个 recipe 一张 A4 纸就能讲完。你能把它写在团队的 onboarding 文档里直接上手。

如果你也在训长程的 agent,无论 SWE、web、tool-use,这套思路值得把 SFT pipeline 改一改试试。预计你能拿到 3 到 5 个点的提升,几乎是免费的。

觉得有启发的话,欢迎点赞、在看、转发。跟进最新AI前沿,关注我