质量实测
ocra 在黄金用例和 AACR-Bench 上找到了什么、漏掉了什么,是怎么测的,以及这些数字说明不了什么。
这一页汇报 ocra 的评测运行到目前为止测到了什么、是怎么计分的,以及这些结果的局限。样本很小,所有运行也都只用了一个模型家族,引用任何数字之前请先读局限。
在 8 个改动、16 个已知问题上,当前配置唯一的一次运行找到了 7 个(44%),报出的 7 条问题全部正确。用例定为 warning 的 6 个问题中找到 5 个,定为 suggestion 的 10 个中找到 2 个。请把 ocra 当作第二位审查者:认真看它报出的问题,但不要把空报告当成"没问题"。
怎么测的
ocra-eval 在固定到具体提交的改动上运行真实的 ocra review,再给它报出的问题计分(运行方法见评测)。数据集有两个:
- 黄金用例(ADR-0011)由 ocra 自己维护。每个用例把一个公开仓库固定在两个提交上,列出 ocra 必须报出的问题、同一个问题也可以正确报在的其他位置、报了就算错的范围,或者注明这次改动没有任何问题。到目前为止的每次运行,用的都是 smoke 档当时的 8 个用例,现在共有 16 个预期问题。此后 smoke 档增加到 10 个用例,full 档增加到 16 个;两者都还没有按现在的样子跑过。
- AACR-Bench 是外部基准,由真实 PR 组成,标准答案是人工评审留下的评论。它的数字可以和已公开的结果对比。
| 这些运行用的 8 个用例 | 用例 | 预期问题 | 语言 |
|---|---|---|---|
| 来自 ocra 自身历史的改动:后来修复的 bug,外加一个没有问题的改动 | 4 | 7 | TypeScript |
| AACR-Bench 的 PR,问题都对照代码核实过 | 4 | 9 | C#、C++、Go、TypeScript |
在黄金用例上,一条问题与某个预期问题匹配的条件是:在同一个文件里,与预期的行号或某个其他位置相距不超过一行,并且判定模型确认它说的是同一个问题。
- 召回率:找到的预期问题所占的比例,严重程度要达到用例要求的下限。
- 精确率:报出的问题中,匹配预期问题或被标为有效的比例。没有匹配任何预期问题的,会对照代码核查一次并标为有效或无效,标注和用例存在一起;标注之前一律算错。
- 落在标明"报了就错"的范围内,或出现在没有问题的改动上的 critical,算作失败。目前还没有一次运行出现过。
AACR-Bench 用基准自己的匹配规则:同一文件、diff 的同一侧、相距不超过一行,再由判定模型确认。它的精确率是命中数除以报出数,不用标注。
所有运行都用 Vertex AI 上的 Gemini:审查员和核查用 gemini-3.5-flash(降级到 gemini-3.5-flash-lite),裁决(Judge)用 gemini-3.1-pro-preview,轻量任务用 gemini-3.5-flash-lite,计分时判定是否匹配用 gemini-flash-lite-latest。花费是 ocra 自己的记账:token 数乘以各模型的标价。
黄金用例
当前配置
2026-09-29(UTC)运行一次,使用 ocra 的默认设置,版本是 main 上的 664c850,加上紧随其后合并的"每个审查 agent 30 步"上限(f966d83):
- 16 个预期问题找到 7 个(44%):用例定为 warning 的 6 个中找到 5 个,定为 suggestion 的 10 个中找到 2 个。没有用例预期 critical 级别的问题。
- 报出 7 条问题,全部正确(7/7,100%),在没有问题的改动上什么都没报。
- 8 个改动共花费 $12.53:平均每个 $1.57(中位数 $1.15,最低 $0.07,最高 $3.98)。一次审查耗时的中位数是 243 秒,90 分位是 437 秒。
找到的问题:头文件里的声明和调用方与定义对不上,导致无法编译(FreeCAD,C++);测试里的 monitor 容器仍然拉取公共镜像,而 server 容器已经改用镜像站的镜像(ASP.NET Core,C#);文件在父目录创建之前就被创建(Ollama,Go);导入了模块并未导出的名字,导致构建失败(RAGFlow,TypeScript);以及 ocra 历史上的三个 bug:文档承诺会写入的 .gitignore 实际上没有任何代码写入、一个辅助函数被注册成了插件、模型写的文字仍可借助引用式 Markdown 链接在 PR 评论里生成可点击的链接。
漏掉的问题:ocra 历史上的四个 bug(git index 的临时副本带着新的修改时间,导致与真实 index 同一秒内修改的文件看起来没变,被排除在审查之外;阻断性结论在新增的覆盖检查之前就返回了;未变更的文件被算作未审查;一个审查员失败、而另一个审查员已经审完同样的文件时,这次运行被算作什么都没审查),Ollama 里四个较小的校验、错误处理和测试问题,以及 RAGFlow 里缺失的翻译键。
预期问题从哪里来
召回率取决于预期的是哪些问题。16 个中有 4 个是在任何运行之前、根据 ocra 历史上修复过的 bug 写下的,当前配置找到了其中 2 个。另外 12 个是某次 ocra 运行报出、又对照代码核实之后才加进来的:5 个来自在 AACR-Bench PR 上的运行,7 个来自在这些用例上的运行,其中一个就是上面这次运行。在这 12 个问题上,召回率衡量的是 ocra 能否再次找到它以前找到过的问题;它找到了 5 个。
每一次运行
这 8 个用例上的全部运行,都按今天的用例和标注重新计分,因此可以相互比较。更早的三次运行只跑了其中最初的 4 个用例,每次都在这 4 个用例的 7 个预期问题中找到 1 个,报出的问题都正确。只用来检查流程是否跑通、或只在几个 AACR-Bench PR 上比较某个改动的运行,没有列在这里。
| 日期(2026 年,UTC) | 配置 | 找到 | 精确率 | 每个改动的花费 |
|---|---|---|---|---|
| 09-28 | 每个审查 agent 20 步 | 6/16(38%) | 6/7(86%) | $1.16 |
| 09-28 | 同上,再跑一次 | 6/16(38%) | 7/7(100%) | $0.97 |
| 09-28 | 每个审查 agent 30 步 | 7/16(44%) | 7/8(88%) | $1.06 |
| 09-28 | 同上,再跑一次;8 个改动中跑了 7 个(花费上限) | 8/15(53%)¹ | 8/9(89%) | $1.77 |
| 09-28 | 20 步,加上防提示注入的边界 | 4/16(25%) | 4/5(80%) | $1.33 |
| 09-29 | 当前配置 | 7/16(44%) | 7/7(100%) | $1.57 |
| 09-29 | 稍后的 main,加上一个没有合并的提示词改动 | 6/16(38%)² | 8/9(89%) | $1.26 |
¹ 第 16 个预期问题就取自这次运行。
² 另有一个预期问题被找到,但严重程度低于用例的要求。
跑过两次的两种配置,两次找到的问题数大致相同(6 和 6,7 和 8),精确率相差一条问题。两次运行不足以看出真实的波动,所以不同配置之间相差一两个问题,应当视为噪声。
AACR-Bench
10 个 PR(--seed 1 --limit 10 --max-change-lines 300:每个最多改动 300 行,共 44 个标注问题),两种配置各跑两次,时间是 2026-09-28,早于当前配置:
| 配置 | 精确率 | 召回率 | 每个 PR 的花费 |
|---|---|---|---|
| 每个审查 agent 20 步 | 4/6(67%);2/5(40%) | 4/44(9.1%);2/44(4.5%) | $0.77;$0.86 |
| 同上,并要求每条问题一经确认就立即报告 | 3/14(21%);3/7(43%) | 3/44(6.8%);3/44(6.8%) | $0.97;$1.02 |
当前配置还没有在 AACR-Bench 上跑过。读这些数字时,要记住这个基准的三个特点:
- 召回率有上限。 在 AACR-Bench 的 94 个 PR 标注的 530 个问题中,40% 是可维护性和可读性方面的意见,ocra 按设计不报这类问题,所以 ocra 最多能覆盖 58%(
ocra-eval ceiling,不调用模型)。 - 精确率被低估。 标准答案是评审者碰巧留下的评论,没人评论过的真问题会被算作误报。对每条问题对照代码做过一次核查(由参与 ocra 开发的 AI agent 完成,没有记录为标注):前两次运行的 11 条问题中,6 条是真实缺陷、4 条是小问题、1 条是错的,而基准只算命中 6 条;后两次运行的 21 条问题中,15 条是真实缺陷、5 条是小问题、1 条是错的,基准同样只算命中 6 条。
- 匹配只容许相差一行。 在一个 Electron 的 PR 上,ocra 报出了标注里的 use-after-free,但位置离标准答案差了十行,于是既算漏报又算误报。正因如此,
ocra-eval会在官方指标旁边给出一个宽松匹配(同一文件里的同一个问题,不论在哪一行)。
花费
这些运行按标价计算:
- 用当前配置审查一个黄金用例,平均花费 $1.57(中位数 $1.15),最低 $0.07,最高 $3.98;
- 用更早的配置审查 AACR-Bench 里较小的 PR,平均每个 $0.77 到 $1.02;
- 所有运行中最贵的一次审查花了 $4.31,改动涉及 10 个文件。
花费随改动的规模,以及风险档位要运行的审查员而增长。--max-cost-usd 可以给一次运行的花费设上限(见 CLI)。
局限
- 样本小。 8 个改动、16 个预期问题,其中只有 4 个是独立于 ocra 自身发现写下的。当前配置只跑过一次,full 档还没有跑过。
- 不独立。 用例和标注都是项目自己的。目前的标注都由参与 ocra 开发的 AI agent 完成,它对照代码核查了每一条问题并记录了理由。另一个模型(Claude Fable 5.1)在不知道原标注的情况下,对照代码重新判断了当时已有的 11 条标注中的 5 条,结论全部一致;项目之外还没有人审阅过。最近的改动(包括 30 步上限)是在这些用例上选定的,这会让当前配置的成绩偏好看。
- 匹配由模型判定。 一条问题是否在说某个预期问题,由
gemini-flash-lite-latest判定。判定结果有缓存,同一次运行重新计分结果不变,但换一个判定模型可能得出不同的结论。 - 只有一个模型家族。 所有运行都用 Vertex AI 上的 Gemini,换成别的模型,成绩会不同。
- 每次运行有波动。 同一配置的两次运行,精确率相差一条问题。
- 召回率是短板。 在这里 ocra 漏掉了一半以上的预期问题,其中大多被定为 suggestion;在 AACR-Bench 上,它命中的标注问题不到 10%。
- 最后一次运行之后的改动还没有测过,其中包括:审查 agent 在看完所有文件之前就停下时,现在会被要求继续一次。
- 不能跨工具比较。 其他工具公开的数字用的是别的数据集、子集、匹配规则和模型。这里的数字只说明 ocra 在自己的用例上表现如何,不代表排名。
对你意味着什么
ocra 能找到真实的 bug,到目前为止也很少误报,但它漏掉的问题比找到的多。把它当作人工审查之外的第二位审查者,而不是门禁:认真看它报出的问题,但不要把空报告当成"没问题"。它给出的结论只是参考意见,不是安全检查(见工作原理)。
复现
用例和标注都在 evals/golden。按评测配置好模型后,在上面这 8 个用例上跑一次按标价要花 $8 到 $13;smoke 档现在有 10 个用例:
node packages/eval/dist/main.js run --dataset golden --tier smoke --label mine --max-cost-usd 20 --pr-max-cost-usd 6