上周五晚上 11 点,线上告警群炸了。一个支付回调接口返回 500,排查下来是 Claude 帮我写的一段金额校验逻辑——parseFloat 处理精度丢失,0.1 + 0.2 !== 0.3 这种经典坑,AI 写得一本正经,我 Review 时也没细看就合了。
说实话,这事之后我反思了很久。不是 AI 写得不好,而是我太信任单一模型的输出了。
先说结论
| 方案 | 发现 bug 数(同一段代码) | 耗时 | 成本 |
|---|---|---|---|
| 人工 Review | 2-3 个 | 30min | 免费但费脑子 |
| 同模型自查(让 Claude 检查 Claude 的代码) | 3-4 个 | 10s | ~$0.05 |
| 多模型交叉 Review(Claude + DeepSeek + GPT-4o) | 8-12 个 | 30s | ~$0.15 |
没错,多模型交叉 Review 的 bug 发现率是同模型自查的 3 倍左右。这不是我编的,Zylos Research 今年 2 月发的论文也验证了这个结论。
为什么同一个模型查不出自己的 bug?
原理其实很简单——系统性盲区。
每个模型的训练数据和架构不同,导致它们犯错的模式是相关的。就像你写完一篇文章自己检查错别字,怎么看都觉得没问题,但别人一眼就能看出来。
Claude 擅长逻辑推理但容易过度设计,DeepSeek 代码生成快但边界处理粗糙,GPT-4o 全面但有时候会编一些不存在的 API。让它们互相 Review,就是利用各自盲区不重叠的特性。
我实际测下来的数据:
- 第 1 轮:抓到 60-70% 的问题(逻辑错误、crash 级 bug)
- 第 2-4 轮:抓到修复引入的新 bug(对,改 bug 会引入新 bug)
- 第 4 轮之后:边际递减明显,基本就是风格建议了
完整代码:30 行 Python 搞定多模型交叉 Review
废话不多说,直接上代码。核心思路:A 模型写代码 → B 模型 Review → C 模型仲裁。
from openai import OpenAI
# 用聚合 API 的好处是不用管理 3 套 key
# 我目前用的 ofox.ai,改个 model 参数就能切模型
client = OpenAI(
api_key="your-api-key",
base_url="https://api.ofox.ai/v1"
)
def cross_review(code: str, models: list[str] = None) -> dict:
"""多模型交叉 Review"""
if models is None:
models = ["claude-sonnet-4-20250514", "deepseek-chat", "gpt-4o"]
review_prompt = f"""作为代码审查员,请检查以下代码的问题:
1. 逻辑错误和边界情况
2. 安全漏洞(注入、越权等)
3. 性能问题
4. 错误处理缺失
只输出发现的问题,按严重程度排序。没有问题就说LGTM。
\`\`\`
{code}
\`\`\`"""
results = {}
for model in models:
resp = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": review_prompt}],
temperature=0.1 # 低温度保证结果稳定
)
results[model] = resp.choices[0].message.content
return results
def arbitrate(code: str, reviews: dict) -> str:
"""让第三方模型仲裁,合并去重"""
review_text = "
".join(
f"=== {model} 的审查结果 ===
{result}"
for model, result in reviews.items()
)
resp = client.chat.completions.create(
model="claude-sonnet-4-20250514", # 仲裁用推理能力强的
messages=[{"role": "user", "content": f"""以下是 3 个不同 AI 模型对同一段代码的审查结果。
请合并去重,按严重程度排序,标注哪些问题被多个模型同时发现(高置信度)。
原始代码:
\`\`\`
{code}
\`\`\`
审查结果:
{review_text}
输出格式:
🔴 严重(多模型确认):...
🟡 中等:...
🟢 建议:..."""}],
temperature=0.1
)
return resp.choices[0].message.content
用法很简单:
code = open("my_module.py").read()
reviews = cross_review(code)
final = arbitrate(code, reviews)
print(final)
实测:拿一段「看起来没问题」的代码跑一下
我拿之前那段支付回调代码测试:
def verify_payment(amount_str: str, expected: float) -> bool:
amount = float(amount_str)
return amount == expected
看起来人畜无害对吧?三个模型的审查结果:
Claude 发现的:
- 🔴 浮点精度问题:
float比较不应该用==,应该用Decimal或容差比较 - 🟡 缺少输入校验:
amount_str可能不是合法数字
DeepSeek 发现的:
- 🔴 浮点精度问题(和 Claude 一样)
- 🟡 没有处理负数金额
- 🟢 函数命名建议改成
validate_payment_amount
GPT-4o 发现的:
- 🔴 浮点精度问题(三个都发现了,高置信度)
- 🟡
amount_str为空字符串时会抛ValueError - 🟡 没有金额上限校验,可能被恶意传入超大值
- 🟢 建议加 type hints 和 docstring
仲裁结果:
🔴 严重(3/3 模型确认):浮点精度问题,用 Decimal 替代 float
🟡 中等:缺少输入校验(空字符串、非数字、负数)
🟡 中等:缺少金额上限校验
🟢 建议:命名优化 + type hints
一个 3 行的函数,被扒出 4 个实际问题。如果只用一个模型 Review,大概率只能发现浮点精度这一个(因为它太经典了)。
踩坑记录
1. 不要用同系列模型交叉 Review
一开始我用 Claude Sonnet + Claude Haiku + Claude Opus 做交叉 Review,效果很差。同家族模型的盲区高度重叠,等于换了三个马甲的同一个人在 Review。
2. temperature 不要设太高
设成 0.7 的时候,DeepSeek 开始编一些不存在的安全漏洞,比如声称某个标准库函数有 CVE(查了根本没有)。设 0.1-0.2 比较稳。
3. 代码太长要分段喂
超过 500 行的文件直接丢进去,模型注意力会分散,容易漏掉中间部分的 bug。我的做法是按函数拆分,每个函数单独 Review。
4. 成本控制
三个模型跑一轮大概 60-120。对比人工 Review 的时间成本,这个钱花得值。
如果想省钱,可以先用便宜模型(DeepSeek)做初筛,只有发现问题的代码段再上贵的模型(Claude)做精审。
小结
AI 写代码的速度已经够快了,瓶颈反而在怎么确认这代码能上线。单模型 Review 有系统性盲区,多模型交叉 Review 是目前性价比最高的方案。
核心就一句话:写代码用一个模型,Review 用三个。
至于 Anthropic 上周刚发的官方 Code Review 工具,我还在测试,等跑够数据再写一篇对比。但不管工具怎么变,多模型交叉验证的思路是通用的——毕竟谁也不希望晚上 11 点被告警群叫醒。