7 档模型审同一份带 bug 的代码:一次 PR 的总账从 ¥0.0007 到 ¥0.4048,附单变量 harness 与 5 个真坑

起点是一句没人回答的质疑

V2EX t/1239395:"单看每百万 Token 多少钱没意义,应该看同一件事最后到底花多少钱、还有花多长时间。"我自己埋了 bug 搭了套 harness 跑了一遍,单价差 40 倍,一次审查的总账差 545 倍。

为什么要自己搭 harness

代码审查这个赛道现在的公开数据分两类。一类是工具方自测,precision、F1、token 降幅,都是项目自己跑自己报。另一类是转述,把自测数字换个说法再发一遍。

两类都缺同样的东西:金额和秒数。按百万 token 报价的表和"审一次 PR 花多少钱"之间隔着一整个 usage,没人把它算出来。

要算这笔账,就得让模型成为唯一变量,其它所有能影响输出的东西都得钉死。下面按变量控制、数据、坑三段写。

变量控制清单

维度 固定值 为什么必须钉死
被测代码 同一份 64 行 Python 文件 换个文件难度就变了,分数没法横比
prompt system 与 user 逐字节相同 一句措辞差异就能改变误报率
payload stream=falsemax_tokens=4096 4096 与该 CLI 的 bl text chat 默认值对齐
端点 直连 OpenAI 兼容端点 走 CLI 通道会撞上后面第一个坑
计时 客户端墙钟,发请求到收完响应 含网络往返,这才是用户体感的耗时
取样 每组只跑一次 这是缺陷不是设计,后面会披露两次跑分的差异

max_tokens=4096 这条得说明白:思考模型的 reasoning_tokens 不计入这个上限。qwen3.8-max 设了 4096,实际返回 11,064 个 completion tokens,其中 9,770 个是思考。这是平台行为,不是我的 harness 写错了。

被测代码:4 个真缺陷 + 2 个诱饵

编号 埋的是什么 判定
B1 查用户时不判空,数据库查不到就崩 真缺陷
B2 用户输入直接拼进 SQL 真缺陷
B3 计数器 += 1 没加锁,文件里定义了锁但从未使用 真缺陷
B4 open() 没用 with,异常路径下句柄泄漏 真缺陷
D1 @lru_cache 装饰纯函数 诱饵,正确用法,报它算误报
D2 except Exception: raise 诱饵,裸 raise 恰恰保留原始堆栈,报它算误报

诱饵是必须的。只统计"抓到几个 bug"会把话痨模型排到前面,它报得越多命中越多,但开发者要为每一条误报付出复核成本。

计分口径:得分 = 真阳 + 0.5 × 部分命中 − 误报,满分 4。部分命中指修复代码给对了但诊断说错了病因,qwen-plus 的 B4 就是这种,它写了 with open(...),诊断栏填的却是路径遍历。行号准确率单独记,不混进得分。模型额外报出的真问题也不计分,只作为定性观察。

结果

模型 思考 token 真阳 漏报 误报 得分 耗时 输入 tok 输出 tok 单次 ¥
qwen-turbo 不思考 2/4(B1,B2) 2(B3,B4) 4 -2.0 7.4 秒 468 1,005 0.0007
qwen3-coder-plus 不思考 3/4(B1,B2,B4) 1(B3) 1 2.0 10.1 秒 464 712 阶梯计费,未公开
qwen-plus 不思考 2/4(B2,B3)+ B4 半分 1(B1) 1 1.5 39.3 秒 464 1,766 0.0039
qwen3.7-plus 1,182 4/4 全中 0 0 4.0 23.4 秒 502 2,052 未公开
qwen3.6-flash 4,258 4/4 全中 0 1 3.0 42.6 秒 502 5,075 未公开
qwen3.8-flash 9,517 4/4 全中 0 0 4.0 241.0 秒 540 12,909 0.0353
qwen3.8-flash + 显式 thinking 11,611 4/4 全中 0 0 4.0 227.0 秒 540 14,954 0.0408
qwen3.8-max 9,770 4/4 全中 0 0 4.0 293.1 秒 540 11,064 0.4048

8 组,每组一次。token 全是 API 原样返回的 usage,金额是真实 usage 乘免登录查到的单价。

最后两行的开关对照值得单独看:qwen3.8-flash 默认就在思考,9,517 个 reasoning tokens。显式加 --enable-thinking 之后思考涨到 11,611、输出涨到 14,954、花费从 ¥0.0353 涨到 ¥0.0408,多了 16%,得分一分没变。在这个任务上,显式开思考只买到一张更贵的账单。

三条规律

第一条,得分的分水岭不是价格,是会不会思考。三个不思考的模型得分 -2.0、2.0、1.5,全部有漏报;五个会思考的得分 3.0、4.0、4.0、4.0、4.0,零漏报。

第二条,思考量过了一个点就不再换分。qwen3.7-plus 用 1,182 个思考 token 拿满分,qwen3.8-max 用 9,770 个也是满分。中间那 8,588 个 token 换来的是 12.5 倍耗时(23.4 秒到 293.1 秒)和 5.4 倍输出 token(2,052 到 11,064)。

第三条,行号准确率随档位单调上升。

模型 行号正确率(对 / 报出条数)
qwen-turbo 0 / 9
qwen-plus 0 / 4
qwen3-coder-plus 1 / 5
qwen3.6-flash 2 / 5
qwen3.7-plus 6 / 6(±1)
qwen3.8-flash 全对
qwen3.8-max 全对

turbo 把 SQL 注入报在第 9 行,实际第 18 行;空指针报在第 10 行,实际第 13 行。描述对,位置错。工程含义是便宜档的输出只能当线索清单,不能当定位结果接进跳转逻辑。

还有一条必须披露的:同一模型跑两次,得分会变。首轮走 CLI 通道时 qwen-turbo 是 -2.5(漏了 B1),本轮 -2.0(抓到了 B1);qwen-plus 首轮 2.0(B4 算全中),本轮 1.5(B4 只给对修复)。这是"每组只跑一次"的直接后果,所以下面所有结论都带"这一次实测"的限定,不外推成某个模型就是或就不是这个水平。

成本对账

单价来自 bl model list 免登录实跑,单位元/百万 tokens:

模型 输入 输出 缓存命中输入
qwen-turbo 0.3 0.6 0.06
qwen-plus 0.8 2 ---
qwen3.8-flash 0.8 2.7 0.1
qwen3.8-max 12 36 1.5

把真实 usage 乘上去:

模型 审一次 1 元可审 审 100 次 每天 10 次 × 22 工作日
qwen-turbo ¥0.0007 ≈1,345 次 ¥0.07 ¥0.16
qwen-plus ¥0.0039 ≈256 次 ¥0.39 ¥0.86
qwen3.8-flash ¥0.0353 ≈28 次 ¥3.53 ¥7.76
qwen3.8-flash + 显式 thinking ¥0.0408 ≈24 次 ¥4.08 ¥8.98
qwen3.8-max ¥0.4048 ≈2 次 ¥40.48 ¥89.05

输入单价差 40 倍(0.3 对 12),单次总账差 545 倍(0.000743 对 0.404784)。差额不在单价上,在思考烧掉的 9,770 个输出 token 上。开头那句质疑被这组数字原样证实了。

三个模型的单价查不到:qwen3-coder 系列官方文档写明采取阶梯计费,qwen3.7-plusqwen3.6-flashbl model list 里没返回价格。查不到就不编,改用不等式。即使 qwen3.7-plus 与旗舰完全同价(12/36),这一次审查也只花 (502×12 + 2052×36)/1e6 = ¥0.0799,是旗舰 ¥0.4048 的 1/5.1;而它的实际单价不可能高于旗舰。这个下界是硬的,比任何估算都有用。

harness 里的 5 个坑

这几个坑都会让你的成本数据静默失真,不报错,最麻烦。

坑一,undici 的 300 秒响应头上限。本机用 bl text chat 非流式调 qwen3.8-max 会撞 Node undici 的 300s 响应头上限,实测 293.1 秒已经贴着这条线。表里的耗时改用直连端点测得。如果你要用该 CLI 跑旗舰档,加 --stream;但 --stream--output json 不返回 usage,成本得另算。这是"旗舰档慢"的硬证据,不是我的网络问题。

坑二,--messages-file 要的是 messages 数组。写成 {"messages":[...]} 会报 i is not iterable,报错信息完全指不到根因。正确的形状长这样:

json 复制代码
[
  {"role": "system", "content": "你是代码审查器"},
  {"role": "user", "content": "审查下面这份代码......"}
]

坑三,--page-size 100 静默返空。bl model list --page 1 --page-size 20 正常,--page-size 100 返回 items: [],不报错。批量抓单价的脚本要是用了大 page-size,会得到一张空表,然后以为这些模型没价格。同理 --output 只接受 textjson,写错值静默回落 text。

坑四,reasoning_tokens 不受 max_tokens 约束。工程含义是你没法靠 max_tokens 给思考模型封顶成本,得靠 --thinking-budget,或者直接换档。

坑五,同一份代码在不同模型下 prompt token 数不同。表里是 464、468、502、540,因为分词器不同。这也是"按百万 token 单价直接横比"不严谨的另一个原因,必须用真实 usage 算,不能用理论 token 数。

换成生产工具:ocr 的配置面

自己搭 harness 适合做实验,日常审 PR 得用现成工具。alibaba/open-code-review(命令名 ocr,Apache-2.0)v1.12.1 在 9 月 14 日发布,今天 GitHub Trending 日榜第 2,26k stars。

它内置 28 个 provider,其中一个叫 dashscope,端点是 https://dashscope.aliyuncs.com/compatible-mode/v1,预置模型列表前 5 个全是 qwen。也就是说接百炼不用写自定义 provider。

bash 复制代码
npm install -g @alibaba-group/open-code-review

前置依赖:Node.js 与 Git ≥ 2.41。

API Key 在控制台的密钥管理页创建,新账号会自动带上各模型的免费额度。额度口径按官方文档:每个模型独立、通常 100 万 Token、90 天有效期、仅华北2(北京)地域、过期不补发、用尽不会自动切换到别的模型。

非交互式配置三行,CI 里也是这三行:

bash 复制代码
ocr config set provider dashscope
ocr config set model qwen3.7-plus
ocr config set providers.dashscope.api_key sk-你的key
ocr llm test

配置字段名容易写错:Base URL 的字段是 url 不是 base_url,key 是 api_key,当前生效模型是单数的 model,复数的 models 只是 TUI 选择器的候选列表。内置 provider 挂在 providers.<name>.* 下,自定义的挂在 custom_providers.<name>.* 下,两个 map 不通用。配置文件在 ~/.opencodereview/config.json

两个容易踩的点。其一,只 export DASHSCOPE_API_KEY 不够,resolver 要求 (url, token, model) 三元组齐全,环境变量只补 token 那一份。其二,别拿 Anthropic 兼容端点配 thinking 模式,issue #1064 报过 400:The tool_choice parameter does not support being set to required or object in thinking mode。该 issue 已关闭但没有维护者说明,所以我只说实测路径:走内置的 dashscope,OpenAI 兼容协议,没这事。

审查命令面:

bash 复制代码
ocr review                                    # 工作区模式,审 staged/unstaged/untracked
ocr review --from main --to feature-branch    # 分支区间,merge-base 模式
ocr review --commit abc123                    # 单个提交
ocr review --format json --output result.json # 结果落文件,方便接门禁
ocr scan --path internal/agent                # 全文件扫描,不依赖 git 历史

模型有个硬要求:必须原生支持 tool calling。ocr 完全靠工具调用驱动审查,只在文本里"叙述"工具调用的模型(比如 deepseek-r1)无论怎么调 prompt 都跑不通。官方 FAQ 点名 qwen3 可用,我这边核到 bl model list --model qwen3.7-plus --output jsonfeatures 里确实含 function-calling

场景到档位的映射

场景 档位 单次成本 依据
pre-commit 粗筛 qwen-turbo ¥0.0007 7.4 秒返回,能抓注入这类明显问题;4 条误报,当提醒不当结论
日常 PR 审查 qwen3.7-plus 这一档 单价未公开,输出 2,052 tok,上界 ¥0.0799 23.4 秒满分,本次实测的性价比拐点
安全相关、合并门禁 qwen3.8-max ¥0.4048 会报出埋点之外的真问题,行号可直接跳转
结论存疑时交叉复核 两个便宜档各跑一遍 两次便宜档的钱 这次 plus 漏 B1、coder-plus 漏 B3,漏报不重叠

最后一行是观察不是结论,7 组样本撑不起"交叉互补"这个普适判断,需要在你自己的代码上复验。而且误报会叠加,复核成本要一起算进去。

什么时候别接进流水线

先算时间账。V2EX 上有人实测 1,400 个 PR 跑了十多个小时,几行改动的小 PR 也要几分钟。这不是秒级工具,挂在同步阻塞的 pre-commit 上会被人骂。

也别指望它替代静态扫描。规则引擎报的是确定命中的模式,它报的是读懂代码之后觉得不对的地方,覆盖面不重合。

旗舰档不要挂在每次提交上。一次 ¥0.4048、293.1 秒,两个维度都撑不住高频调用。

复算脚本

单价和 token 都能自己核:

bash 复制代码
bl model list --model qwen-plus --output json    # 单价,免登录
bl quota list --model qwen-turbo                 # 限流,API Key 鉴权即可

token 在每次调用返回的 usage.prompt_tokensusage.completion_tokens 里。算钱用 Decimal,别用 float:

python 复制代码
from decimal import Decimal, ROUND_HALF_UP

def cost(in_tok, out_tok, price_in, price_out):
    """price 单位:元/百万 tokens"""
    c = (Decimal(in_tok) * Decimal(price_in) + Decimal(out_tok) * Decimal(price_out)) / Decimal(1000000)
    return c.quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)

print(cost(502, 2052, "12", "36"))   # 即使按旗舰单价算,qwen3.7-plus 这一次也只花 0.0799

Python 的 round() 是银行家舍入,算钱会得到反直觉的结果,所以这里显式指定 ROUND_HALF_UP

小结

这次 8 组数据能确定的是三件事:满分出现在 23.4 秒那一档而不是 293.1 秒那一档;决定漏报与否的是会不会思考,不是单价;单价差 40 倍可以对应总账差 545 倍,因为思考 token 计入输出计费。

不能确定的是外推。每组只跑一次,同一模型两次跑分已经观察到差异;样本是一份 64 行的 Python,复杂仓库上拐点会不会右移,这次没测。下一步是把 ocr review --format json 接进 CI 当合并门禁,用真实 PR 复算一遍时间与金钱两个维度。

适用边界也说清楚:已经在用 Copilot 或 CodeRabbit 订阅、流水线跑得也顺的,这套方案解决的不是同一类问题。它面向的是需要自主指定模型底座、并且要按档位核算单次成本与耗时的场景。

实验材料(64 行被测代码、答案卷、计分脚本、8 组原始输出含 usage 与墙钟耗时)都在 source/lab/ 下,金额一律由真实 usage 乘免登录实跑单价得出,未返回单价的模型标注"未公开",不做估算。

相关推荐
liukuang1101 小时前
WorkBuddy、千问办公、TRAE Work、百度搭子:四大AI办公硬碰硬
人工智能
大模型真好玩1 小时前
仅需3轮对话,Seed-Evolving大模型帮我创造出 “知识跳动”——一个智能化时代的知识学习系统!
人工智能·agent·豆包marscode
IvorySQL1 小时前
AI 时代,PostgreSQL 正在发生什么变化?
数据库·人工智能·postgresql
学习日记5251 小时前
AI PPT生成系统实践:从自由生成到可控生成的工程演进复盘
人工智能·ai·prompt
用户3705743608391 小时前
Claude Agent SDK 和 LangGraph 都用过之后,我发现选型先问一个问题
人工智能
资讯综合1 小时前
2026 高精度 AI 3D 模型生成工具实测对比:Hyper3D 、Tripo、Meshy 谁更适合生产级管线?
人工智能
2601_963749101 小时前
越华环保集团污水云边协同自控架构:边缘 PLC 闭环与断网自治实现方案
人工智能
用户5274675614211 小时前
给岗位Agent试岗,别只看它说了什么
人工智能