给代码审查 Agent 配上共享的 Unix 风格代码探索工具,看起来理应提升效果:它能搜索仓库、读取文件、查看差异,也能沿着调用链继续调查。但 GitHub 的实践揭示了一个反直觉结果:工具能力增强后,Copilot 代码审查一度变得更差。真正带来改善的,不是继续增加工具,而是围绕 Pull Request 中的证据重塑 Agent 工作流,从而减少无效探索和审查成本。
问题不在工具,而在搜索空间
rg、sed、git diff 和 git show 都是成熟、高效的代码探索工具。对人类工程师而言,它们能快速回答具体问题;对 Agent 而言,它们也会打开一个几乎没有边界的搜索空间。
当审查流程缺少明确约束时,Agent 很容易出现几类行为:
- 从一个改动文件扩散到大量未修改文件;
- 沿着调用关系不断追踪,却没有形成可验证的审查结论;
- 重复读取相同代码,消耗上下文窗口和工具调用预算;
- 根据仓库中的一般风险发表评论,而不是判断本次 PR 是否引入了问题;
- 把“可能值得关注”写成缺乏证据的审查意见。
因此,工具更强并不自动等于审查更准。如果 Agent 的目标只是“理解代码库并寻找问题”,更强的探索能力可能带来更高成本和更多噪声。代码审查需要的是一个更窄的目标:判断当前补丁是否引入了能够由 PR 证据支持的问题。
把差异作为起点,也作为边界
围绕 PR 证据组织工作流,可以把审查拆成三个问题:
- 这次提交具体改变了什么行为?
- 哪些仓库上下文能够证明该变化存在风险?
- 审查意见能否指向修改行,并说明可触发的后果?
这里的“证据”不只包括 diff。它还可以包括被修改函数的直接调用者、相关测试、配置约束、类型定义和错误处理约定。关键在于,每一次仓库探索都应由补丁中的具体疑问触发。
例如,看到函数参数从必填改为可选后,读取它的直接调用者是合理的;扫描整个仓库的所有 API 处理器通常没有必要。看到事务边界发生变化后,可以检查同一调用路径上的写操作;继续研究无关模块的数据库封装则很可能偏离本次 PR。
这种工作方式让 Unix 工具回到它们擅长的位置:工具负责提取证据,工作流负责限制范围。
可以这样实践:构造一个有预算的审查入口
下面是一个可复制改造的 Bash 脚本。它不是原文披露的内部实现,而是依据摘要中的方法构造的最小实践:先保存 PR diff,再只收集修改文件和变更附近的上下文。运行前将 BASE_REF 改成目标分支;本地需要安装 Git 和 ripgrep。
#!/usr/bin/env bash
set -euo pipefail
BASE_REF="${BASE_REF:-origin/main}"
CONTEXT_LINES="${CONTEXT_LINES:-40}"
OUTPUT_DIR="${OUTPUT_DIR:-.review-evidence}"
rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR/files"
git diff --find-renames --unified=3 "$BASE_REF"...HEAD > "$OUTPUT_DIR/pr.diff"
git diff --name-only --diff-filter=ACMR "$BASE_REF"...HEAD > "$OUTPUT_DIR/changed-files.txt"
while IFS= read -r file; do
[ -f "$file" ] || continue
safe_name="$(printf '%s' "$file" | tr '/' '_')"
rg -n --context "$CONTEXT_LINES" \
'^(class |def |func |function |export |interface |type |public |private |protected )' \
"$file" > "$OUTPUT_DIR/files/$safe_name.context.txt" || true
done < "$OUTPUT_DIR/changed-files.txt"
printf 'Evidence written to %s\n' "$OUTPUT_DIR"
printf 'Changed files: %s\n' "$(wc -l < "$OUTPUT_DIR/changed-files.txt" | tr -d ' ')"
保存为 collect-review-evidence.sh 后执行:
chmod +x collect-review-evidence.sh
BASE_REF=origin/main CONTEXT_LINES=25 ./collect-review-evidence.sh
脚本有意不做全仓库漫游。生成的 .review-evidence/pr.diff 是主要输入,其他文件只提供有限上下文。实际接入 Agent 时,可以把探索规则写进提示词:
你正在审查一个 Pull Request。
目标:只报告由本次补丁引入、且有仓库证据支持的问题。
工作规则:
1. 先阅读 pr.diff,列出发生行为变化的修改点。
2. 只有在验证某个具体疑问时,才能读取未修改代码。
3. 优先检查直接调用者、相关测试、类型定义和配置约束。
4. 每个疑问最多执行 3 次探索命令;证据不足时放弃该意见。
5. 不评论纯风格偏好,也不报告补丁之前已经存在的问题。
6. 每条意见必须包含修改位置、触发条件、实际后果和证据来源。
“最多 3 次”只是可调整的初始预算,不应被理解为 GitHub 公开的固定参数。团队可以根据仓库规模、语言和风险等级设置不同上限。
让审查意见携带证据
控制工具调用只是第一步。输出格式也要迫使 Agent 区分事实、推断和建议。可以要求它生成如下结构化结果:
{
"file": "src/orders/service.ts",
"line": 84,
"severity": "high",
"trigger": "Two workers confirm the same pending order concurrently",
"impact": "The inventory decrement can be committed twice",
"evidence": [
"The patch moves the status check outside the transaction",
"confirmOrder is called concurrently by the queue consumer"
],
"suggestion": "Move the check back into the transaction or use a conditional update"
}
这种格式不会自动保证结论正确,但它提高了提交低质量意见的门槛。如果无法填写触发条件或证据,Agent 就不应把猜测发布为行内评论。
评估系统时,也不要只统计“发现了多少问题”。更有价值的指标包括:
- 每个有效意见消耗的工具调用数;
- 被开发者接受、修复或明确驳回的意见比例;
- 评论能否准确落在引入问题的修改行;
- 无证据意见和重复意见的数量;
- 不同仓库规模下的延迟与计算成本。
落地时保留风险分级
证据优先不意味着禁止跨文件调查。身份验证、并发控制、数据迁移和权限边界等高风险改动,往往必须读取补丁之外的代码。合理的做法是按风险分配预算,而不是对所有 PR 使用同一探索深度。
落地时可以采用这份检查表:
- 默认从 diff 开始,并记录每次扩展搜索的原因;
- 先调查修改符号的直接邻域,再决定是否扩大范围;
- 为工具调用、读取字节数和总耗时设置预算;
- 要求评论同时包含触发条件、后果和代码证据;
- 将安全敏感或架构级变更交给更深的审查流程;
- 用真实 PR 和开发者反馈评估准确率,而不是只看离线样例。
这次经验的核心不是“少用工具”,而是让工具服从审查任务。Agent 可以拥有完整的 Unix 工具箱,但每一步探索都应回答一个由 PR 提出的具体问题。能力决定它能走多远,证据工作流决定它是否走在正确方向上。