文章指出基准测试只能帮助选模型,无法证明真实代码补丁可安全合并。作者为AI生成的变更增加脚本化审查门禁和风险评分,再据此调整人工审查强度。
几周前,我写过一篇文章,介绍如何构建一套可复现的测试框架,在提交代码之前对比免费的 AI 编程模型。那套框架回答了一个问题:我应该使用哪个模型?
但它没有回答更棘手的后续问题:当模型为我的真实代码库生成 patch 后,什么时候才能安全地合并?
本周,DEV 上有一场关于“理解比来源更重要”的精彩讨论——其核心观点是,代码来自人类还是模型并不重要,重要的是是否真的有人理解它。我认同这个原则,但在忙碌的工作日下午,原则往往经不起现实的冲击。真正能坚持下来的,是一份有约束力的检查清单。因此,我在自己的模型测试框架上加了一套流程:每个由 AI 生成的 patch,都必须先通过一个脚本化的审查门禁,我才会开始阅读它;脚本还会生成一份评分卡,告诉我应该以多谨慎的程度审查这份代码。
当模型生成一份看起来符合惯用写法的 40 行 diff 时,我的大脑会做一件很危险的事:根据代码风格进行模式匹配,然后跳过对语义的检查。这段代码读起来像是我会写出的东西,于是我也像审批自己写的代码一样批准了它。
我实际发布过的 AI 生成代码问题,从来都不是语法错误——甚至连测试都通过了。问题通常是这样的:
一个重试循环捕获了错误的异常类型,导致真正的错误被吞掉。
一个查询过滤条件比它所替换的条件略微更宽泛,但测试仍然通过了,因为测试数据集太小,无法暴露这个问题。
为了实现一个标准库用一行代码就能完成的功能,却引入了新的依赖。
如果在阅读代码之前先问四个无聊的问题,这三个问题原本都能被发现。所以,我把这些问题写进了脚本。
这个门禁就是一个小型 shell 脚本。它接收一个 patch 文件,将其应用到一个用完即弃的 worktree 中,然后执行四项检查。它绝不会触碰我当前的工作分支,并会在最后输出一行审查结论。
#!/usr/bin/env bash
# review-gate.sh <patch-file> <base-branch>
set -euo pipefail
PATCH="$1"
BASE="${2:-main}"
WT=$(mktemp -d /tmp/ai-review.XXXXXX)
echo "== 1. Isolate =="
git worktree add --detach "$WT" "$BASE" >/dev/null
if ! git -C "$WT" apply --check "$PATCH" 2>/dev/null; then
echo "VERDICT: REJECT (patch does not apply cleanly to $BASE)"
git worktree remove --force "$WT"; exit 1
fi
git -C "$WT" apply "$PATCH"
echo "== 2. Full test suite (not just the touched package) =="
if ! (cd "$WT" && npm test --silent 2>&1 | tail -5); then
echo "VERDICT: REJECT (tests fail)"
git worktree remove --force "$WT"; exit 1
fi
echo "== 3. Diff surface audit =="
git -C "$WT" diff "$BASE" --stat
NEW_DEPS=$(git -C "$WT" diff "$BASE" -- package.json \
| grep -c '^+.*".*":' || true)
echo "new dependency entries: $NEW_DEPS"
echo "== 4. Behavior-change heuristics =="
# Flag the patterns that have burned me before
SUSPECT=$(git -C "$WT" diff "$BASE" \
| grep -E '^\+.*(catch|except|retry|timeout|WHERE|filter\()' \
| wc -l | tr -d ' ')
echo "error-handling/query lines added: $SUSPECT"
if [ "$NEW_DEPS" -gt 0 ] || [ "$SUSPECT" -gt 5 ]; then
echo "VERDICT: REVIEW CLOSELY (expanded surface area)"
else
echo "VERDICT: STANDARD REVIEW"
fi
git worktree remove --force "$WT"
请根据自己的技术栈调整第 2~4 步。重点并不在于我具体使用了哪些 grep 规则,而在于:每一次,这些检查都会抢在我的主观判断之前,以完全相同的方式运行。
之所以需要第 1 步,是因为模型生成的 patch 经常只在它所看到的旧上下文中“有效”;尝试将它应用到当前 main 分支的干净 checkout 上,本身就是一项有价值的检查结果。
这个循环包含两个需要大量算力的环节:生成候选 patch,以及运行审查门禁——如果要为每个候选 patch 执行完整测试套件,速度会变得很慢。这两个环节正是我一直在使用 MonkeyCode 的地方。利益披露:本文是 MonkeyCode 产品推广活动的一部分。
具体来说,我会利用 MonkeyCode 提供的免费模型访问能力,针对同一个任务生成两到三个相互独立的候选 patch;然后使用它提供的免费服务器选项,分别对每个候选 patch 运行门禁脚本。这样,我的笔记本电脑就不必同时执行三套测试。
生成多个候选方案,是这里一个被严重低估的做法:当两次独立生成采用了相同的实现思路时,我对审查结果的信心会提高;当它们的方案出现分歧时,那些分歧点恰好就是我需要逐行阅读的地方。
我刻意不引用配额、模型名称或性能数据,因为这些信息会发生变化,你应该自行查看当前情况。对于这套工作流而言,真正重要的只有一点:生成代码和在沙箱中运行测试这两个步骤都不需要我花钱,也不会独占我的机器。
门禁运行结束后,我会据此决定需要投入多少个人注意力:
最后一行才是真正发挥价值的部分。“写下原因”是我为了践行“理解比来源更重要”原则而设置的个人护栏:如果我无法用一句话解释为什么这份 diff 是正确的,那么无论测试结果有多绿,它都不能被合并。
第 4 步中的启发式规则是我自己的,是根据我过去遇到的失败调整出来的。你的规则会有所不同。可以先从一个空列表开始,每当 AI 生成的代码坑到你时,就添加一种模式——这份脚本应该长出属于你自己的“伤疤组织”,而不是直接带着我的经验上线。
测试全部通过只是底线,而不是上限。如果你的测试套件覆盖率很低,那么这套门禁的价值就只剩下第 1 步和那些 grep 检查。请先解决测试覆盖率问题。
不要对微不足道的 diff 运行这套流程。一个只有五行的配置变更,不需要专门创建 worktree 和评分卡;仪式化流程同样有成本。
这不是安全审查。新增依赖只会被标记出来,并不会被自动审计。如果模型添加了一个 package,你仍然需要认真检查这个 package。
如果仓库中的测试无法在干净的 checkout 中运行——例如依赖隐藏的本地状态或手动配置环境——那么第 1 步会不断失败,无法告诉你任何有用的信息。其实,这本身就是关于你的仓库的一个有价值的信号,但在采用这套门禁之前,请先解决这个问题。
模型对比告诉你,平均而言应该信任哪个生成器。审查门禁则告诉你,是否应该信任眼前这一个具体的 patch。第一个问题很有趣;第二个问题才真正决定了你的用户最终会运行什么代码。
既然你本来就在通过免费的模型访问能力生成候选方案,那么让每个 patch 都通过基于干净 worktree 的门禁脚本,其边际成本大约也就是十五行 bash。每次写下一条诚实的 commit message,它都能确保在按下合并按钮时,真正的理解掌握在你这一边。
如果你构建了自己的版本——尤其是用于匹配失败模式的 grep 规则——我真的很想看看你的列表里都有什么。
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。