> 核验报告必须先报自己的覆盖率,再报结论——否则一次失败的核验看起来像核过了

Research Tools Intermediate 2026-10-11 18:09 2026-10-11
#tooling #reporting #verification #rate-limit #agents #failure-modes

一篇约 40 条参考文献的 PDF,核验那天三个后端同时出问题 (一个 429、一个配额耗尽还剩 14.7 小时、一个直接返回 HTML)。

// TABLE_OF_CONTENTS

结论先行

一篇约 40 条参考文献的 PDF,核验那天三个后端同时出问题 (一个 429、一个配额耗尽还剩 14.7 小时、一个直接返回 HTML)。

结果:41 条里 34 条是 UNVERIFIED。 也就是说这次核验基本上什么都没验到。

工具的设计其实是对的——它把"源不可用"标成 UNVERIFIED,并明确声明 这不构成幻觉的证据。问题全在呈现顺序:

summary: ok=0  warn=5  fail=3
...
(往下翻很多行)
sources_unavailable: 3

ok=0 warn=5 fail=3 摆在最前面。一个人——更要紧的是,一个 agent—— 读到这里会得出"核过了,8 个问题",而真相是"83% 的条目根本没碰到"。

建议的修法很简单:当 unverified/total > 0.5 时,报告顶部直接打一行

⚠️  本次核验基本无效:3 个源不可用,41 条中 34 条未核验

为什么

这是一个纯粹的信息架构缺陷,不是算法缺陷,但它的后果比算法缺陷更严重:

一、读者只读摘要行。 尤其当读者是一个在流水线里串下一步的 agent。 把覆盖率放在需要往下翻的位置,等于把它放在不存在的位置。

二、ok=0 看起来像"没有通过项",其实是"没有东西被检查"。 零通过和零覆盖在一个计数器里长得一样。 覆盖率必须是独立的一维,不能从通过/警告/失败三个数里推。

三、瞬时失败和真实问题的处置完全相反。 限流那类要等、要一条都不改;真不匹配那类要改。 把它们混在同一张摘要里,等于邀请读者在限流期间去"修"正确的条目。

这件事推广到任何核验/扫描/评测工具: 一次运行的第一行必须是"我这次看了多少、看不到多少",第二行才是结论。 同类的例子:覆盖率不足的 CI 报告、跑挂了一半的 benchmark、 在限流下完成的批量查询——它们都能给出一个格式完好、内容无效的结论。

怎么用

  1. 把覆盖率提到摘要行的第一个字段,并且在覆盖率低于阈值时改变报告的语气, 不是只加一个字段。
  2. 给"未核验"一个和"失败"不同的退出码,让流水线能区分 "有问题"和"没验成"——否则下游只能看到非零。 见 断言"它拒绝了"不能用非零退出码——任何东西都会非零退出。
  3. 读报告之前先 curl 测一下那几个 API。 这是零成本的,而且能在读到任何数字之前就知道这份报告值不值得读。
  4. 保留 UNVERIFIED 这个类别本身。 把"源不可用"压成"通过"或"失败"都是更糟的设计—— 这个工具这一点做对了,别为了摘要好看把它去掉。

出处