0. 一句话总结
这篇论文的核心结论是:很多 code agent 失败,并不是因为完全没找到问题代码,而是因为虽然找到了大致位置,却在更细粒度的推理、修改和回退上出了问题。 另外,失败轨迹通常更长、更发散,说明“不会停损”的 agent 会浪费大量计算。(arXiv)
1. 背景:这篇论文为什么重要?
1.1 什么是 code agent?
论文里的 code agent,不是单独一个大模型,而是 LLM + 工具 + 规划/执行循环 的系统。这样的系统会读代码仓库、调用命令、运行测试、改代码、再根据结果继续决策,所以它比“只会补全代码”的模型更像一个会动手的程序员。(arXiv)
1.2 现有问题在哪里?
作者认为,现在很多工作评估 code agent 时,主要只看 成功率,例如在 SWE-Bench 上修复了多少真实 GitHub issue。这样做的问题是:最后修没修好,只告诉你结果,不告诉你过程。 研究者就会不知道失败究竟来自哪里:
是没有收集到足够上下文?
是虽然找到了相关文件,但推理方向错了?
是 fault localization(故障定位)只定位到文件,没有定位到函数或代码块?
还是 agent 掉进了很长的错误循环里?
这篇论文就是要把这些黑箱部分拆开来看。(arXiv)
1.3 这篇论文研究了什么?
作者分析了三个开源 code agent:OpenHands、SWE-agent、Prometheus,并使用它们在 SWE-Bench Lite 和 SWE-Bench Verified 上的执行轨迹做比较研究。论文不是训练新模型,而是做一套 经验研究(empirical study):看不同 agent 的成功路径和失败路径到底长什么样。(arXiv)
2. 这篇论文最重要的 insight
2.1 作者最后提炼出的 8 个 takeaways,可以压缩成 3 组理解
A. 成功不只是“找到答案”,而是“走对抽象层级”
Prometheus 在一些 case 里之所以独特地成功,不是因为它修改得更猛,而是因为它更早看懂了 这个 bug 本质上属于哪个抽象层级。比如有的 bug 表面看像数据库字段问题,Prometheus 却识别出本质是 enum 表示问题;这种“repository-aware context gathering”能帮助 agent 对齐仓库已有设计模式。(arXiv)
B. 失败往往不是立即死掉,而是越来越深地走错
论文发现失败轨迹通常比成功轨迹更长,而且方差更大;尤其 OpenHands 和 Prometheus 的失败轨迹更容易出现“长尾”,也就是有些失败会拖很久很久才结束。作者因此提出,agent 需要更强的 early stopping / backtracking / abandon path 机制,而不是一直把错误假设越走越远。(arXiv)
C. 很多失败已经找对文件了,但没找对“怎么改”
故障定位分析显示,成功 patch 在 90% 以上都能找到正确文件;但即使是失败轨迹,也有相当高比例能找到正确文件,例如 Lite 上失败案例的 file-level match 仍可达到 72.5%–81.4%。这说明很多失败不是“仓库里迷路”,而是 进入文件之后,函数级/代码块级判断和修改策略不够好。(arXiv)
3. 方法:这篇论文到底是怎么做的?
先说一个很关键的点:
这篇论文的方法不是“提出一个新算法去修 bug”,而是“提出一套分析框架去研究 agent 的行为”。
所以这里的“理论”,更准确地说是 分析框架与测量设计,而不是数学定理证明。(arXiv)
3.1 研究对象与数据来源
作者选择 agent 的标准是三条:
开源;
有可获得的 trajectory;
最近一年发布且仍在维护。
最后选了 OpenHands、SWE-agent、Prometheus。OpenHands 和 SWE-agent 的 trajectory 来自 SWE-Bench 维护者公开的 bucket;Prometheus 的日志来自作者实验评估时直接收集。论文同时看了 SWE-Bench Lite 和 Verified 两个分区。(arXiv)
论文还列出了每个 agent 在两个分区对应的 base LLM 和评测时间:
OpenHands:CodeAct 2.1 Sonnet
SWE-agent:Claude 4 Sonnet
Prometheus:Lite 上用 GPT-4o,Verified 上用 Devstral Medium 2507。(arXiv)
3.2 理论框架:把 trajectory 统一成可比较的“步骤流”
作者受到 Thought-Action-Result 结构启发,把每条轨迹拆成 step,而不是用更粗的 iteration。这里的 step 分三种:
Thought step:agent 输出的思考/反思;
Action step:工具调用、命令执行、agent 内部组件交互等动作;
Result step:动作返回的结果、观察到的输出。
这样做的目的是:把不同 agent、不同日志格式,统一映射到一个可比较的行为序列里。作者特地说明,他们选择 step 而不是更粗粒度的 iteration,是为了保留更多细节,避免把本来不相关的相邻事件硬绑在一起。(arXiv)
3.3 实现细节:不同 agent 的日志是怎么被解析的?
这是这篇论文很容易被忽略、但其实很重要的实现部分。
作者为三种 agent 分别写了解析器,把原始日志转换成统一格式:
OpenHands:输入是 JSON 数组形式的 trajectory steps;thought 从 assistant text fields 里抽;action 用结构化 tool_calls;result 通过匹配 tool_call_id 和动作对应起来。
SWE-agent:输入是带 trajectory list 的 JSON 对象;thought 来自显式 thought/response 字段;action 优先取结构化 tool_calls,没有结构时回退到推断出的 commands;result 通过 tool_call_id 匹配,若没有则附着在后续 observation 上。
Prometheus:输入是原始
.log文本;thought 直接从日志行里解析 reasoning segments;action 从日志信息里的 tool_calls 数组里提取;result 通过“与最近一个前序动作关联”的方式配对。(arXiv)
这一步解决的实际问题是:三个 agent 的日志格式完全不同,如果不先做统一解析,后面所有比较都没有可比性。 这也是论文最像“系统研究”的地方之一。(arXiv)
3.4 RQ1:作者怎么分析“谁擅长修哪类 bug”?
作者先从 SWE-Bench 实验公共仓库里拿到每个 agent 解决成功的 issue 集合,再用 集合差(set difference) 计算“某个 agent 独特解决的 issue”,也就是:这个 issue 只有该 agent 解决了,另外两个都没解决。(arXiv)
拿到这些 unique issue 后,作者做人工深挖分析。为了让比较有统一框架,作者把一条解决问题的轨迹分成 5 个阶段:
Diagnosis:初始定位相关文件、类、函数;
Problem Reproduction:复现 bug;
Hypothesis and Plan:形成修复假设和计划;
Implementation:第一次重要代码修改;
Verification:测试是否真的修好。
如果 agent 失败后又根据新信息重新来一轮,作者把它当作一个 loop,也还是沿着这 5 个阶段重新走。作者尤其关注 Hypothesis 和 Implementation,因为最容易在这两个点看到成功路径和失败路径分叉。(arXiv)
3.5 RQ2:作者怎么量化“失败轨迹是不是更长”?
作者假设:失败轨迹会包含更多迭代,因为 agent 更容易被困在错误路径中。于是作者对每条轨迹统计总 step 数,比较成功与失败的分布差异。这里统计的是包含所有 step 类型的总数,而不是只看某一类工具调用。(arXiv)
这一步解决的问题是:把“感觉这个 agent 很会绕路”变成可以量化的现象。 如果失败轨迹真的更长、分布更散,就说明系统设计里可能缺少有效的停损机制。(arXiv)
3.6 RQ3:作者怎么测 fault localization?
这是论文最“可操作”的量化设计之一。
作者不是简单问“最后 patch 成没成功”,而是比较:agent 生成的 candidate patch 和 benchmark 里的 gold patch 在哪里重合。具体抽取三个层级:
file level:是不是改到了 gold patch 所在文件;
function level:是不是改到了 gold patch 所在函数;
hunk level:是不是改到了 gold patch 对应的代码块/行。(arXiv)
更细一点的实现细节是:
他们从 candidate patch 和 gold patch 中抽取 modified files、modified functions、modified hunks;
然后检查 gold patch 里的所有实体 是否都出现在 candidate patch 里;
hunk level 还有一个 宽松匹配(lenient hunk match):如果所有 gold hunks 都出现了,只是行号最多偏差 5 行,就记作
0.5,表示“接近命中”;完全命中记作1,没命中记作0。他们还特别说明:gold patch 只是参考,不是成功与否的裁判。 因为 benchmark 真正的成功标准,是 patch 通过所有测试;一个 candidate patch 即使和 gold patch 不完全一样,也可能是另一条正确修复路径。(arXiv)
这一步到底解决什么?它解决的是:如果 agent 失败了,到底是“连大概位置都找错了”,还是“已经很接近正确修改区域,但最后没收住”。 这比单看 pass/fail 更能解释失败机制。(arXiv)
4. 实验设置(按“实验到底怎么做的”来讲)
4.1 RQ1 的实验怎么做?
RQ1 不是大规模统计先行,而是 先用集合运算找 unique solved issues,再对这些 unique issues 做案例分析。论文最终展示了三个 case study:每个 agent 各取一个独特成功案例。也就是说,这部分实验的目的不是给出“平均性能”,而是找出 不同 agent 独特的成功风格。(arXiv)
4.2 RQ2 的实验怎么做?
RQ2 先把异构日志统一解析成 thought/action/result 的 step 序列,再统计每条轨迹总步数,最后分别比较:
success vs failure;
Lite vs Verified;
OpenHands vs SWE-agent vs Prometheus。
作者看的是均值、最小值、最大值、标准差,并用图展示分布形态,尤其关注 failure 是否出现长尾。(arXiv)
4.3 RQ3 的实验怎么做?
RQ3 对每个 issue 比较 candidate patch 和 gold patch 的重叠程度,然后分别统计两类东西:
Marginal frequencies:单独看 file/function/hunk 各自命中情况;
Joint frequencies:看三者组合,例如“文件对了、函数没对、hunk 也没对”这种组合出现得多不多。
作者预期会看到一种“漏斗”现象:越细粒度,命中越难。实验最后也确实支持了这个判断。(arXiv)
5. 实验结果(详细版)
5.1 RQ1:不同 agent 的独特强项是什么?
5.1.1 Prometheus:擅长找到“正确抽象层级”
Prometheus 在 Lite 上独特解决了 7 个 issue,在 Verified 上独特解决了 8 个。作者拿 django-11964 做例子:这个问题表面像字段行为问题,但 Prometheus 判断本质是 enum representation 问题,于是选择去改 IntegerChoices / TextChoices 的 __str__ 方法,以及 IntegerField.to_python() 对 enum instance 的处理。这个修复是 小而准 的,它贴合了 Django 仓库原有设计方式。相比之下,SWE-agent 和 OpenHands 虽然也复现了 bug,但都把问题理解偏了,走到了更复杂也更偏离根因的修改方向上。(arXiv)
我对这个 case 的理解:
Prometheus 的强项不是“更会改代码”,而是 更会先理解这个仓库习惯用什么方式解决这类问题。这就是论文所谓的 repository-aware context gathering。(arXiv)
5.1.2 OpenHands:擅长在大方向正确时,直接做有效改动
OpenHands 在 Lite 上独特解决了 11 个 issue,在 Verified 上独特解决了 17 个。作者给的例子是 pylint-6258:Pylint 递归模式下 ignore flags 没生效。OpenHands 的判断是 _discover_files 在收集文件时过早遍历,ignore 逻辑执行得太晚,于是它把相关方法从 static 改成 instance method,这样就能访问 linter 配置。虽然这个 patch 和 gold patch 不完全一致,而且实现上不够优雅,但功能上是对的。(arXiv)
SWE-agent 其实也理解到了问题,但第一次修改把所有文件都忽略掉了,造成 regression;Prometheus 静态分析也找到了“过滤太晚”这个点,却在弄清配置项时陷入长时间 context gathering,最后没能产出 patch。(arXiv)
我对这个 case 的理解:
OpenHands 的优势是:当根因方向已经猜对时,它更敢做 一大步的结构性修改,有点像直接把水闸拨开,先让水流通起来再说。代价是 patch 可能不够漂亮,但有时确实能过。(arXiv)
5.1.3 SWE-agent:擅长“保守但稳”的 defensive programming
SWE-agent 在 Lite 上独特解决了 46 个 issue,在 Verified 上独特解决了 71 个,是这部分最强的。作者的例子是 sympy-12236:多项式除法错误地做了简化。SWE-agent 先定位到 apart 函数,用测试复现 bug,然后提出假设:问题在于执行了 integer division,而不是 field division。它最后并没有完全走 gold patch 那条路,而是在简化计算时加了一个检查:如果简化后的值与原值数学上并不一致,就保留原始 field type。 这是一种典型的 defensive programming:不一定完全看透底层数学机制,但用额外的 guard 把错误结果挡住。(arXiv)
Prometheus 和 OpenHands 在这个 case 里都把注意力转到 symbolic values 上,越修越偏,还引入了新的递归或额外错误。OpenHands 甚至跑出了看起来对的输出,但单元测试 div 还是没过,说明它抓错了根因。(arXiv)
我对这个 case 的理解:
SWE-agent 这里像一位很谨慎的工程师:即便没有最深的领域知识,也可以通过“多一道验证、少一点激进假设”的方式把 patch 修对。(arXiv)
5.2 RQ2:失败轨迹真的更长吗?
下面这张表是我根据论文 Table 4 整理的“平均 step 数(success / failure)”。 (arXiv)
从这个结果里,至少可以看出四件事:
所有设置里,failure 的平均 step 数都比 success 高。
Prometheus 的失败膨胀最明显,Lite 上从 87.16 涨到 136.47,Verified 上从 146.59 涨到 220.92。
SWE-agent 本来就更“话多”和更细粒度,成功轨迹本身就长,但失败比成功只多一点点,所以它的失败没有另外两个 agent 那么发散。
Verified 上 OpenHands 和 Prometheus 的 failure 比 Lite 更不稳定,说明更清晰、可解的任务并没有自动让它们更稳,反而可能把它们设计里的弱点暴露出来。(arXiv)
论文还给了最大值和标准差:
Prometheus failure 在 Lite/Verified 的最大 step 数达到 691 / 715;
OpenHands failure 在 Verified 的标准差 80.81,大约是 success 的两倍;
Prometheus Lite failure 的标准差 100.79,接近 success 的三倍。
这说明失败不只是“更长”,而且是 更不可预测、更长尾。(arXiv)
作者进一步给出一个挺有意思的解释:
SWE-agent 这种“很多小步、渐进推理”的风格,虽然成功时轨迹更长,但它的错误更不容易一下子滑向灾难;相反,比较激进、跳跃式的推理风格,一旦假设错了,失败可能会很发散。这个解释是论文的经验性推断,不是严格因果证明,但很有启发性。(arXiv)
5.3 RQ3:fault localization 到底告诉了我们什么?
5.3.1 最关键的结论先说
成功 patch 基本都能找到正确文件,但很少能精确命中 gold patch 的函数甚至精确代码块。 换句话说,成功并不要求“逐行复刻 gold patch”,更像是要在正确区域附近做出有效修复。(arXiv)
5.3.2 具体数字怎么读?
下面这些数字整理自论文 Table 5。 (arXiv)
文件级命中(file-level match):成功 patch 在所有设置下都超过 90%,范围大约是 92.2%–97.3%。
函数级命中(function-level match):成功 patch 只有 21.3%–33.5% 命中 gold function。
精确 hunk 命中(hunk = 1):成功 patch 只有 2.7%–8.4%。
接近命中 hunk(hunk = 0.5,5 行内偏差):成功 patch 大约有 9.3%–12.6%。(arXiv)
这个结果非常重要,因为它直接说明:
修 bug 成功更像“在正确文件的正确邻域里做出合理修改”,而不是“必须精确改到 benchmark 标准答案那几行”。 论文甚至明确说,追求完美 line-level match 并不是高效目标,更值得追求的是 close-proximity hunk localisation。(arXiv)
5.3.3 失败 patch 为什么也常常 file-level 是对的?
失败案例中,file-level match 仍然很高:
Lite 上失败 patch 的 file-level match 为 72.5%–81.4%;
Verified 上下降到 59.3%–67.1%,但仍不算低。(arXiv)
所以失败常常不是“没找到哪个文件”,而是下面这些更细的问题:
在文件内没有进入正确函数;
进入函数后形成了错误假设;
patch 虽接近正确区域,但做了额外错误修改;
验证失败后没有及时放弃错误路径。(arXiv)
5.3.4 Figure 4 说明了什么?
Figure 4 看的是 file/function/hunk 三个层级组合起来后的分布。出现频率最高的组合,是:
文件对了,函数没对,hunk 也没对。
这说明 agent 在大量时间里,其实是在“正确文件内部继续摸索”。论文还发现,在 Verified 上失败案例中,“连文件都找错”的比例比 Lite 明显更高,而且这些错文件失败并不会更快结束,说明 agent 会在错误路径上浪费差不多同样多的时间。(arXiv)
6. 我对这篇论文方法与贡献的评价
6.1 贡献到底在哪里?
这篇论文的贡献,不在于“提出一个更强的修 bug agent”,而在于它搭建了一套 研究 agent 行为的分析框架。我觉得它最有价值的贡献有四个:
把异构日志统一成可比较的 step 序列。
把成功/失败拆成路径问题,而不是只看最终分数。
把 fault localization 细化到 file/function/hunk 三层。
提出“近似命中比精确命中更重要”的经验结论。 (arXiv)
6.2 这套方法具体解决了什么?
如果没有这篇论文,研究者只能看到:
agent A 过了多少题;
agent B 为什么 leaderboard 更高。
但看不到:
agent 是靠仓库模式理解赢的,还是靠保守 guard 赢的;
agent 是在文件定位阶段就输了,还是在函数/代码块阶段输了;
失败是不是“越失败越长”,有没有可能做 trajectory monitoring 来省算力。
所以它真正解决的是 解释性和诊断性 问题。对“怎么设计下一代 code agent”来说,这种诊断价值其实很大。(arXiv)
7. 局限性
7.1 论文自己承认的局限性
作者在 Threats to Validity 里明确说了几件事:
RQ1 的 case study 只覆盖很小一部分轨迹,可能不够有代表性;
thought/action/result 的提取过程带有一定主观性;
扩展到更多 agent 时,需要保证不同日志格式的解析一致;
为了减少格式差异带来的偏差,他们主要比较 repository exploration 和 code modification 事件,并且主要做相对比较。(arXiv)
7.2 我觉得还可以再补充的局限性
(1)这是观察研究,不是因果研究
论文能告诉我们“长失败轨迹”和“更高失败概率”经常一起出现,但不能严格证明“轨迹长导致失败”或者“某种推理风格一定导致成功”。因为它没有做系统级 ablation 或干预实验。(arXiv)
(2)RQ1 的 qualitative evidence 仍然偏少
虽然作者的案例分析很有洞察力,但展示出来的 case 数量不多,因此更适合拿来形成假设,而不是作为非常稳定的普适规律。(arXiv)
(3)fault localization 的“正确性”仍然依赖 gold patch 近似
作者已经很诚实地承认 gold patch 只是 guide,不是 arbiter;但这也意味着,如果 candidate patch 走的是另一条完全正确但结构不同的修复路径,file/function/hunk 对齐指标仍然可能低估它的“定位质量”。(arXiv)
8. 未来方向(论文本身给出的方向 + 我的理解)
论文明确指向了几条后续路线:
更早地放弃错误路径:尤其是 Prometheus 这类 search-heavy agent,需要更强的 backtracking / abandon policy。(arXiv)
把目标从“精确 line-level match”转成“接近正确 hunk 的定位能力”。论文认为 close-proximity hunk localisation 更有意义。(arXiv)
在 Verified 上加强 file-level localisation。作者发现 Verified 暴露出更多“连文件都没找对”的失败。(arXiv)
结合 agent 架构特征做更深入分析。作者怀疑某些架构弱点在 Lite 的噪声里被遮住了,到 Verified 才被放大。(arXiv)
9. 从这篇论文出发,我觉得可以做出的新 idea
下面这些不是论文原文,而是我从论文结果里长出来的想法,像生态园里顺着水脉长出的新枝条一样。
Idea 1:做一个“轨迹停损器(Trajectory Stop-Loss Controller)”
要解决的问题:失败轨迹更长、更发散,很多算力浪费在已经注定要失败的路径上。(arXiv)
怎么做:
在 agent 执行过程中,实时读取 trajectory prefix 的特征,例如:
当前总 step 数;
最近是否反复访问同一批文件;
是否连续出现相似错误(递归错误、测试失败模式不变等);
是否多轮修改后 hypothesis 仍未更新;
file/function/hunk 命中 proxy 是否停滞。
然后训练一个小的控制器,输出三种动作之一:
继续当前路线;
回退到更早的分叉点;
直接结束并交给另一策略或人工。
怎么验证:
在相同 compute budget 下,对比原 agent 与加 stop-loss controller 的 agent,看:
平均 token / step 是否下降;
pass rate 是否持平或上升;
failure 的长尾是否被削掉。
我觉得这是离论文最近、最容易落地的一个方向。(arXiv)
Idea 2:做一个“近似编辑区域规划器(Approximate Edit Region Planner)”
要解决的问题:成功不要求精确命中 gold hunk,但“接近正确 hunk”显著更有希望成功。(arXiv)
怎么做:
不要一上来就逼 agent 找“唯一正确那几行”,而是先做三级规划:
先排文件;
再排函数;
最后在函数附近切出若干个 edit neighborhoods(比如以 suspicious lines 为中心的窗口)。
生成 patch 时,不是直接对全文件自由发挥,而是优先在 top-k neighborhoods 内修改。这样能减少在正确文件里瞎游走的情况。
怎么验证:
除了 benchmark success rate,还可以单独看:
file/function/hunk 的 hit rate;
lenient hunk match 是否上升;
patch edit scope 是否更集中、更少额外修改。
这条路特别契合论文“close-proximity localisation 比 exact localisation 更值得追”的结论。(arXiv)
Idea 3:做一个“策略切换型 agent(Search-first ↔ Guard-first Hybrid Agent)”
要解决的问题:Prometheus 和 SWE-agent 的强项其实互补。Prometheus 更像“先理解架构再下手”,SWE-agent 更像“即便没完全懂,也用 defensive programming 保守修对”。(arXiv)
怎么做:
先让一个 controller 判断当前 issue 更像哪一类:
需要仓库模式理解、抽象层级判断的任务;
需要快速验证、逐步加 guard 的任务。
然后在两个模式之间切换:
Search-first mode:先做 repository-aware context gathering,找 abstraction level;
Guard-first mode:先复现、加 test、做小步 defensive patching。
也可以更进一步:前半程用 Prometheus 风格找抽象层,后半程交给 SWE-agent 风格做渐进修改。
怎么验证:
专门在论文里那些“某 agent 独特成功”的 issue 上做 targeted evaluation,看 hybrid 能不能吃到两边的优点。(arXiv)
Idea 4:用“成功/失败分叉点”做轨迹偏好学习
要解决的问题:论文已经告诉我们,很多失败不是完全无信息,而是在某个 hypothesis 或 implementation 阶段开始偏航。(arXiv)
怎么做:
把同一个 issue 上的 success trajectory 和 failure trajectory 对齐到分叉点,训练一个 trajectory preference model,学习:
在这个状态下,下一步更好的动作是什么;
哪些 thought/action 模式通常预示着错误方向。
然后把这个偏好模型作为 agent 的 reranker 或 critique module。
怎么验证:
看它是否能减少“重复错误测试”“在错误 hypothesis 上修补新增错误”这类失败模式。
这个想法的魅力在于:失败轨迹不再只是垃圾数据,而是监督信号。 这和论文“失败轨迹也包含部分进展信息”的精神很契合。(arXiv)
10. 最后给博士的阅读结论
如果你把这篇论文当成“谁的 agent 最强”的排行榜论文,它其实不算最刺激;但如果你把它当成“如何研究 agent 的行为机制”的论文,它是很有价值的。它最大的意义,是把一个常被分数掩盖的问题讲清楚了:
agent 失败,往往不是因为完全不会修,而是因为它不知道什么时候该停、该回头、该换抽象层级。 (arXiv)
这篇论文很适合作为入门者理解 trajectory analysis、fault localization、agent interpretability 的第一篇。它像是把一池看似浑浊的水慢慢静下来,让你看见底下每一圈涟漪到底从哪里开始偏开。
博士要是愿意,我下一条可以继续把这份笔记再压缩成一版 “适合组会汇报的 10 页以内提纲”。