AB
AiBoss
Tutorials

用捕获-重捕获法估算 AI Agent 漏掉了多少字段

Tutorials

用捕获-重捕获法估算 AI Agent 漏掉了多少字段

当两个信息源(两张地图、两个 Agent、Agent 与 LLM 裁判)共享同一批盲区时,它们的一致会制造虚假信心。本教程用 Chapman 估计量与二阶 jackknife,从「谁找到了哪一条」的重叠矩阵出发,估算所有来源都没找到的条目数量,并用带完整标注的合同数据集演示如何校验这个估计。

当你用两个来源去覆盖同一批对象时,很容易以为「两边都查过了,应该差不多了」。但两个来源如果共享同一批盲区,它们的一致恰恰是最危险的信号。本教程讲的就是如何用捕获-重捕获(capture-recapture)的思路,从「哪个来源找到了哪一条」的重叠情况,反推所有来源都没找到的条目有多少——并把它用在 AI Agent 的召回率评估上。

适合的读者:正在做 Agent 抽取类任务(合同字段、条款、表单、文档信息)并需要回答「它到底漏了多少」的工程师;以及任何需要评估两个信息源合并后覆盖率的人。核心工具只有两个:一个五行的 Chapman 估计量,和一个需要多来源计数的二阶 jackknife 估计量。

准备工作

开始之前,先把下面几件事想清楚,否则算出来的数字没有意义。

1. 明确「条目」是什么

估计的对象必须是可枚举、可匹配的个体。在森林地图的例子中,条目是「面积 100 公顷以上的具名针叶林」;在合同 Agent 的例子中,条目是「某一类条款在合同中的一次出现」。条目定义得越模糊,重叠匹配越不可靠,估计值就越没有参考价值。

2. 至少两个来源,且来源之间要尽量独立

两个来源可以是两张地图、两个不同厂商的模型、同一个模型跑两次、或者「Agent + 关键词规则」。独立性是整个方法的地基:一个来源找到某条目,不应该显著改变另一个来源找到它的概率。这一点无法完全验证,只能通过选择差异大的来源来近似。

3. 一套匹配规则

你需要判断「来源 A 的第 i 条」和「来源 B 的第 j 条」是不是同一个条目。素材中的做法是:两段文本的重叠部分至少达到较短文本的一半,就算命中同一条款;没有逐字照抄原文的引用,用模糊匹配定位。匹配规则要在跑估计之前定好,不能事后调整。

4. 一个 0/1 矩阵

最终喂给估计量的是一张矩阵:行是「至少被一个来源找到的条目」,列是各个来源,单元格为 1 表示该来源找到了这一条。Chapman 估计量只需要三个数:来源 1 找到多少(n1)、来源 2 找到多少(n2)、两者都找到多少(m)。jackknife 需要整张矩阵,因为它要看「只被 1 个来源找到」和「恰好被 2 个来源找到」的条目数。

5. 可选的答案键

如果你手上有一份人工标注完整的集合,就能校验估计值。素材用的是 CUAD 数据集:510 份商业合同,律师逐条标注了 41 类条款。从中取约 10,000 token 以下的 294 份合同、10 类可能在一份合同中多次出现的条款(如许可授予、责任上限、禁止转让、审计权),得到 1413 条已标注条款,作为所有估计值的对照真值。没有答案键也能用这个方法,只是你无法知道当天算出来的数字偏了多少。

操作步骤

步骤一:统计两个来源的发现数与重叠数

先跑两个来源,把结果按匹配规则对齐,数出三个整数。素材中的森林例子是:OpenStreetMap 找到 1052 片,Ordnance Survey 找到 1190 片,两者都有的 727 片。合同场景中,则是「Agent A 找到的条款数」「Agent B 找到的条款数」「两者都找到的条款数」。

步骤二:套用 Chapman 估计量

Chapman 在 1951 年给 Lincoln-Petersen 估计量加了一个小样本修正,让重叠很小时结果更稳定。整个估计器只有五行:

def chapman(n1, n2, m, z=1.96):
    """Estimate the total from two independent catches.
    n1, n2: items found by each source; m: items found by both."""
    N = (n1 + 1) * (n2 + 1) / (m + 1) - 1
    var = (n1 + 1) * (n2 + 1) * (n1 - m) * (n2 - m) / ((m + 1) ** 2 * (m + 2))
    return N, N - z * var ** 0.5, N + z * var ** 0.5

N, lo, hi = chapman(n1=1052, n2=1190, m=727)

森林例子得到总量约 1722,95% 区间为 1678 到 1765。两个来源合计只覆盖了 1515 片,也就是说估计有约 207 片、约 12% 的森林两个来源都没找到。

直觉上可以这样理解:把每个来源想成一张网,重叠部分就是「被两张网都捞到的鱼」。重叠越小,说明每张网的覆盖越不完整,未被捞到的总量就越大。这也是为什么估计值对 m 极其敏感——m 稍有偏差,N 就会明显移动。

步骤三:检查独立性假设是否被破坏

这一步没有公式,只有判断。素材列出了两种典型失效方式:

  • 著名条目问题。有些条目在所有来源里都更容易出现。如果某些条目对两个来源都更容易被发现,重叠 m 会偏大,估计出的总量 N 会偏小。此时 12% 只是下限,真实缺口可能更大。
  • 来源各有专长。志愿者可能偏爱公园与自然保护区,国家测绘机构可能更常收录人工林地块。如果两个来源各自擅长不同类别,重叠 m 会偏小,估计出的总量 N 会偏大。

素材做了一个小规模检查:在另外一项测试中挑出的 18 片知名森林里,有 10 片同时出现在两张地图上,占 56%,而全体森林的重叠率是 48%。这略微指向「著名森林更容易被找到」,但 18 个样本太小,不足以得出确定结论。这个检查的思路值得借用:挑一批你确信「重要、显眼」的条目,单独算一次重叠率,和整体重叠率对比。

步骤四:把估计量用在 Agent 对上

把每个 Agent 当成一张网。素材把 9 个 Agent 排成一个「阶梯」,从几乎互为副本的配置,到差异很大的配置,并按价格把两个模型家族配对。整轮跑完 294 份合同、9 个 Agent,花费 14.71 美元。

对每一对 Agent 跑一次上面的五行估计器,与真值 1413 比较,结果呈现出清晰的规律:

配对类型估计值范围相对真值
同一模型跑两次约 1102低约 22%
同一家族的两个模型1149 – 1243偏低
不同家族的两个模型1173 – 1258偏低,但更接近
包含关键词规则的配对与上者大致相当偏低

最值得注意的是误差棒。同一模型跑两次时,报告出的区间只有正负 3 条左右,而答案本身已经显著低估了真值。原因是这个区间只度量抽样噪声,对共享盲区一无所知:两个高度一致的 Agent 会给出一个既偏低又「非常自信」的估计。

在常规评估里,Agent 与裁判高度一致通常被当作好兆头;在这个设定下恰恰相反。另外,素材发现两个 OpenAI 模型之间的相似度并不比跨厂商配对高多少,而 Claude 系列模型之间明显更相似。所以「同家族」并不对应一个固定的相似度,具体模型组合的相似程度值得单独测量。仅靠更换厂商也不够——即使差异最大的配对,估计值仍偏低约 10%。

步骤五:来源多于两个时改用 jackknife

生态学家早就遇到过同样的问题:有些动物就是比其他动物更容易被捕获。他们因此发展出使用两次以上捕获、并考察「被看到一次、两次、三次……」的估计方法。软件工程领域后来用同样的模型估计代码审查后还剩多少缺陷,结论是少于四名审查者时没有哪个模型足够准确,低估可能很严重。

其中最简单的是 Burnham 与 Overton 在 1978 年提出的二阶 jackknife,只需要「恰好被 1 个来源找到」和「恰好被 2 个来源找到」的条目数:

def jackknife2(H):
    """Second-order jackknife (Burnham & Overton 1978).
    H: 0/1 matrix, rows = items found by at least one source, columns = sources."""
    k = H.sum(axis=1)          # how many sources found each item
    t = H.shape[1]             # number of sources
    f1, f2 = (k == 1).sum(), (k == 2).sum()
    return len(H) + (2 * t - 3) / t * f1 - (t - 2) ** 2 / (t * (t - 1)) * f2

用上全部 7 个 Agent 后,平均绝对误差从两两配对时的约 12% 降到约 5%。一个同时学习「哪些 Agent 彼此相关」的对数线性模型表现大致相当,在全部条款上估计出 1360,真值为 1413。这组对比说明:每增加一个来源,就会多找到几条,而估计值能告诉你外面还剩多少。

一个完整示例

下面用一个最小可运行的流程,把上面的步骤串起来。假设你有两份合同条款抽取结果,已经按匹配规则对齐,并整理成 0/1 矩阵。

import numpy as np

# 行 = 至少被一个来源找到的条款,列 = 来源
# 这里用 3 个来源演示,实际可以是 2 个
H = np.array([
    [1, 1, 1],
    [1, 1, 0],
    [1, 0, 1],
    [0, 1, 1],
    [1, 0, 0],
    [0, 1, 0],
    [0, 0, 1],
    [1, 1, 0],
])

# 两来源 Chapman:取前两列
n1 = H[:, 0].sum()
n2 = H[:, 1].sum()
m  = (H[:, 0] * H[:, 1]).sum()
N, lo, hi = chapman(n1, n2)
print(f"两来源估计: {N:.1f}  区间 [{lo:.1f}, {hi:.1f}]")

# 多来源 jackknife
print(f"jackknife 估计: {jackknife2(H):.1f}")
print(f"实际已发现: {len(H)}")

运行后你会得到两个数字:两来源估计和 jackknife 估计。把它们与「实际已发现」的条目数相减,就是估计的遗漏量。如果手上有答案键,再把这个遗漏量与真实遗漏量对比,就能知道这套估计在你这个任务上偏了多少、偏哪个方向。

在合同场景中,这套流程的实际表现是:大多数 Agent 找到约四分之三的条款;1413 条中有 127 条被全部 7 个 Agent 漏掉,占 9%,与森林例子中的 12% 相当接近。精确率看起来偏低,但其中一部分是答案键本身的问题——素材作者手工读过一些「误报」,发现其中若干是律师没有标注的真实条款,也就是说标注本身也有缺口。

注意事项

  • 区间只反映抽样噪声。Chapman 给出的置信区间不包含共享盲区带来的偏差。两个高度一致的来源会得到一个偏低且区间很窄的估计,这是最容易被误读的情形。
  • 独立性无法直接验证。素材明确指出,12% 这个估计无法被直接检验,因为不存在一份完整的森林清单可供对照。你能做的只是选择差异更大的来源,并对「著名条目」做小样本抽查。
  • 来源少于四个时误差可能很大。代码审查领域的经验是,少于四名审查者时没有哪个模型足够准确,低估可能相当严重。两两配对只是起点,不是终点。
  • 答案键本身有缺口。人工标注会漏标,因此用答案键校验时,部分「误报」可能是真实条目。评估估计器精度时要考虑这一点。
  • 生产环境没有答案键。带标注的演示只是展示方法的行为与偏差方向,不是生产用法。生产中没有人工标注,而这正是你需要估计的原因。
  • 匹配规则会显著影响结果。「重叠达到较短文本一半」这类阈值是人为设定的,换一个阈值,n1、n2、m 都会变化。规则要在看到结果之前固定下来。
  • 成本与配额。多来源、多 Agent 的跑量会带来实际费用,素材中一轮 294 份合同、9 个 Agent 花费 14.71 美元。具体价格、模型版本与配额以各服务商官网当前信息为准。