要跑多少次,取决于你想证明什么

证明失败率低于 p:零失败要跑约 3/p 次;把成功率估到 ±5%:最多 385 个样本;检测两个版本差 5 个点:每个版本约 900 个。

三种问题,三个公式。样本量数的都是独立样本,同一个输入重跑 400 次不算 400 个。

1问题:"跑多少次"之前,先问"要证明什么"

面试官问"这个 Agent 上线前要跑多少次评测",答"100 次"或"越多越好"都会被追问:凭什么是 100?

样本量不是拍脑袋的数,它由你要下的结论反推出来。测开和 Agent 评测里常见的结论只有三种:

想说的话统计问题典型答案(95% 置信度)
"退款误操作率 ≤ 5%"零失败证明上界59 次全过
"任务成功率约 80%,误差 ±5%"估计到指定精度246 个样本;不知道成功率时按最坏情况 385 个
"新 prompt 比旧的好 5 个点"检测两个版本的差距80% → 85%:每个版本 906 个(独立两组);配对能省多少看两个版本有多一致

三个问题的难度差了一个数量级。先说清楚是哪一种,再算 n。

2场景一:零失败,证明失败率 ≤ p(回顾 rule of three)

这是「rule of three」一章的内容。如果真实失败率等于 p,n 次全过的概率是 \((1-p)^n\)。要让这件事"巧合到只有 α 的概率",解出:

$$n \ge \frac{\ln \alpha}{\ln(1-p)} \approx \frac{-\ln\alpha}{p}$$

α = 5%(95% 置信度)时 \(-\ln 0.05 \approx 3\),就是 rule of three:n ≈ 3/p。99% 置信度时常数变成 4.6。

要证明失败率 ≤90% 置信95% 置信99% 置信速算 3/p
10%22294430
5%45599060
2%114149228150
1%230299459300

表里是精确法向上取整后的次数。速算 3/p 总是略多一点,面试时说 3/p 就够。

这个公式只管"一次都没挂"的情况。挂了 1 次,就不能再说"≤ 3/n"了,要换 Wilson 区间或精确二项区间(「Wilson 区间」一章),或者提前设计一个允许少量失败的门禁(第 5 节)。

3场景二:把成功率估到 ±E

老板问"这个 Agent 成功率多少",你想回答"80%,误差 ±5%"。误差(区间半宽)约为 \(z\sqrt{p(1-p)/n}\),令它等于 E,反解 n:

$$n \approx \frac{z^2\,p(1-p)}{E^2}$$

z 是置信度对应的正态分位数:90% 取 1.645,95% 取 1.96,99% 取 2.576。

预估成功率 p±10%±5%±3%±2.5%
50%(最坏情况)9738510681537
80%62246683984
90%35139385554

两个规律:

  1. p = 50% 是最坏情况。\(p(1-p)\) 在 p = 0.5 时最大,等于 0.25。不知道成功率大概多少时,就按 50% 算,结果只会偏保守。
  2. 精度减半,样本量 ×4。E 在分母上是平方。±5% 要 385 个,±2.5% 要 1537 个。想把误差从 5 个点压到 1 个点,要 25 倍的样本。
这个公式用来事前规划跑多少。跑完以后报区间,用 Wilson 区间,尤其是成功率接近 0 或 100% 的时候。成功率 98% 时"±5%"本身就没有意义,应该改问"失败率上界是多少",回到场景一。

4场景三:检测两个版本的差距

改了 prompt,想知道新版本是不是真的更好。这时有两种犯错方式:

错误含义控制它的参数常用取值
误报(第一类错误)其实没变好,你说变好了显著性水平 α5%(双侧)
漏报(第二类错误)其实变好了,你没测出来β;功效 power = 1 − βpower 80% 或 90%

再加上第三个量:最小可检测差距(效应量)δ。你关心"好 5 个点"还是"好 1 个点"?差距越小越难测出来。

两个版本各跑一批互不相关的样本(独立两组),基线成功率 \(p_1\),新版本 \(p_2 = p_1 + \delta\),每个版本需要:

$$n = \frac{\left(z_{1-\alpha/2}\sqrt{2\bar p(1-\bar p)} + z_{1-\beta}\sqrt{p_1(1-p_1)+p_2(1-p_2)}\right)^2}{\delta^2},\qquad \bar p = \frac{p_1+p_2}{2}$$
基线 → 新版本power 80%power 90%
80% → 90%(差 10 个点)199266
80% → 85%(差 5 个点)9061212
90% → 95%435582
50% → 55%15652095
80% → 82%(差 2 个点)60398084

α = 5% 双侧,正态近似、不带连续性校正,数字是每个版本的样本数。差距减半,样本量约 ×4,和场景二一样。

配对设计:同一批用例,两个版本都跑

离线评测里,两个 prompt 版本几乎总是跑同一批用例。这时应该逐条比较:大部分用例两个版本结果一样(都过或都挂),这些用例对"谁更好"没有信息;真正有用的是结果不一致的用例。

设两个版本结果不一致的用例占比为 ψ,配对设计需要的用例数(Connor, 1987):

$$n = \frac{\left(z_{1-\alpha/2}\sqrt{\psi} + z_{1-\beta}\sqrt{\psi-\delta^2}\right)^2}{\delta^2}$$
80% → 85%,power 80%每个版本要跑的用例数
独立两组906
配对,不一致率 ψ = 20%626
配对,不一致率 ψ = 10%312
配对,ψ = 5%(新版本只修好、没改坏)155
配对,ψ = 29%(两个版本的结果互不相关)909
两个版本行为越接近(ψ 越小),配对省得越多:ψ = 10% 时省约三分之二,ψ = 20% 时只省约三成;两个版本的结果互不相关时(这里 ψ = 0.8 × 0.15 + 0.85 × 0.2 ≈ 29%)完全不省。改一版 prompt,大部分用例的结果通常不会变,ψ 往往不大,所以离线评测值得按配对来设计和检验。配对数据怎么做检验,是下一章「McNemar」的内容。

▶互动演示:三种问题,各要跑多少次

选场景

5允许少量失败的发版门禁:漏放率和误拦率

把场景一变成流水线里的门禁:"跑 n 次,失败不超过 f 次就放行"。一个门禁有两个错误率,和上一节的 α、β 一一对应:

失败数服从二项分布,两个概率都能精确算出来。把"通过概率"画成失败率的函数,就是抽样验收里的 OC 曲线(operating characteristic)。f = 0 时,漏放率就是 \((1-q_{坏})^n\),也就是 rule of three 里的 α。

以 q好 = 2%、q坏 = 10% 为例:

门禁规则漏放率(10% 的坏版本通过)误拦率(2% 的好版本被拦)
5 次全过59.0%9.6%
30 次全过4.2%45.5%
30 次最多挂 1 次18.4%12.1%
89 次最多挂 4 次5.0%3.3%

"30 次全过"漏放率够低,但好版本有将近一半会被拦下。团队很快就会习惯"挂了再跑一遍"。最多跑 3 轮、有一轮全过就放行,坏版本的漏放率从 4.2% 涨到 12.2%,门禁的保证就没了。

想让两个错误率同时低于 5%,要先定好 q好 和 q坏,再找最小的 (n, f)。q好 和 q坏 离得越近,n 越大:2% 对 10% 要 89 次,1% 对 5% 要 181 次。

▶模拟门禁:跑 n 次,最多允许 f 次失败

常见门禁
漏放率:坏版本通过
误拦率:好版本被拦
被测版本的通过概率
OC 曲线:通过概率 P(失败数 ≤ f) q好 q坏 被测版本 q

模拟结果

点"模拟 200 轮发版":每一格是一轮,按真实失败率 q 随机跑 n 次,失败 ≤ f 次算放行(绿),否则拦下(红)。

6样本量数的是独立样本

上面所有公式里的 n,都是独立样本的个数(见「独立性假设」一章)。同一个输入重跑 400 次,只能说明这一个输入的 flaky 率,对"Agent 在这类任务上的成功率",换算成独立样本也只有个位数(公式上限约 1/ρ ≈ 3.3),而且只有 1 个用例,根本推不到这类任务。

如果每个用例跑 m 次,用例内相关系数为 ρ,有效样本是 \(n/(1+(m-1)\rho)\)。反过来,要凑够 \(n_{\text{req}}\) 个有效样本,需要的用例数是:

$$C = \frac{n_{\text{req}}\,\bigl(1+(m-1)\rho\bigr)}{m}$$
目标:±5% 精度(需要 385 个有效样本),ρ = 0.3用例数总运行次数
每个用例跑 1 次385385
每个用例跑 5 次170850
1 个用例跑 385 次做不到:有效样本上限约 1/ρ ≈ 3.3
重跑能省一些用例,但要多花运行成本,而且省得有上限。规划样本量时,先算需要多少个不同的用例,再决定每个跑几次。报告里写"170 个用例 × 每个 5 次",不要写"850 次"。

✎练习

题 1(算):要在 95% 置信度下证明退款误操作率 ≤ 5%,零失败的前提下至少跑几次?
次
精确法:ln 0.05 / ln 0.95 ≈ 58.4,向上取整 59 次;rule of three 速算 3 / 0.05 = 60 次。两个答案都算对。
题 2(算):不知道成功率大概多少,想在 95% 置信度下估到 ±5%,至少要多少个独立样本?
个
按最坏情况 p = 50%:1.96² × 0.25 / 0.05² ≈ 384.1,向上取整 385(写 384 也算对)。精度要到 ±2.5%,就得 ×4,约 1537 个。
题 3(门禁):门禁规则是"30 次全过才放行"。一个真实失败率 5% 的版本,通过门禁的概率是多少?
%
0.9530 ≈ 21.5%。失败率 5% 的版本有两成机会溜过去;想把它也拦住,要按 q坏 = 5% 重新设计门禁,至少 59 次全过。
题 4(算):基线成功率 80%,想检测新版本提升到 90%。α = 5% 双侧、power 80%,独立两组设计每个版本要多少个样本?(可以用上面的演示算)
个
p̄ = 0.85,(1.96 × √(2 × 0.85 × 0.15) + 0.8416 × √(0.16 + 0.09))² / 0.1² ≈ 199。差距缩到 5 个点(80% → 85%)就要 906 个。
题 5(场景):同事说"我把同一条退款请求跑了 400 次,成功 360 次,所以 Agent 的成功率是 90% ± 3%"。问题在哪?
公式里的 n 数的是独立样本。要谈任务整体的成功率,得从退款任务里抽几百个不同的用例。B 说的是次要问题,n = 400、p = 90% 时 Wilson 和正态近似差得不多。
题 6(设计):离线评测新旧两个 prompt,手上有一批 400 条用例。怎么安排最省?
配对设计把"用例难度"这个最大的噪声源抵消掉了,样本需求取决于不一致率 ψ。80% → 85%、ψ = 10% 时配对只要 312 条,独立两组每个版本要 906 条。C 只有 1 个独立样本。

7面试要点与代码

一句话讲清楚

样本量由要下的结论决定。证明失败率低于 p,零失败要跑约 3/p 次,失败率 <10% 要 30 次全过;把成功率估到 ±E,要 1.96²·p(1−p)/E²,最坏 ±5% 是 385 个,精度减半样本 ×4;比较两个版本要定 α、功效和最小差距,80% 到 85% 独立两组每边约 900 条,同一批用例配对跑,不一致率低时能省一大半。所有 n 数的都是不同的用例,不是重跑次数。

常见错误说法

❌ "失败率 <10%,跑 100 次":零失败 30 次就够,100 次是没算过的数。
❌ "估计误差 ±1%,跑 1000 次":±1% 最坏要 9604 个,1000 个只能到 ±3.1%。
❌ "新版本 85%、旧版本 80%,跑了 100 条,新版本更好":每边 100 条时差 5 个点的功效只有约 15%,这点差距多半是噪声。
❌ "30 次全过的门禁很严格":对坏版本严格,对好版本也严格。2% 失败率的好版本有 45% 会被拦,最后变成"挂了重跑"。
❌ "同一个用例跑 400 次,样本量 400":有效样本看的是用例数。
from math import ceil, log, sqrt
from scipy.stats import binom, norm

def n_zero_failure(p: float, conf: float = 0.95) -> int:
    """零失败时,证明失败率 <= p 需要的次数(精确法)。"""
    return ceil(log(1 - conf) / log(1 - p))

def n_precision(p: float, e: float, conf: float = 0.95) -> int:
    """把成功率估到 ±e 需要的独立样本数;p 未知时用 0.5。"""
    z = norm.ppf(1 - (1 - conf) / 2)
    return ceil(z ** 2 * p * (1 - p) / e ** 2)

def n_two_groups(p1: float, p2: float, alpha: float = 0.05, power: float = 0.8) -> int:
    """独立两组比较成功率,每组需要的样本数(双侧、无连续性校正)。"""
    za, zb = norm.ppf(1 - alpha / 2), norm.ppf(power)
    pbar = (p1 + p2) / 2
    num = za * sqrt(2 * pbar * (1 - pbar)) + zb * sqrt(p1 * (1 - p1) + p2 * (1 - p2))
    return ceil(num ** 2 / (p1 - p2) ** 2)

def n_paired(psi: float, delta: float, alpha: float = 0.05, power: float = 0.8) -> int:
    """配对设计(McNemar)需要的用例数,psi 是结果不一致的用例占比(Connor, 1987)。"""
    if not 0 < abs(delta) <= psi:
        raise ValueError(f"需要 0 < |delta| <= psi,收到 delta={delta}, psi={psi}")
    za, zb = norm.ppf(1 - alpha / 2), norm.ppf(power)
    return ceil((za * sqrt(psi) + zb * sqrt(psi - delta ** 2)) ** 2 / delta ** 2)

def gate_errors(n: int, f: int, q_good: float, q_bad: float) -> tuple[float, float]:
    """门禁"n 次里最多 f 次失败"的(漏放率, 误拦率)。"""
    return binom.cdf(f, n, q_bad), 1 - binom.cdf(f, n, q_good)

print(n_zero_failure(0.05))            # 59
print(n_precision(0.5, 0.05))          # 385
print(n_two_groups(0.80, 0.85))        # 906
print(n_paired(0.10, 0.05))            # 312
print(gate_errors(89, 4, 0.02, 0.10))  # (0.0497, 0.0334)

公式显示依赖 KaTeX(CDN),断网时公式会显示成原始 LaTeX 源码,交互部分不受影响。