Learning AI Quality 返回 KuthorX Blog II

第 04 章

第 1 周:跑 8 次,该看哪个数?

pass@k 与 pass^k:至少对 1 次和次次都对,差距随 k 越拉越大。一段讲解视频,一个可以拖参数的互动演示。

一个 Agent 单次成功率 90%。让它处理同一个请求 8 次,至少对 1 次的概率几乎是 100%,8 次都对的概率只有 43%。同一个 Agent,一个数字接近完美,另一个说明它一半时候靠不住。这一章讲这两个指标:pass@k 和 pass^k,以及什么时候该看哪个。

讲解视频

互动演示

拖动单次成功率 p 和运行次数 k,看两条曲线怎么分开。下面还有一个计算器:填入跑了几次、成功几次,算出无偏估计和区间。页面底部有自动判分的练习。

互动演示:pass@k 与 pass^k 在新标签页打开

两个公式

设单次成功率为 \(p\),每次运行相互独立:

$$ \text{pass@}k = 1 - (1-p)^k \qquad\qquad \text{pass}^k = p^k $$
  • pass@k:k 次里至少成功 1 次,等于 1 减去"k 次全失败"。由 Kulal et al.(2019,SPoC)提出,OpenAI 的 Codex 论文(Chen et al., 2021)把它推广开并给出了无偏估计量,用来评代码生成:生成 k 份代码,有一份通过单测就算解出。
  • pass^k(读作 pass hat k):k 次全部成功。出自 τ-bench(Yao et al., 2024),用来评客服类 Agent:同一个用户请求跑 k 次,要求每次都处理对。
单次成功率 ppass@3pass@8pass^3pass^8
50%87.5%99.6%12.5%0.4%
80%99.2%>99.9%51.2%16.8%
90%99.9%>99.9%72.9%43.0%
99%>99.9%>99.9%97.0%92.3%

三个规律:

  1. k = 1 时两者相等,都是 p。
  2. k 越大,pass@k 越高,pass^k 越低。p = 90% 时,k = 3 差 27 个百分点,k = 8 差 57 个。
  3. pass^k 对 p 极其敏感。p 从 90% 提到 99%,pass^8 从 43% 涨到 92%。要让"8 次都对的概率 ≥ 90%",单次成功率得 ≥ 98.7%。

该看哪个:用户有没有重试机会

场景指标理由
代码生成,有单测把关pass@k生成 k 份,自动挑出通过测试的那份,失败的用户看不见
搜索、头脑风暴pass@k给 k 个候选,用户自己挑,有一个好的就行
客服、退款、订票 Agentpass^k每个用户只有一次机会,同类请求来 k 次,每次都得对
改数据库、发邮件、执行命令pass^k操作不可撤销,错一次就是事故

Agent 上线后,同类请求会被成千上万个用户反复触发。pass@k 回答"它有没有能力做对",pass^k 回答"它能不能稳定地做对",可靠性说的是后者。τ-bench 的论文里,当时最强的模型任务成功率不到 50%,零售场景的 pass^8 掉到 25% 以下。

pass@k 在报告里很好看,因为它随 k 单调上升。看到别人报 pass@10,先问一句:产品上用户真的能重试 10 次吗?

实际怎么算:无偏估计量

真实的 p 不知道。做法是对每个任务跑 n 次(n ≥ k),数出成功 c 次。直觉上会直接把 \(\hat p = c/n\) 代进公式,但这样算出的 pass@k 系统性偏低;pass^k 正好相反,直接代入会系统性偏高。

Codex 论文给的无偏估计是:从 n 次结果里不放回地抽 k 次,算"抽到的 k 次全失败"的概率。pass^k 同理,算"抽到的 k 次全成功"的概率(τ-bench 用的就是这个):

$$ \widehat{\text{pass@}k} = 1 - \frac{\binom{n-c}{k}}{\binom{n}{k}} \qquad\qquad \widehat{\text{pass}^k} = \frac{\binom{c}{k}}{\binom{n}{k}} $$

例子:跑 10 次,成功 3 次,求 pass@5。

  • 无偏估计:\(1 - \binom{7}{5}/\binom{10}{5} = 1 - 21/252 \approx 91.7\%\)
  • 直接代入:\(1 - 0.7^5 \approx 83.2\%\),低了 8 个多百分点

有多个任务时,每个任务单独算,再对所有任务取平均。不能先把所有任务的成功率平均成一个 p 再套公式,原因见「公式成立的前提」一节。

from math import comb

def pass_at_k(n: int, c: int, k: int) -> float:
    """n 次里成功 c 次,pass@k 的无偏估计(Chen et al., 2021)。"""
    if not 0 <= c <= n or not 1 <= k <= n:
        raise ValueError(f"需要 0 <= c <= n 且 1 <= k <= n,收到 n={n}, c={c}, k={k}")
    if n - c < k:          # 失败次数不够 k 次,抽 k 次必有成功
        return 1.0
    return 1 - comb(n - c, k) / comb(n, k)

def pass_hat_k(n: int, c: int, k: int) -> float:
    """n 次里成功 c 次,pass^k 的无偏估计(τ-bench)。"""
    if not 0 <= c <= n or not 1 <= k <= n:
        raise ValueError(f"需要 0 <= c <= n 且 1 <= k <= n,收到 n={n}, c={c}, k={k}")
    return comb(c, k) / comb(n, k)

print(pass_at_k(10, 3, 5))   # 0.9167
print(pass_hat_k(10, 7, 3))  # 0.2917

p 本身就不准:和 rule of three、Wilson 的关系

上面的公式都把 p 当成已知。可 p 是跑出来的估计,本身带着不确定性,pass^k 会把这个不确定性放大。

因为 \(p^k\) 随 p 单调增,把 p 的置信区间两端各取 k 次方,就是 pass^k 的区间:

观测p 的 95% 区间pass^8 点估计(无偏)pass^8 区间
30 次成功 27 次Wilson 双侧 95%:[74.4%, 96.5%]37.9%(直接代入 0.98 为 43.0%)[9.4%, 75.5%]
30 次全过精确法单侧 95%:p ≥ 90.5%—≥ 45.0%

30 次成功 27 次,pass^8 可能低到 9%,也可能高到 75%。只报一个点估计,等于没说清楚。注意两行口径不同:第一行是双侧区间,第二行是单侧下界。

反过来算样本量:要证明 pass^8 ≥ 90%,单次失败率得 ≤ 1.3%。零失败的前提下,按精确法算至少要连续 228 次全过(rule of three 速算约 230 次)。

公式成立的前提

\(p^k\) 成立,要求 k 次运行相互独立,并且每次的成功率都是同一个 p。现实中常常不满足。

两个 Agent 在 10 个任务上的平均单次成功率都是 70%:

  • Agent A:每个任务的成功率都是 70%,时好时坏。pass^8 = \(0.7^8 \approx 5.8\%\)。
  • Agent B:7 个任务每次必对,3 个任务每次必错。pass^8 = 70%。

平均成功率一样,pass^8 差了 12 倍。A 是"不稳定",B 是"稳定地不会",修法完全不同。这也是 pass^k 必须按任务分别算再平均的原因。

同一个 prompt 重跑 k 次、换 temperature、换用例,算不算"独立的 k 次"?这是下一章「独立性假设」的内容。

常见错误说法

  • “pass@10 达到 95%,Agent 很可靠”:pass@k 说的是能力,不是可靠性。
  • “把 c/n 代进 1 − (1 − p)k 就是 pass@k”:有偏,系统性偏低,要用组合数公式。
  • “所有任务平均成功率 70%,所以 pass^8 = 0.78”:任务之间成功率不一样,要逐任务算再平均。
  • “跑了 8 次就能算 pass@8”:n = k 时估计值只能是 0 或 1,方差很大。Codex 论文每题采样 n = 200。