作者被便宜模型坑过两次(统一 diff 格式静默失效、长大文件 retry 率翻三倍),设计了一套从 git commit 元数据提取任务、用 shell 脚本跑金丝雀测试的流程。
每隔几周就会有一个新的编程模型发布,价格低到让现有模型显得尴尬,朋友圈里满是一上线就改配置的人。我在这上面吃过两次亏:一次一个"开箱即用替代品"悄悄停止了有效 unified diff 的输出,还有一次一个更便宜的模型通过了所有 prompt,但在长文件上把重试率翻了三倍,把省下的钱又吐回去了。
所以现在我不再凭感觉或 leaderboard 截图来评估新模型。我会用一个从我自己仓库历史里挖掘出来的小型金丝雀测试集,在候选模型接触任何真实工作之前先跑一遍。这篇文章就是这套 harness:任务提取脚本、运行器、决策表,以及这个方法的诚实局限。
这是我之前写过的个人记分板的延续,但目标不同——不是"给模型总体排名",而是"回答一个具体问题:这个特定的便宜模型安全到可以承载我的流量吗?"
Benchmark 测试的是 benchmark 作者关心的东西。你的 git 历史测试的是你关心的东西。我直接从 commit 元数据里拉取已完成的任务:
#!/usr/bin/env bash
# extract_tasks.sh — build canary tasks from your own repo history.
# Each task = the state before a real commit + the human-written
# commit message as the instruction. The real diff becomes the reference.
set -euo pipefail
REPO="$1"
OUT="canary_tasks"
N="${2:-30}"
mkdir -p "$OUT"
cd "$REPO"
git log --format='%H' -n "$((N + 1))" -- 'src/**' | tac > /tmp/canary_commits.txt
i=0
while read -r commit; do
parent=$(git rev-parse "$commit^" 2>/dev/null) || continue
# Skip merge commits and giant diffs — they make noisy tasks.
[ "$(git cat-file -p "$commit" | grep -c '^parent')" -eq 1 ] || continue
files_changed=$(git diff --name-only "$parent" "$commit" | wc -l)
[ "$files_changed" -le 4 ] || continue
msg=$(git log -1 --format='%s%n%n%b' "$commit")
diff=$(git diff "$parent" "$commit")
mkdir -p "../../$OUT/task_$i"
echo "$msg" > "../../$OUT/task_$i/instruction.md"
echo "$diff" > "../../$OUT/task_$i/reference.diff"
git archive "$parent" | tar -x -C "../../$OUT/task_$i" 2>/dev/null || true
i=$((i + 1))
done < /tmp/canary_commits.txt
echo "Extracted $i tasks into $OUT"
三十个小的、单一目的的 commit 给你的是一个比三十个手工写的 prompt 诚实得多的测试集,因为你自己知道这些任务是具有代表性的——它们从字面上就是你项目实际需要的工作。
一条规则:永远不要对一个历史里有 secrets 的仓库跑这个。先把敏感信息剥离干净,跟你在给任何 agent 访问代码库之前会做的准备工作一样。
运行器把每个任务发送给候选模型,应用结果,然后分类结果。我只追踪三个类别——比这更细的粒度就不再具有可操作性了:
# grade.py — deliberately simple. Example code; adapt to your stack.
import json, subprocess, sys
from pathlib import Path
def grade(task_dir: Path) -> str:
ref = (task_dir / "reference.diff").read_text()
out = task_dir / "candidate.diff"
if not out.exists() or not out.read_text().strip():
return "hard_fail" # empty / unparseable output
apply = subprocess.run(
["git", "apply", "--check", str(out)], cwd=task_dir,
capture_output=True)
if apply.returncode != 0:
return "hard_fail" # malformed diff
ref_files = set(l.split()[1] for l in ref.splitlines()
if l.startswith("+++ b/"))
out_files = set(l.split()[1] for l in out.read_text().splitlines()
if l.startswith("+++ b/"))
if not out_files <= ref_files | {f.replace('b/', 'a/') for f in ref_files}:
return "soft_fail" # scope creep
return "pass" # shape is right; eyeball diffs after
results = {p.name: grade(p) for p in Path(sys.argv[1]).iterdir() if p.is_dir()}
print(json.dumps(results, indent=2))
这个评分故意很浅——它只检查形状和范围,不检查语义正确性。语义检查是第三步,而且是有意为之的手工操作。
聚合分数会掩盖那些真正重要的失败。跑完之后,我从十个随机选取的任务中打开候选 diff 和参考 diff 并排比较,问自己一个问题:我在代码审查里能 catch 到这个吗,还是它会直接发布?悄无声息丢弃的错误处理和"好心"重新格式化的文件在通过率数字里都看起来没问题,而这种问题恰恰是更便宜的模型容易引入的。如果我在十个样本里发现任一模式两次,不管分数多少,这个模型都不会获得路由流量。
这个 harness 运行成本低但不是免费的——三十个任务乘以 N 个候选模型加起来不少,而且每次新模型发布都重新跑一遍,正是这种成本让人们跳过评估、直接 YOLO 配置的原因。
披露:本文是 MonkeyCode 产品推广的一部分。
这就是我一直在用这个 harness 指向 MonkeyCode 的地方:它的免费模型访问覆盖了支持模型的候选端比较,免费服务器选项意味着运行器本身——提取、评分、结果存储——不需要我付费买机器或占用笔记本。实际效果是"在采纳之前评估新热门模型"不再是成本决策,而是变成了一种习惯。
两个诚实的警告。首先,"免费"层会变——把这当作现在跑评估的一种方式,而不是永久补贴,让 harness 保持 provider-agnostic(我的只是读取一个 env var 作为 endpoint),这样你一个下午就能迁移。其次,免费访问决定了你能够用这种方式做金丝雀测试的模型范围;如果实际上你想测的模型不在那里,在付费 endpoint 上跑一个更小的任务集,而不是完全跳过评估。
一旦模型通过了金丝雀测试,我仍然不会把所有流量都路由过去。整个练习的输出是一张路由表,不是一个赢家:
| 场景 | 路由决策 |
|---|---|
| 通过金丝雀 + 无历史类型冲突 | 逐步灰度:5% → 20% → 50% |
| 通过金丝雀 + 有历史类型冲突 | 只跑新任务类型,不碰现有工作 |
| 软失败(scope creep) | 降级到 5% 或审查模式 |
| 硬失败(malformed diff) | 立即摘除,不路由任何流量 |
三十个 commit 是一个有结构的 vibe,不是统计学。它能 catch 重大回归和格式破坏。它 catch 不了 3% 的质量下降,也没法比较两个都好的模型。
你的历史不是你的未来。如果你要规划的新工作(新语言、新的服务形态)不在 commit 窗口里,金丝雀测试告诉不了你任何关于它的信息。从你实际要工作的仓库里提取任务。
参考 diff 不是 ground truth。人类 commit 本身也可能只是一般。你在测试的是"它能做形状像我工作一样的任务吗",而不是"它是否正确"。
如果你的量很小就不要费这个事。如果你一周只跑几个 agent 任务,评估开销超过任何合理的节省——直接用你信任的模型。这个方法在你要路由真实流量或者你的团队准备标准化到一个模型的时候才值得。
永远不要在历史里有 secrets 的仓库上做金丝雀测试,并且把候选模型的沙箱锁定到跟你锁定任何 agent 一样严密。
上面的 harness 就是全部了——提取脚本、评分器、表格。如果你想找一个零成本跑第一轮的地方,MonkeyCode 的免费服务器和免费模型访问是一个合理的起点;这些脚本不关心在哪里运行。
更重要的一点:模型发布是一个营销事件,而你的 git 历史是唯一知道你工作实际长什么样的 benchmark。两小时的金丝雀测试比一次静默的 diff 损坏要便宜。