我们最近注意到GitHub Copilot团队分享了一个反直觉的案例:他们把Code Review的代码探查工具从自建的一套(list_dirsearch_fileread_code)迁移到了Copilot CLI 共享的Unix风格工具层(grepglobview)。工具本身明显更好——更标准、更稳定、更容易维护。但Benchmark跑下来,结果让所有人愣住:review成本反而上升,问题漏检增多。

这不是一次平滑升级,而是一次痛苦的回退和再出发。最终他们通过重写Agent的tool instructions,实现了生产环境review成本降低约20%,同时质量信号不降。这篇文章我会拆解这个case:根因在哪,五条修复原则是怎么来的,以及为什么同样的instructions放到Copilot CLI就完全没用。

现象:换工具,效果反而变差

Copilot Code Review之前有一套自建的代码探查工具:

  • list_dir:列出目录内容
  • search_file / search_dir:按文件名或路径搜索
  • read_code:读取指定文件内容

这套工具虽然不标准,但有个关键特性:默认返回匹配行 + 周围上下文。Agent拿到结果后,往往不需要额外探索就能直接做分析。比如search_file("utils.js")会返回整个文件摘要和关键代码段。

为了统一技术栈,团队决定把这套工具迁移到Copilot CLI共享的Unix风格工具层:

  • grep:搜索代码文本
  • glob:查找文件路径
  • view:读取文件内容

新工具只返回精确匹配。grep "getUser"只返回匹配的行号,不带上下文。glob "*.js"只返回文件名列表,不含内容。Agent拿到这些精确结果后,必须自己决定下一步:到底要不要读这个文件?读到哪一行?——这给Agent留下了大量“猜测”空间,于是灾难发生了。

Benchmark数据对比:

指标 旧工具 新工具(未修改instructions) 变化
平均review成本(工具调用次数) 基线 +35% 恶化
关键问题漏检率 基线 +12% 恶化
完成率(成功完成review) 基线 -8% 恶化

数据来自GitHub内部Benchmark(官方博客原文)。 表现:新工具在每一项上都变得更差,这就是“更好的工具更差的效果”的反直觉案例。

诊断:Agent陷入了browsing loop

为什么工具升级后效果反而下降?根因不在工具本身,而在tool instructions

Copilot CLI环境的instructions让Agent按照“编程助手”的模式工作:

  1. 宽泛搜索路径(glob
  2. 猜测文件名
  3. 读取文件内容(view
  4. 根据读到的内容再搜索(grep
  5. 循环回到第1步

这种模式在coding assistant场景下合理——你给一个任务,AI需要探索整个代码库才能找到相关文件。但在Code Review场景下,Agent已经有了明确的起点:PR diff。它不需要“浏览”代码库,而是需要“调查”PR中哪些改动有问题。

错误的instructions导致Agent的行为模式变成了一个browsing loop

glob("src/**/*.ts") → view("src/utils.ts") → grep("deprecatedFunc") → glob("**/*.ts") → view("src/helpers.ts")...

Agent在大量无关的文件中来回跳跃,不断调用viewgrep,但始终没有聚焦到diff所涉及的那几个文件。review成本自然飙升,且因为噪声太多,真正的问题反而被淹没。

工具映射对照表

旧工具 → 新工具的职责映射很清楚:

旧工具 新工具 职责 行为变化
list_dir glob 发现候选文件和目录 glob只返回路径,不返回内容摘要
search_file / search_dir grep 搜索代码匹配文本 grep只返回匹配行号,不带上文
read_code view 精确定位后读取文件内容 view需要明确的文件+行范围,否则返回整个文件

问题出在:新工具的精确性要求Agent有更强的“侦察能力”——必须知道自己在搜什么、为什么要读这个文件、读到什么程度为止。而旧的instructions完全没有给Agent灌输这种思维。

修复:5条review-shaped原则

团队重写了tool instructions,核心是让Agent的行为从“浏览器”变成“调查员”。原则如下:

1. Start from the diff and form specific review questions

Agent必须先将PR diff作为锚点,明确自己需要验证哪些问题。比如:“这个PR修改了认证逻辑,我需要检查token是否被正确验证”、“新增了缓存机制,我需要确认缓存淘汰策略是否合理”。这些问题直接决定后续搜索方向。

2. Use glob when path uncertain, grep to find candidates/symbols/call sites

当Agent不确定目标文件路径时,用glob缩小范围;当需要找到函数调用链或符号定义时,用grep精确搜索。避免无目的的glob通配符探索。

3. Batch cheap discovery before reading files

在真正调用view读文件之前,先一次性收集所有需要的路径和符号位置。比如先glob到所有相关文件名,再grep到所有需要查看的函数签名,形成一个读文件清单,然后批量view。这比“搜一个→读一个→再搜一个”要高效得多。

4. Use view only when agent knows which file/line range it needs

只有在Agent明确知道要读哪个文件的哪一段时,才能调用view。如果不知道具体行号,先用grep定位。这条原则直接消除了之前“先view再猜”的浪费。

5. Batch focused reads instead of alternating search→read→search→read

不要交替执行搜索和读取,而是先完成两个阶段的探索,然后一次性读取所有需要的代码段。这减少了工具调用的循环次数,也避免了Agent在读取时被新问题分心。

这五条原则合并成一段连贯的instructions写进System Prompt。以下是简化后的伪代码(实际为自然语言描述):

你是一名代码审查专家。PR diff已经提供。你应该:
1. 从diff出发,形成具体待验证的问题列表。
2. 对于每个问题,先用glob确定候选文件路径,或用grep定位符号/调用点。
3. 在一个探索阶段完成后,批量调用view读取所需的文件行。
4. 仅在明确了文件+行范围后才调用view。
5. 如果遇到路径不确定,用glob反查,而不是猜测。

对比旧instructions的核心差异:恢复策略不同。旧instructions让Agent猜测邻近路径→读取→再搜索(失败时盲目猜测)。新instructions让Agent失败时用glob找正确路径,而非猜测。这个区别看似微小,但在trace中效果显著。

结果:20%降本 + 质量不降

应用新instructions后,生产环境的数据:

指标 旧工具(基线) 新工具+旧instructions 新工具+新instructions 变化 vs 基线
平均review成本 基线 +35% -20% 降低20%
关键问题漏检率 基线 +12% -2% 改善
完成率 基线 -8% +3% 改善

数据来自GitHub Engineering Blog(2026-07-10)。 注意:基准对比是旧工具,新工具从+35%降到-20%,净改善55个百分点。质量信号(问题检出覆盖率)甚至略好于旧工具。

团队还总结了一套Benchmark trace调试法:不只看最终分数,而是逐条追踪Agent的工具调用路径。调试信号包括:

  • 是否先窄化再读取?
  • 是否批量独立搜索?
  • call view时是否有明确理由?
  • 工具失败后的恢复模式是什么?

通过这些信号,可以快速判断instructions是否有效,而不用等完整的A/B实验。

反例验证:为什么CLI场景无效

团队做了一个巧妙的反向验证:把同样的review-style instructions应用到Copilot CLI(通用编程助手场景)。结果——无效

原因是CLI场景没有diff anchor。用户可能问“怎么优化这个模块”,Agent需要从零开始探索代码库,浏览本身就是工作的一部分。如果一上来就让Agent“从diff出发形成问题”,它根本没有diff。所以在CLI场景下,原来的browsing模式反而是合理的。

这个反例说明了一条核心设计原则:同一套工具层可以复用,但instructions必须匹配具体product scenario。Code Review和Coding Assistant是两个不同的产品,Agent的工作流也应该不同。

对你的启发:如何设计Agent的Tool Instructions

GitHub这个case给我的启发有三条:

1. Instructions > Tools

工具本身的质量很重要,但instructions决定了Agent如何使用工具。这次重构中,工具没有变化(都是grep/glob/view),只是instructions从“浏览模式”变成“调查模式”,效果就从+35%变成-20%。instructions是Agent行为的“操作系统”,工具只是“指令集”。投入时间精心设计instructions,比盲目换工具更有效。

2. Diff-anchored workflow

如果你正在做Code Review Agent,一定要把PR diff作为固定的起点。Agent的所有搜索都应该从diff中提到的问题出发,而不是从全局代码库出发。这听起来简单,但在实际prompt中很容易被忽略。可以参考GitHub的这五条原则,按你团队的代码规范调整后直接使用。

3. Trace-based debugging

不要只看最终的review通过率或成本。把Agent的每次工具调用记录下来,绘制成行为图,观察它是否走了弯路。如果你发现Agent在不断glob → view → glob循环,那你的instructions一定有问题。用trace定位问题,比凭感觉调prompt高效得多。

最后,GitHub的做法也提醒我们:即使是用同样的技术栈(Copilot CLI),不同的产品场景也需要不同的引导策略。你在设计Agent时,先问自己一个问题:“这个Agent在什么场景下工作?它的起点是什么?它的目标是什么?”明确了这些,instructions自然就有了方向。

我们团队之前也做过类似的Code Review Agent探索,但只停留在调整模型层面。今天看了这个案例,下一个版本准备直接抄作业——先把diff锚点写进prompt里,再设计一个便宜工具批处理->精确读取的流程。工具复用、instructions定制,这个范式值得更多人试试。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐