Sourcegraph 基于 1281 次 agent 运行的数据分析,总结出编码 agent 在大型开源项目中的失败原因和基础设施修复方案。
来自 40 多个大型开源仓库的 1,281 次 Agent 运行数据显示,coding agent 存在五种反复出现的失败模式,以及分别对应的基础设施解决方案。
某个 coding agent 接到一项任务:分析 Kubernetes 源代码中的特定资源分配机制,如何将决策传递到多个 package。这需要追踪 Dynamic Resource Allocation(DRA)系统在 22,000 个文件、共计 140 万行 Go 代码中的运行路径。
Agent 开始工作。它用 grep 搜索 DRA allocator,结果在几十个目录中搜出了数百处匹配。它读取一个文件,发现该文件从另一个 package 导入内容,于是跳转过去。那个 package 又引用了另外三个 package。每一步单独看都合情合理,但整条探索路径最终一无所获。
运行到 6,000 秒时——超过一个半小时——Agent 仍然什么都没有产出。没有分析,没有输出,得分为零。
现在,让同一个 Agent 执行同一个任务,唯一的区别是:它不再只能访问本地文件,而是可以使用由完善索引支持的代码搜索工具,包括关键词搜索、语义搜索和 find-references。8 次关键词搜索和 6 次语义搜索定位出了相关 package。一次 find-references 调用便梳理出了跨 package 的依赖链。89 秒后,Agent 给出了一份全面的分析,得分达到 0.90(满分 1.0)。
同一个模型,同一个任务,不同的上下文基础设施。彻底失败与近乎完美完成之间的差距,不在于智能水平,而在于能否高效获取上下文。
本文所述的失败模式来自 CodeScaleBench。这是一套软件工程任务 benchmark,覆盖 9 种编程语言,并在 40 多个规模最大的开源仓库上进行评测。这些观察结果来自 1,281 次有评分的 Agent 运行,数据量足以让我们区分系统性模式与随机噪声,并为每种失败模式确定具体原因。
理解这些模式非常重要,因为每一种模式都对应着特定的基础设施干预措施。如果跳过诊断,你就会做错东西。
在大型代码库中,Agent 的失败并不是随机发生的,而是集中在五种反复出现的模式上。只有先判断自己面对的是哪一种模式,才能知道应该修复什么。
这是最常见的失败模式。Agent 不断导航、追踪引用、读取文件,却始终无法收敛出一套计划,也没有产生任何输出。它把整个超时时间都耗在了探索上。
背后的机制很直观。Agent 的基本策略是读取一个文件、沿着它的 import 继续追踪,再读取下一个文件。当搜索空间有限时,这套方法运作良好;但在包含 22,000 个文件的代码库中,这种策略生成的探索树,其分支增长速度会超过 Agent 的剪枝速度。每个文件都会引用另外三个文件,而在把所有分支都读一遍之前,Agent 无法判断哪些分支真正重要。
CodeScaleBench 的数据显示,这种情况与代码库规模直接相关。当代码库超过约 40 万行代码时,只配备本地工具(grep、文件读取、glob)的 Agent 就会开始系统性地陷入困境。加入代码智能工具后,reward 的变化如下:
随着代码库复杂度增加,这类 Agent 遇到的并不是推理失败;它每一步的推理其实都是正确的。真正失败的是搜索基础设施。Agent 缺少能在选定遍历路径之前缩小搜索空间的工具。
Agent 找到了与搜索词匹配的代码,却选择了错误的结果。在大型代码库中,常见的 symbol 名称可能出现在几十个文件里。在 Kubernetes 中用 grep 搜索 allocate,会得到数百处匹配,分散在测试文件、已弃用代码、工具函数以及真正的分配逻辑中。
# Lexical search: 47 matches, no ranking by structural relevance
$ grep -rn "allocate" pkg/ | wc -l
47
# Structural navigation: 1 definition, 12 call sites, ranked by role
find-references --symbol "DRAAllocator.allocate" --scope "pkg/"
→ Definition: pkg/scheduler/framework/plugins/dynamicresources/allocator.go:142
→ 12 call sites across 4 packages
在 benchmark 数据中,关键词搜索是使用最多的工具类型:所有运行共调用 7,993 次,相比之下,语义搜索调用了 2,449 次,deep-search 仅调用了 57 次。Agent 极其偏爱能够奏效的最简单工具。但单靠词法搜索,无法区分一个 symbol 的定义、它的 47 个调用点、测试 mock 和文档中的提及。当每个 package 都有一个 handler.go,或者每个 module 都有一个 __init__.py 时,文本搜索会返回大量结果,却无法按照结构相关性对其排序。
解决方案是结构化代码导航:go-to-definition、find-references 和 type-hierarchy resolution。这些能力利用编译器对代码的理解,将定义与调用点区分开来。
Agent 找到了一部分相关代码,却遗漏了其余部分。在 Strata 金融库的一项跨文件重构任务中,基线 Agent 只修改了 7 个受影响文件中的 2 个,得分为 0.32。使用 Sourcegraph MCP 的 Agent 则识别出了所有受影响文件,完成了完整重构,得分达到 0.80。
基线 Agent 对它找到的文件并没有判断错误,所做的修改在局部也是正确的。它只是没有找到另外 5 个同样需要修改的文件。在高度耦合的代码库中,不完整的重构往往比完全不重构更糟,因为它会让代码处于不一致状态:已修改位置的 API contract 与尚未修改的调用点出现偏差。
这是最隐蔽的失败模式,因为它看起来似乎取得了一定成功。在多仓库任务中,这一问题会进一步恶化。CodeScaleBench 数据显示,多仓库任务的 F1 提升幅度为 +0.209,而单仓库任务只有 +0.085。当 Agent 所需的代码跨越组织内部的仓库边界时,如果没有专门的工具,Agent 找全所有相关代码的概率会显著降低。
Agent 会过度调用工具,并在反复试错中不断回退。在一项重构任务中,基线 Agent 在 84 分钟内调用了 96 次工具,其中包括 6 次彻底推翻原有方案,最终得分为 0.32。配备 Sourcegraph MCP 的 Agent 则只进行了 5 次有针对性的搜索,耗时 4.4 分钟,得分为 0.68。
96 比 5 并不是特例。当 Agent 缺少高效的搜索工具时,它寻找代码的策略就会退化:用 grep 搜索一个词,读取结果,发现不对;再 grep 另一个词,读取另一个文件;然后回退,换个目录继续尝试。每一轮循环都会消耗 token 和时间。
使用 MCP 增强的 Agent,也就是具备由完善索引支持的结构化搜索接口的 Agent,成本降低了 30%(每项任务 0.51 美元,而基线为 0.73 美元),平均速度则提高了 38%。成本和时间的下降,几乎完全来自对这种反复折腾的消除。由于推理并不是检索环节的瓶颈,这也会影响企业应该选择哪些模型,才能为后续 Agentic 任务取得足够好的检索结果。
工具调用上的反复折腾不只是更慢,在结构上也更糟。每次回退都会在对话历史中留下残留内容:那些文件内容已经不再相关,却依然占用上下文。等到 Agent 终于找到正确文件时,它能够用于生成输出的上下文空间,可能反而少于第一次尝试就找到这些文件的情况。
Agent 会读取过多无关代码,继而失去重点。即使找到了相关文件,它也经常完整读取整个文件,导致数百行无关代码稀释真正有用的信号。
这里有一个反直觉的发现:为 Agent 提供更多工具,有时反而会让情况更糟。这很可能是因为我们没有提供足够的策略信息,告诉它应该在何时、以何种方式使用这些工具。在某些任务中,配备代码搜索工具的 Agent,耗时甚至超过了只有本地工具的 Agent。在这些情况下,Agent 用搜索找到更多代码来阅读,花时间理解它们,最终却仍然要完成与基线 Agent 相同的本地工作。
这背后有一个已经得到充分研究的认知机制。针对长上下文语言模型的研究表明,它们难以有效利用长上下文中间位置的信息。当 Agent 把大量搜索结果塞进上下文时,最相关的信息可能恰好落在最不利于模型注意力的位置。如果模型无法有效访问检索到的内容,那么获取更多代码并不能提升性能。我们正在积极改进工具说明,引导 Agent 更有效地使用现有能力。
解决方案不是更大的上下文窗口,而是更聪明地选择应该放进窗口的内容;而这一点完全可以通过代码智能工具来控制。
看到这份列表后,一个常见反应是:模型要到什么时候才能变得足够好,让这些问题自行消失?但其中大多数问题都不会自行消失,因为它们并不是模型能力问题。
以“在代码库中迷失方向”为例。Agent 每一步的推理都是正确的:它读取一个文件,识别相关 import,然后继续追踪。问题在于,这种策略在大型代码库中会产生指数级增长的分支。更聪明的模型或许能更高效地执行同一策略,却仍然要面对同样的组合爆炸。解决方案不是更聪明的 Agent,而是一个能让 Agent 跳过探索、直接抵达相关代码的搜索索引。
再看工具调用上的反复折腾。那 96 次工具调用并不等于 96 次错误,而是 Agent 使用仅有的工具寻找信息的 96 次尝试。每次单独的搜索都合情合理,但这些工具无法区分结构相关性与文本共现,因此 Agent 只能尝试多种方法。即使换成更聪明的模型,也仍会受制于同样的工具。
这一区别会直接影响你应该把工程投入放在哪里。如果你认为问题出在模型能力上,就只能等待下一次模型发布。如果你理解到这是基础设施问题,就会引入代码搜索系统、结构化索引和检索流水线。后一种方法会产生复利效应:你为今天的 Agent 构建的基础设施,也会让明天的 Agent 表现得更好。
每一种失败模式,都对应着一项具体的基础设施投入。
在代码库中迷失方向,以及找错文件、认错 symbol:需要代码搜索和索引基础设施。在 40 万至 200 万行代码的规模区间内,+0.259 的 reward 增幅,为这方面的投入提供了实证依据。结构化导航(go-to-definition、find-references、type hierarchies)能够为 Agent 提供词法搜索无法提供的能力:利用编译器对代码的理解,判断哪些代码在结构上彼此相关。
只完成了一部分:需要检索覆盖系统。结合关键词搜索、语义搜索和结构化搜索的混合检索流水线,可以最大限度提高找出所有受影响文件的概率,而不只是找到最显眼的那些文件。
工具调用上的反复折腾和上下文溢出:需要上下文管理。根据任务类型选择检索策略,使策略与任务结构相匹配,并通过实证阈值判断在什么情况下增加上下文有帮助,又会在什么情况下适得其反。
贯穿其中的共同点是:要在生产环境中打造可靠的 coding agent,仅仅选对模型远远不够。真正需要解决的,是模型与代码库之间的一系列工程问题。代码搜索、结构化索引、检索流水线和完善的评估基础设施,才能把一个能够理解和推理代码的模型,转变为一个能够可靠完成工作的 Agent。
帮助你的组织扫清阻碍,更快交付。
选择 Sourcegraph,面向企业的代码理解平台。