当前位置:首页 > AI编程类

AI 写代码到底行不行?代码生成评测与 Pass@k 指标拆解

1周前 (10-05)AI编程类21

现在的模型动不动就晒"通过率 90%",这些数到底是怎么量出来的?给 AI 的代码能力打分数,看着像"跑一遍能不能过测试"这么简单,实际上门道不少。这篇就拆代码生成评测里绕不开的一套东西:用什么题、怎么判对错,以及那个常被引用的 Pass@k 指标,到底在算什么。

为什么不能只让它写一次、跑一次

code-eval-cover.jpg

直接的做法是:丢给模型一道编码题,让它写一次,跑测试,过了就是 1,没过就是 0。问题出在"写一次"这三个字上。

模型生成时带随机性——同一个题目、同一个模型,多采样几次,可能这次写对、下次写错。如果评测只看一次的结果,等于用一个随机波动当成了模型的真实水平,运气成分全混了进来。

于是行业里通行的思路,是对每道题采样多个候选答案,再用一个"只要有一个对就算过"的口径来统计,这样能更稳地反映"模型有没有能力写出正确答案",而不是"这一把运气好不好"。这个口径,就是 Pass@k 的由来。

HumanEval:一套成了事实标准的题

要聊 Pass@k,先得知道它在什么题上算。常被拿来当基准的,是 OpenAI 提出来的 HumanEval。

HumanEval 包含 164 道 Python 编程题,每道题的形态是"给一个函数签名和一段 docstring 说明,让模型补全函数体"。比如给一个函数名和注释说"这个函数返回列表里所有偶数的平方和",模型要写出符合这段说明的函数实现。

判对错不靠人眼看,靠在隐藏的单测:每道题都配了若干组输入输出断言,模型写出来的函数跑这些断言,全过才算对。这种"看 docstring 写实现、用单测判分"的设定,成了后来大量代码评测题的基础范式。

不过 HumanEval 也有个老生常谈的顾虑:题目早就在网上公开了,模型可能在训练时见过。为了绕开"背题",后来才有了 MBPP、以及用真实 GitHub issue 的 SWE-bench 这类口径。

Pass@k 到底在算什么?拆开看公式

Pass@k 的定义一句话:对一道题采样 n 个候选,从中随机取 k 个,这 k 个里只要有至少一个通过了测试,这道题就算被解决。对每道题都这么算,再取平均,就是整个数据集的 Pass@k。

但这里有个别扭的地方:我们通常不会真去"采样 n 个再从中抽 k 个"这么绕一圈。工程上更实际的做法是采样 n 个、跑出 c 个通过,然后用组合数学反推出"如果当初只取 k 个,命中至少一个正确"的概率。这就是那个无偏估计公式:

Pass@k ≈ E[ 1 − C(n − c, k) / C(n, k) ]

逐块翻译一下这个式子。

c 是 n 个候选中通过测试的个数,C(n, k) 是从 n 个里取 k 个的组合总数,C(n − c, k) 是从"没通过的那 n − c 个"里取 k 个的组合数。用后者除以前者,得到的是"抽的 k 个碰巧一个对的都没有"的概率;再用 1 减去它,就是"抽的 k 个里至少有一个对"的概率。

这个式子妙在:哪怕 c 很小,只要 n 够大,k 取大一点,Pass@k 依然能"救"回来——因为它统计的是"能不能写出一个对的",而不是"一次写对的命中率有多高"。

实践里常见的取值,是让 n 取到一两百,k 取 1、10、100 这样的档位,分别报告 Pass@1、Pass@10、Pass@100。Pass@1 反映"一把写对"的能力,k 越大,越偏向"多试几次总能碰对"的能力上限。

指标背后,还有几个容易忽略的前提

Pass@k 好看,不代表就能直接下结论。

一是 k 越大,含义越弱。Pass@100 高,只说明模型在多采样里能碰出正确答案,不代表你实际用的时候(往往就让它写一版)有这么靠谱。日常体验更接近 Pass@1。

二是单测的覆盖面。一道题可能单测只盯住了几组常规输入,模型写段代码碰巧蒙过了这几组,却未必真的正确、健壮,这叫"过拟合测试"。评测分数高,和代码真的好用,中间还隔着一层。

三是数据泄露。HumanEval 这类公开题,训练语料里可能就见过,考出来的高分未必是泛化能力。所以严肃一点的评测,会用不公开的题,或者像 SWE-bench 那样让模型在真实仓库、真实 issue 上去修 bug、跑整套项目测试。

四是工程能力远比"补全函数"复杂。真实开发里有跨文件依赖、环境配置、版本兼容,这些靠单测式的补全题量不出来,这也是为什么"评测分很高、真干活还得人上"这种反差经常出现。

小结

把代码生成评测这条线收一下:评测不能只跑一次,因为采样有随机性;HumanEval 用"docstring 出题、单测判分"立了个范式;Pass@k 的本质是"多采样里至少出一个对的概率",靠组合数做无偏估计;但 Pass@k 越高不等于干活越靠谱,k 的取值、单测覆盖、数据泄露、工程复杂度,都会让分数和真实体验拉开差距。

下次再看到"某某模型 HumanEval 通过率刷新纪录",你至少知道该怎么去读它了:先看是 Pass@1 还是 Pass@10,再看题是否可能被训练语料见过,末了再想一想,这 164 道补全题,离你手头那个真正的代码仓库,到底有多远。

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。