pass@k 详解

pass@k 是代码生成领域最常用的验收指标之一:对每道题允许模型生成 k 个候选,只要其中至少一个通过全部单元测试,该题就算「通过」。它刻画的是「多次尝试下的成功率」,比单次 greedy 解码更贴近实际编程辅助场景。

段末注释:pass@k 中 (k) 为每题采样次数;(k=1) 即单次生成必须一次做对,与 pass@10、pass@100 等不可直接比较绝对值。

系列索引:微调评估指标导读


一、直观含义

HumanEval、MBPP 等基准中,每题有:

  • 函数签名与 docstring(prompt)
  • 若干隐藏单元测试(oracle)

模型生成 (k) 段代码 ({c_1,\ldots,c_k}),若 (\exists j) 使 (c_j) 通过全部测试,则该题 pass。

$$
\text{pass@k} = \frac{\text{至少一个候选通过的题目数}}{\text{总题目数}}
$$

人话:100 道题里,有多少道在「给 k 次机会」下能写对可运行代码。


二、使用场景与所需数据

场景 适用性
代码补全 / 函数合成
数学推理(可执行验证) 中 — 需符号或数值 checker
开放对话 不适用
分类标签生成 不适用 — 用 Accuracy / F1

数据要求

  1. 题目 prompt
  2. 可自动执行的判题器(单元测试、assert、sandbox)
  3. 每题固定采样数 (n \ge k)(见无偏估计)

三、计算方式

3.1 朴素定义(每题恰好 k 个样本)

对单题,设 k 个候选中通过数为 (c),该题贡献为 (\mathbb{1}[c \ge 1])。全集平均即 pass@k。

3.2 无偏估计(HumanEval 标准)

实际常每题采样 (n > k) 个(如 n=200),其中 (c) 个通过。无偏 pass@k 估计:

$$
\text{pass@k} = \mathbb{E}_{\text{problems}}\left[ 1 - \frac{\binom{n-c}{k}}{\binom{n}{k}} \right]
$$

当 (n - c < k) 时,(\binom{n-c}{k}=0),该题贡献为 1(至少 c 个通过,必能选出通过的 k 子集)。

直觉:从 n 个样本里随机抽 k 个,抽不到任一通过样本的概率是 (\binom{n-c}{k}/\binom{n}{k}),用 1 减去即「至少一次通过」的概率。

3.3 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
from collections import defaultdict

def pass_at_k(n: int, c: int, k: int) -> float:
"""
n: 该题总采样数
c: 通过单元测试的采样数
k: pass@k 中的 k
"""
if n - c < k:
return 1.0
return 1.0 - np.prod(1.0 - k / np.arange(n - c + 1, n + 1))

# 示例:100 题,每题 n=10 次采样
results = [] # 每题 (n, c)
for n, c in results:
results.append(pass_at_k(n, c, k=1))

pass_at_1 = np.mean(results)

OpenAI human_eval 官方实现即采用上述公式;evaluate 库亦提供 code_eval 指标。

3.4 采样策略

策略 说明
temperature > 0 多样性采样,k 越大 pass@k 通常越高
nucleus (top-p) 控制候选质量与多样性平衡
greedy (k=1) 等价 pass@1,无随机性

报告时必须注明:temperature、top_p、n、k、是否 strip / 提取 markdown 代码块。


四、pass@1 vs pass@k

pass@1 pass@k (k>1)
采样 通常 greedy 或单次 多次独立采样
含义 一次写对能力 多次尝试下能否写对
数值 一般最低 随 k 单调不降
成本 k 倍推理 + k 倍沙箱执行

文献常见 pass@1(与 leaderboard 对齐)与 pass@10 / pass@100(展示潜力)。微调对比时固定 k 与采样超参


五、如何解读

现象 可能含义
pass@1 低、pass@10 高 模型「偶尔能写对」,不稳定;需改进一致性
微调后 pass@1 ↑、pass@10 ↑ 有效提升代码能力
pass@1 ↑ 但沙箱超时增多 生成更长或死循环代码增多
不同 k 曲线平行上移 整体能力抬升,相对形状稳定

HumanEval 上顶尖模型 pass@1 可达 0.9+(随时间演进);跨论文比绝对值需同 benchmark、同 k、同 n、同判题环境。


六、局限性与常见误用

  1. 强依赖测试覆盖:测试不全则「假通过」;过严则「假失败」。
  2. 仅测功能不测质量:通过测试的代码可能低效、难读、有安全隐患。
  3. 数据泄漏:训练集含 benchmark 题目会虚高 pass@k。
  4. k 与 n 不一致不可比:pass@10 用 n=10 vs n=200 估计方差不同。
  5. 沙箱环境差异:Python 版本、依赖、超时阈值影响结果。
  6. 与 BLEU/EM 无关:代码评估几乎不用 n-gram 文本重叠。

七、与其他指标的关系

指标 关系
Exact Match 字符串级;pass@k 为执行级,更贴近代码
BLEU / ROUGE 文本重叠;代码任务一般不采用
pass@k 与 unit test pass rate 单样本通过率 vs 至少一次通过率

八、实践建议

  1. 代码微调验收:pass@1 为主,附 pass@10 展示上限(若算力允许)。
  2. 使用官方或 evaluate("code_eval") 无偏估计,避免手写「k 次里有没有 1 次对」在小 n 下有偏。
  3. 沙箱隔离执行,设 timeout内存上限
  4. 记录失败样例类型:语法错 / 逻辑错 / 超时 / import 缺失,指导数据增广。
  5. 微调前后用同一 n、k、temperature 对比 delta。
-------------本文结束感谢您的阅读-------------