想象你去一家百年老字号应聘御厨。考官不发食材、不看颜值,而是递来一张菜谱卡:“荷叶糯米鸡:要求去骨、糯米耙而不烂、荷叶香透。”卡上除了菜名和要求,还写着几组“验收暗号”——放多少盐、炖多久、出锅长什么样。你要做的,就是照这张卡把菜做出来。 大语言模型的“厨艺定级考”就叫 HumanEval。它把代码生成变成了一场标准化考试:164 张菜谱卡就是 164 道 Python 编程题,模型照着自然语言描述写函数,最后由考官用单元测试统一打分。一个模型代码写得好不好,不再靠人肉眼判断,而是看它能不能像学徒一样,把一张张菜谱卡变成端上桌还能通过验收的“菜”。
学会理解 HumanEval,你就掌握了 AI 领域最常用的“代码生成能力度量尺”,无论是做模型选型、算法研发还是模型评测,都能用同一套标准看懂各家大模型的技术报告。
可视化演示
展示HumanEval代码生成评测:自然语言到函数代码的生成流程、pass@k通过率曲线、单元测试用例验证结果,通过交互理解代码生成能力的评测方法。
本节配有交互动效(进入视口后自动加载,约 3KB)。
代码生成:自然语言到函数 由函数签名与文档生成 模型生成函数实现 NL→Code 经单元测试验证
设计起源
想象你去一家百年老字号应聘御厨。考官不发食材、不看颜值,而是递来一张菜谱卡:“荷叶糯米鸡:要求去骨、糯米耙而不烂、荷叶香透。”卡上除了菜名和要求,还写着几组“验收暗号”——放多少盐、炖多久、出锅长什么样。你要做的,就是照这张卡把菜做出来。
HumanEval 就是给大语言模型准备的这样一套“御厨菜谱卡”。它是由 OpenAI 研究者手工编写的 164 道 Python 编程题,最早因 Codex 论文进入大众视野,后来又因为 GPT-4 等技术报告频繁引用而成为业界标杆。每道题都包含三样东西:函数签名、文档字符串和隐藏测试用例。函数签名像是菜名和装菜的盘子,规定了函数叫什么、要接几个参数;文档字符串则是写满要求的制作说明,告诉模型这道菜要完成什么功能、有哪些输入输出的例子。
这些题目不是随机抓来的,而是专门为“功能正确性”设计的。题目覆盖字符串处理、数学运算、数据结构、逻辑推演等常见编程任务,难度定位在编程面试中的中等水平。这样做的好处是:题目足够短,模型可以在一次生成中被完整评估;题目又足够多样,能够从多个侧面反映模型的代码能力。
如果把模型比作厨师,函数签名和文档字符串就是考官递出的菜谱卡,而隐藏测试用例就是考官手里的“小秤”。HumanEval 的初衷,就是让代码生成这件事像考级一样,有一套稳定、可复现、能横向比较的评分标准。
评测流程
有了菜谱卡,接下来就是走进考场。HumanEval 的评测流程可以拆成四步:先给模型看“考卷”,再让模型“写菜”,然后考官“试菜”,最后记录“通过/不通过”。
第一步,考卷拼装。评测系统把函数签名和文档字符串拼接成一个提示词,例如 def add(a, b): 加上一段“返回两个数之和”的说明,让模型补全函数体。第二步,生成候选代码。模型像厨师一样开始动手,输出一版函数实现。第三步,运行测试用例。评测系统把生成出来的函数放进沙箱,调用若干组输入输出,看结果是否完全匹配。第四步,判定结果。所有测试用例都通过,这题得 1 分;任何一个用例失败、超时或报错,这题得 0 分。
这里最关键的设计是“测试用例隐藏”。题目不会把测试用例写进提示词,模型在生成代码时看不到最终验收标准。这就像厨师做菜时不知道考官会精确称量几克盐,只能靠理解菜谱要求来把握火候。模型必须真正理解文档字符串中的自然语言需求,而不是在输出里“背答案”。
“单元测试”这个概念听起来专业,其实就是一张张“验收小纸条”。每张纸条上写着“给我 1 和 2,你应该吐出 3;给我 0 和 0,你应该吐出 0”。厨师做出来的菜只要有一张纸条对不上,整道菜就算报废。评测流程也因此变得极其客观:不需要人读代码,不需要看注释,只看能不能通过测试。
核心指标
考场上,一位厨师做一道菜可能会翻车,但如果允许他重做几次,成功率自然会上升。模型生成代码也一样:同一个问题,采样 1 次可能碰巧写出 Bug,采样 100 次却总有一次能蒙对。为了公平度量,HumanEval 引入了 pass@k 指标。
pass@k 的意思是:对同一个问题生成 n 个候选答案,从中随机抽取 k 个交给测试用例检验,只要 k 个里至少有一个通过,就算这次“通过”。最初的论文里直接用 pass@100 展示模型上限,但样本量有限时直接用经验比例会有偏差,于是研究者给出了无偏估计公式:
其中,n 是为一道题生成的候选代码总数,c 是这 n 个候选中通过测试的正确数量,k 是要抽样检验的次数。公式用组合数算出“抽到的全是失败答案”的坏运气概率,再用 1 减去它,就得到“至少一次成功”的概率。
需要注意的是,k 越小越接近真实产品体验。因为线上产品通常只让模型生成一次代码,所以 pass@1 是“单次下厨成功率”,而 pass@100 更像是“给厨师一百次返工机会后的过关率”。两者各有价值,但绝不能混为一谈。
- 分母选法从 n 个候选答案中任选 k 个接受测试,总共有多少种等可能的选法。
- 分子坏签c 个是正确的,n-c 个是错误的;如果 k 个全是错的,相当于从错误集合里挑 k 个。
- 坏运气概率用分子除以分母,得到“随机抽 k 个全是错误答案”的概率。
- 成功概率用 1 减去坏运气概率,得到“k 个里至少有一个正确”的概率。
基准地位
HumanEval 出名之后,几乎成了 AI 圈的“米其林指南”。各家大模型发布技术报告时,都会在显眼位置贴出 HumanEval 分数,从 Codex、CodeLlama 到 GPT-4,无一例外。这个数字成了衡量模型代码能力的“通用货币”,让不同论文之间有了一个可以横向对比的锚点。
这也是 HumanEval 的价值所在:它把“代码生成能力”从过去的“人工看几个例子,觉得不错”变成了可复现、可量化、可追踪的“能力信号”。模型调参、指令微调、数据清洗有没有效果?跑一遍 HumanEval,分数涨了就是涨了,跌了就是跌了。
但基准地位越高,越要警惕“数据污染”。如果某个模型的训练数据里已经包含了 HumanEval 的 164 道题,那它考试时就等于提前背过菜谱,分数自然虚高。就像一位厨师声称自己能做满汉全席,结果考的全是他每天在家练习的那几道菜,真实水平是要打个问号的。
所以,HumanEval 的排名只能作为“参考坐标”,不能当成“绝对真理”。它告诉我们的不是“谁天下第一”,而是“在同样考题、同样评分规则下,谁表现得更好”。真金不怕火炼,但前提是火得是同一把火。
局限挑战
拿到厨师证不代表会做分子料理,HumanEval 考高分也不代表模型能在真实项目里独当一面。这个基准有很多肉眼可见的局限,认识它们,才能正确理解分数背后的含义。
第一,题目偏“算法小题”。164 道题大多是几十行就能写完的 LeetCode 风格函数,缺少真实工程里的多文件协作、依赖管理、错误处理、并发安全等复杂上下文。第二,只测功能正确,不看代码质量。模型写出来的代码只要测试通过就得满分,哪怕变量名是 a、b,逻辑绕了三层,甚至存在安全隐患。第三,测试用例覆盖有限。题目里的测试只覆盖了少量输入输出,很多边界情况和异常分支根本没被验证。第四,存在过拟合风险。模型可以通过见过大量相似题或直接“背题”来刷分,导致分数不能真实反映泛化能力。
这些局限就像是菜谱卡上的“验收暗号”只检查了咸淡和熟度,却没有检查摆盘、营养、卫生和后厨是否整洁。对那些真正关心代码可维护性和安全性的企业来说,HumanEval 高分只能算“入场券”,不能算“免检牌”。
因此,在使用 HumanEval 时,我们既要肯定它作为标准化考卷的开创意义,也要清醒地认识到:它衡量的是“给定清晰需求后写出正确小函数”的能力,而不是“在大型代码库里做工程”的能力。分数可以参考,但不要神化。
实践应用
回到招聘场景,一家真正爱惜羽毛的餐厅,不会只看厨师手里的证书,还会让厨师到自家后厨试做几道私房菜。HumanEval 在实际 AI 工作中,扮演的正是“公共证书”和“私房菜模板”的双重角色。
最常见的应用是模型选型。算法团队要在大模型之间做取舍时,可以在统一的采样参数和测试环境下跑一遍 HumanEval,用 pass@1 看单次生成能力,用 pass@100 看模型的搜索上限,再把训练成本、推理速度放在一起综合判断。第二个应用是研发迭代中的回归测试。微调后的模型是否变强?在 CI 流程里每天自动跑一次 HumanEval,一旦分数倒退,立刻就能发现是哪次改动引入了能力回退。第三个应用是构建私有评测集。企业可以模仿 HumanEval 的格式,把内部代码任务改写成“函数签名 + 文档字符串 + 单元测试”,形成一套不会外泄、也不容易被污染的私有“菜谱卡”。
持续监控则贯穿始终。模型不是训练完就一劳永逸的,提示词调整、底座模型升级、微调数据变化,都可能影响代码生成质量。把 HumanEval 打磨成一条标准流水线,既能在选型时帮你看清谁强谁弱,也能在长期迭代中帮你守住质量底线。
说到底,HumanEval 是一柄好用的“量尺”,但量尺只能告诉你长度,不能告诉你味道。聪明的工程师会用这把尺子先筛出种子选手,再用自己的业务场景做最终试菜。
AI 应用场景
大模型代码能力选型
阶段:模型评估与选型
解决的问题:传统方式靠人工看模型生成样例,主观且样本少;用 HumanEval 可以在同一标准下批量测量多个模型的代码生成正确率,快速缩小候选范围。
具体案例:某算法团队要在 CodeLlama、DeepSeek-Coder 和 GPT-4o 之间做技术选型。他们固定温度参数,分别对同一套 HumanEval 子集采样,对比 pass@1 和执行耗时,最终选择在正确率与速度上最平衡的模型进入下一轮业务测试。
代码生成模型的回归监控
阶段:模型迭代与回归测试
解决的问题:微调后的模型可能在某些任务上变强,却在基础代码能力上“退化”,人工抽查很难发现;用 HumanEval 做自动回归集,可以在每次模型更新后量化能力变化。
具体案例:某 LLM 应用团队在 CI 流水线中加入 HumanEval 回归任务,每晚跑 164 题并记录 pass@1。一次调参后分数从 72.4% 降到 69.1%,团队立刻定位到训练数据里混入了大量重复的相似题目,回滚后分数恢复。
构造企业私有代码评测集
阶段:评测体系搭建
解决的问题:公共 HumanEval 有数据污染风险,而且题目与业务场景脱节;按它的题目格式构造私有评测集,能让评测更贴近真实代码需求。
具体案例:某银行研发团队把日常数据清洗脚本改写成 200 道“函数签名 + 文档字符串 + 单元测试”的私有题目,用来评测内部代码生成助手。上线后,模型在真实业务上的推荐通过率从 58% 提升到 74%。
Python 演示
import mathimport random def pass_at_k(n, c, k): if n - c < k: return 1.0 return 1.0 - math.comb(n - c, k) / math.comb(n, k) def check(problem, candidate): for args, expected in problem["tests"]: try: if candidate(*args) != expected: return False except Exception: return False return True def eval_model(problem, generate, samples=5, k=1): ok = 0 for _ in range(samples): candidate = generate(problem["prompt"]) if check(problem, candidate): ok += 1 return pass_at_k(samples, ok, k) problems = [ { "prompt": "add_two", "tests": [((1, 2), 3), ((5, 6), 11), ((0, 0), 0)], }, { "prompt": "is_even", "tests": [((2,), True), ((3,), False), ((0,), True)], },] def model_a(prompt): if prompt == "add_two": return lambda a, b: a + b return lambda x: x % 2 == 0 def model_b(prompt): if prompt == "add_two": return lambda a, b: a - b if random.random() < 0.2 else a + b return lambda x: x % 2 == 1 if __name__ == "__main__": random.seed(42) for name, model in [("model_a", model_a), ("model_b", model_b)]: scores = [eval_model(p, model) for p in problems] print(name, sum(scores) / len(scores))
def pass_at_k(n, c, k):实现 HumanEval 的 pass@k 无偏估计公式。if n - c < k: return 1.0如果错误候选不足 k 个,随机抽取时必然命中正确代码。def check(problem, candidate):对每个测试用例执行函数并比对返回值。candidate = generate(problem["prompt"])让模型根据题目提示生成候选函数。if check(problem, candidate): ok += 1统计多个候选答案中通过测试的数量。scores = [eval_model(p, model) for p in problems]跑完所有题目后取平均分。
常见误区
误区“这个模型 HumanEval 考了 90 分,应该什么代码都能写吧?”
正解HumanEval 只考几十行的算法小函数,不考多文件工程、代码风格、安全性和可维护性。就像厨师证只能证明他能按标准菜谱做菜,不能证明他能管理一间大型后厨。加上数据污染的可能性,90 分可能只是“背熟了考题”的结果。
为何常见:基准测试的数字看起来客观、可比较,人们很容易把分数高等同于能力强,忽略了评测范围本身很窄。
误区“反正多采样几次总能做对,模型 pass@100 很高,直接上线没问题。”
正解pass@100 允许模型生成 100 个候选答案,只要其中 1 个通过就算成功。但真实产品通常只给用户生成一次或几次结果,采样太多会带来成本和延迟问题。pass@1 更接近用户实际体验,两者应该一起看。
为何常见:pass@k 中的 k 让人误以为线上也可以无限重试,忽略了实际推理资源和响应时间的约束。
误区“这道题测试用例全部通过了,说明生成的代码肯定没问题。”
正解测试用例只是从输入空间中抽样的“考官小纸条”,不可能覆盖所有边界情况。一个 add 函数可能通过 (1,2)、(5,6),却在字符串拼接或空值输入时崩溃。测试全绿只能说明“在已验证的样本上正确”,不能证明“在一切输入上正确”。
为何常见:看到 CI 里所有测试变绿,人会本能地产生“安全感和确定性”,忘记了测试本身是有覆盖边界的。
误区“才 164 道题,样本这么小,这个指标早该淘汰了。”
正解164 道题确实不够覆盖真实世界的代码任务,但它的价值在于“标准化”和“可复现”。正因为题目固定、评测方式统一,全世界的研究者才能拿同一把尺子比较模型。它不能当唯一标准,但依然是模型对比和趋势追踪的重要参照。
为何常见:人们看到绝对数量少,就直觉地认为统计意义不足,却忽略了它在榜单对比中的“控制变量”价值。
面试题
Q1. HumanEval 主要用来评测大语言模型的什么能力?
- A.自然语言理解← 正确答案
- B.代码生成正确性
- C.图像识别能力
- D.推理与响应速度
答案:A。HumanEval 让学生模型根据函数签名和文档字符串写函数,再通过单元测试判断功能是否正确,评测的核心是代码生成的功能正确性。自然语言理解只是完成任务的中间手段,不是评测对象。
Q2. HumanEval 包含多少道 Python 编程题?
- A.64 道
- B.100 道
- C.164 道← 正确答案
- D.1000 道
答案:C。HumanEval 由 OpenAI 研究者手工编写了 164 道 Python 编程题。这个数量虽然不大,但因为题目质量高、格式统一,成了业界广泛使用的代码生成基准。
Q3. 在 HumanEval 中,文档字符串(docstring)的主要作用是什么?
- A.规范了代码风格
- B.描述需求并附示例← 正确答案
- C.保存了运行日志
- D.限制了函数权限
答案:B。文档字符串就像菜谱卡上的制作说明,用自然语言描述函数功能,并常附带输入输出示例。模型根据它理解题目需求并生成函数体,而不是用它控制权限或记录日志。
Q4. pass@k 中的 k 表示什么?
- A.生成的代码行数
- B.允许生成的候选次数← 正确答案
- C.隐藏测试的数量
- D.模型的神经网络层数
答案:B。pass@k 衡量的是从 n 个候选答案中抽取 k 个,至少有一个通过测试的概率。k 是“允许尝试的次数”,与代码行数、测试数量、网络层数无关。
Q5. 下列关于 pass@k 的说法,正确的是?
- A.衡量 k 次采样至少一次通过← 正确答案
- B.用组合数做无偏估计← 正确答案
- C.k 越大分数反而越低
- D.k=1 更贴近单次调用← 正确答案
答案:ABD。pass@k 衡量 k 个候选里至少一个通过的概率,原论文使用组合数进行无偏估计。k 越大,候选越多,通常分数越高而非越低,所以 C 错误。k=1 只允许一次生成,最接近线上真实调用场景。
Q6. HumanEval 如何判断生成代码是否正确?
- A.由人工阅读代码打分
- B.运行测试用例验证← 正确答案
- C.统计代码注释数量
- D.比较代码长度相似度
答案:B。HumanEval 采用单元测试自动判断代码是否正确。评测系统把生成的函数放进沙箱,运行预置的输入输出用例,全部通过才能得分,不需要人工阅读代码。
Q7. 关于 HumanEval 的数据污染,下列说法正确的是?
- A.模型见过原题影响不大
- B.数据污染会使分数虚高← 正确答案
- C.污染只会降低推理速度
- D.过拟合在评测中不存在
答案:B。如果模型的训练数据包含 HumanEval 题目,模型等于提前背过答案,测试分数会虚高。数据污染直接影响的是“泛化能力评估”,与推理速度无关,更不是可忽略的问题。
Q8. HumanEval 的局限性包括哪些?
- A.题目偏算法模板化← 正确答案
- B.忽略代码风格与安全← 正确答案
- C.测试用例覆盖有限← 正确答案
- D.可直接衡量工程能力
答案:ABC。HumanEval 的题目多是几十行的算法小函数,不涉及大型工程场景;评分只看功能正确,不评价代码质量;测试用例抽样有限,覆盖不了所有边界情况。因此它不能直接衡量真实工程能力,D 错误。
Q9. 在 pass@k 的无偏估计公式中,n 表示什么?
- A.测试用例的总数量
- B.每道题采样的候选数← 正确答案
- C.HumanEval 题目总数
- D.正确候选代码数量
答案:B。公式中的 n 是为同一道题生成的候选代码总数,c 才是其中通过测试的正确候选数。题目总数是 164,与单题采样的 n 不是同一个概念。
Q10. 关于 HumanEval 的正确说法是?
- A.完全不存在数据污染
- B.pass@k 可用组合数估计← 正确答案
- C.所有题目取自 LeetCode
- D.只评估功能不评估质量← 正确答案
答案:BD。HumanEval 的 pass@k 确实使用组合数做无偏估计,且评测只关心功能正确性,不评估代码质量和安全性。数据污染是真实存在的风险,A 错误;题目由研究者手工编写,并非全部来自 LeetCode,C 错误。