工具更强,审查反而更差:用 PR 证据约束 Copilot 代码审查

2026-07-10 41 预计阅读时间: 1 分钟
来源: github.blog AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:10 分钟

给代码审查 Agent 配上共享的 Unix 风格代码探索工具,看起来理应提升效果:它能搜索仓库、读取文件、查看差异,也能沿着调用链继续调查。但 GitHub 的实践揭示了一个反直觉结果:工具能力增强后,Copilot 代码审查一度变得更差。真正带来改善的,不是继续增加工具,而是围绕 Pull Request 中的证据重塑 Agent 工作流,从而减少无效探索和审查成本。

问题不在工具,而在搜索空间

rgsedgit diffgit show 都是成熟、高效的代码探索工具。对人类工程师而言,它们能快速回答具体问题;对 Agent 而言,它们也会打开一个几乎没有边界的搜索空间。

当审查流程缺少明确约束时,Agent 很容易出现几类行为:

  • 从一个改动文件扩散到大量未修改文件;
  • 沿着调用关系不断追踪,却没有形成可验证的审查结论;
  • 重复读取相同代码,消耗上下文窗口和工具调用预算;
  • 根据仓库中的一般风险发表评论,而不是判断本次 PR 是否引入了问题;
  • 把“可能值得关注”写成缺乏证据的审查意见。

因此,工具更强并不自动等于审查更准。如果 Agent 的目标只是“理解代码库并寻找问题”,更强的探索能力可能带来更高成本和更多噪声。代码审查需要的是一个更窄的目标:判断当前补丁是否引入了能够由 PR 证据支持的问题。

把差异作为起点,也作为边界

围绕 PR 证据组织工作流,可以把审查拆成三个问题:

  1. 这次提交具体改变了什么行为?
  2. 哪些仓库上下文能够证明该变化存在风险?
  3. 审查意见能否指向修改行,并说明可触发的后果?

这里的“证据”不只包括 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 提出的具体问题。能力决定它能走多远,证据工作流决定它是否走在正确方向上。


相关推荐