编程补习班的林老师最近很头疼:班里有个叫“小码”的学生,周考次次高分,可只要题目稍微变个花样,他就当场抓瞎。林老师翻出考卷一看,立刻明白了——每道大题只配了七八个检测点,小码只要把这几道样例背得滚瓜烂熟,就能轻松蒙混过关。于是林老师决定升级考卷:每道题配上七百多个检测点,故意塞进空列表、全负数、超大数组这些刁钻陷阱,还请“卧底”提前试考、验证每题质量。结果小码的分数当场崩了,而真正理解知识的学生稳如泰山。 这正是 AI 评测领域里 HumanEval+ 的故事。原版 HumanEval 用 164 道编程题考察代码生成大模型,每题平均只有约 7.7 个测试用例;HumanEval+ 用自动化手段把测试用例膨胀到每题数百上千个,覆盖边界条件与对抗场景,并引入变异测试来校验测试本身的质量。它像一把“放大镜”,把靠运气和背题获得的假高分照出原形,让模型排名更可信、能力对比更有说服力。

岗位关联

一句话职业价值:学会增强测试设计,你就能看穿“虚高分数”,在模型选型、基准建设和上线评估中做出更靠谱的判断。

目录
  1. 可视化演示
  2. 评测背景:一张“太简单”的考卷
  3. 测试生成策略:出题老师的“题海战术”
  4. 对抗性测试:专挑边角料来刁难
  5. 变异测试校验:给考试题“验毒”
  6. 评测可靠性提升:挤掉分数的水分
  7. 模型排名与能力:重新洗牌见真章
  8. 局限与未来趋势:严格考试的代价
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

通过原版vs增强版用例对比、变异测试驱动的用例生成、以及假阳性率消除曲线,展示HumanEval+如何通过大规模测试用例提升LLM代码评测可靠性。

本节配有交互动效(进入视口后自动加载,约 3KB)。

原版vs增强版测试用例对比 原版HumanEval每题约9个用例假阳率高达35% HumanEval+扩展至数百用例假阳率降至3%以下 FP↓=Tests↑ 用例数量与假阳性率呈反比关系

评测背景:一张“太简单”的考卷

林老师的补习班每周周考,考卷共 164 道大题,可每题只配了约七八个小检测点。“小码”这个学生把样例背得滚瓜烂熟,每次都能拿高分。林老师多了个心眼:把题目换成没见过的变体,小码立刻答错。原来,它的“高分”只是运气好——考题太少,恰好全被它“背”中了。

大模型评测里的原版 HumanEval 就长这样:164 道编程题,要求模型补全函数实现,每题平均仅约 7.7 个测试用例。测试点太少,就像考卷只问“3+5=?“,把”背答案“的模型和真正会计算的模型混在一起。这种现象叫”假阳性”:代码本身是错的,却因为通过全部测试被判为正确。

为此,EvalPlus 团队提出了 HumanEval+:给每道题自动生成数百上千个新测试用例,把平均测试数从约 7.7 个提升到约 774 个。测试面积扩大了约 100 倍,“背答案”的侥幸空间被压缩到几乎为零。

考卷题目变多,背答案的“小码”立刻现出原形。HumanEval+ 正是林老师那份“千人千题”的严格考卷——它用测试用例的数量与质量,重新定义了什么叫“真正会做这道题”。

TˉHE≈7.7,TˉHE+≈774\bar{T}_{\mathrm{HE}}\approx 7.7,\qquad \bar{T}_{\mathrm{HE+}}\approx 774
左边是原版每题平均测试数,右边是增强后每题平均测试数,两者相差约 100 倍,这就是“考卷加码”的量化含义。
  1. 原版平均测试数把 164 道题的测试数加总后取平均,得到原版基准的“每卷题量”。
    TˉHE=1164∑j=1164Tj≈7.7\bar{T}_{\mathrm{HE}}=\frac{1}{164}\sum_{j=1}^{164}T_j\approx 7.7
  2. 增强平均测试数用同样的方式统计 HumanEval+ 的测试规模,反映增强后的“每卷题量”。
    TˉHE+=1164∑j=1164Tj+≈774\bar{T}_{\mathrm{HE+}}=\frac{1}{164}\sum_{j=1}^{164}T_j^{+}\approx 774
  3. 规模差距两数之比直观展示增强力度,约 100 倍的差距是假阳性被压缩的关键。
    TˉHE+/TˉHE≈100\bar{T}_{\mathrm{HE+}}/\bar{T}_{\mathrm{HE}}\approx 100

测试生成策略:出题老师的“题海战术”

林老师出题自有套路:先选一个普通题目,像变魔术一样变出空列表、全负数、超大数组等各种花样;然后请成绩最好的学生把标准答案算出来;最后再让“卧底”提前考一遍,确认题目没有漏洞。三步走完,一张高质量考卷才敢发下去。

HumanEval+ 生成增强测试的流程与此如出一辙。第一步,解析函数的签名和问题描述,构造“输入种子”;第二步,拼贴边界条件、随机组合、大规模采样,产生成千上万个输入;第三步,用一份“参考实现”(公认正确的代码)运行每个输入,得到期望输出。人工只需要审查少量种子和规则,剩下的交给自动化流水线。

这套流水线的关键创新在于:期望输出不是人逐条手写的,而是“参考实现跑出来的”。这让大规模生成成为可能——只要输入够多、够刁钻,期望输出就源源不断。最终,增强测试集就是“输入 × 期望输出”的配对集合。

题海战术的好处是覆盖面广,但题目本身必须“有标准答案且答案正确”,否则就是白考一场。测试质量如何保证?这就引出了后面的变异测试——林老师请“卧底”验题的环节。

T+={(x,y)∣x∼Dinput, y=Ref(x)}\mathcal{T}^{+}=\{(x,y)\mid x\sim\mathcal{D}_{\text{input}},\ y=\mathrm{Ref}(x)\}
增强测试集中的每个用例,是一个输入 x 与它对应标准答案 y 的配对:x 从精心构造的输入分布中采样,y 由参考实现计算得出。
  1. 采样输入从输入分布中抽取多样化的测试数据,包括典型值与边界值。
    x∼Dinputx\sim\mathcal{D}_{\text{input}}
  2. 计算期望参考实现逐一处理输入,给出标准输出,保证“答案正确”。
    y=Ref(x)y=\mathrm{Ref}(x)
  3. 组装套件把所有配对收集起来,构成可批量执行的增强测试集。
    T+={(x,y)∣x∼Dinput, y=Ref(x)}\mathcal{T}^{+}=\{(x,y)\mid x\sim\mathcal{D}_{\text{input}},\ y=\mathrm{Ref}(x)\}

对抗性测试:专挑边角料来刁难

驾校教练最会“刁难”学员:专挑下雨天、夜间、急刹车来考。林老师也一样,普通题目考不出真功夫,就把陷阱埋在边界上:空数组、负数、超大数值、深层嵌套……这些边角料恰恰是“背答案”型学生最怕的。

对抗性测试就是这套思路的工程化:人类工程师总结“模型最容易翻车”的输入类型,再用程序批量构造。以“找最大值”函数为例,样例全是正数,模型把初始值设为 0 也能蒙混过关;但增强测试偏要给全负数——这种实现立刻露馅,因为正确的最大值应该是 -2 而不是 0。

除了边界输入,还有两类“刁难”手段。其一是随机扰动:对合法输入做微小改动,观察输出是否突变,揪出对输入敏感的错误实现。其二是性能压力:给每个测试设置超时上限,死循环和指数爆炸的代码直接判挂。这些手段让测试从“验证正确性”升级为“挑战鲁棒性”。

专挑边角料的考题,让只会“背样例”的模型毫无还手之力;真正的内功——对边界条件的正确处理——这才显山露水。出题老师越刁钻,学生的真实水平就越藏不住。

ϕ(x)={∅,x is emptyxflip,x is reversed or negatedx×106,x is scaled up\phi(x)=\begin{cases}\varnothing, & x\text{ is empty}\\[2pt] x_{\mathrm{flip}}, & x\text{ is reversed or negated}\\[2pt] x\times10^6, & x\text{ is scaled up}\end{cases}
φ 是一个“刁难变换器”,把普通输入 x 映射成边界输入:空值、翻转值、放大值等,专治只会处理“标准样例”的模型。
  1. 空值注入把输入置为空集合,检查函数对空输入的保护逻辑。
    ϕ(x)=∅\phi(x)=\varnothing
  2. 翻转取负将输入反序或取负,打乱模型对“样例惯性”的依赖。
    xflip=reverse(x) 或 −xx_{\mathrm{flip}}=\mathrm{reverse}(x)\ \text{或}\ -x
  3. 规模放大把输入放大百万倍,制造超大数组或大数运算压力。
    xlarge=x×106x_{\mathrm{large}}=x\times10^6

变异测试校验:给考试题“验毒”

林老师有句口头禅:“好题要经得起卧底检验。”每次出完卷子,他都请几个“故意做错”的卧底学生先考一遍——如果卧底都能考满分,说明题目太水,必须重出。这套土办法,在软件工程里有个正儿八经的名字:变异测试。

变异测试的做法是:把参考实现改出一些小 bug,产生一批“变异体”。比如把 > 改成 <、删掉空值保护、去掉某个分支。然后用待检验的测试套件去“考”这些变异体:能被判错,说明测试有效;如果变异体“幸存”下来,说明测试还没覆盖到那一类错误,套件存在盲区。

HumanEval+ 正是用变异测试来筛选和校验自动生成的测试用例,剔除那些质量差、抓不住错误的“废题”。衡量指标叫变异分数:被测试杀死的变异体占全部变异体的比例。原版测试只能杀死一部分变异体,增强测试则能把绝大多数变异体“绳之以法”。

有了“验毒”环节,林老师才敢把卷子发下去——测试用例不是越多越好,而是每一道题都要经得起卧底挑战。数量是增强的外衣,变异分数才是增强的内核。

MS=MkilledMtotal×100%\mathrm{MS}=\frac{M_{\mathrm{killed}}}{M_{\mathrm{total}}}\times100\%
变异分数 = 被测试抓获的变异体数 ÷ 变异体总数。分数越高,测试套件越“毒”,越能防止作弊代码蒙混过关。
  1. 制造变异体给参考实现注入微小 bug,获得一批“带病答案”。
    Mtotal={mutant1,mutant2,… }M_{\mathrm{total}}=\{\mathrm{mutant}_1,\mathrm{mutant}_2,\dots\}
  2. 执行测试用测试套件逐一检验变异体,判错的记为被杀死。
    Mkilled={m∈Mtotal∣Tests(m)=fail}M_{\mathrm{killed}}=\{m\in M_{\mathrm{total}}\mid \mathrm{Tests}(m)=\mathrm{fail}\}
  3. 计算分数死亡比例即变异分数,衡量套件对错误的敏感度。
    MS=MkilledMtotal×100%\mathrm{MS}=\frac{M_{\mathrm{killed}}}{M_{\mathrm{total}}}\times100\%

评测可靠性提升:挤掉分数的水分

试卷变严之后,成绩单上的“水分”被挤了出来。小码从 90 分掉到 65 分,反而那个一直默默无闻、会推导的学生稳住了 80 分。分数下降了,但对能力的判断却更真实了——这才是严格考试的意义。

在真实评测中,论文报告 ChatGPT 的 pass@1 从 HumanEval 上的约 65.8% 下降到 HumanEval+ 上的约 48.1%。近 18 个百分点的差距,就是被挤掉的“水分”:原版测试太少造成的假阳性。注意,模型本身没有变笨,是测量标准变严了,虚高的分数被还原成可信的能力估计。

研究者用增强测试重新评估大量模型后发现:分数普遍下降,但下降幅度各不相同。越是“背题”的模型掉分越多,而真正具备泛化能力的模型掉分有限。于是,评测的置信度大幅提升——分数背后的每一个百分点,都有了成百上千个测试用例撑腰。

严格考试的意义正在于此:宁可分数难看,也要让每一个分数都经得起推敲。挤掉水分后的通过率,才是业内人士敢用来下结论、做对比的硬信号。

Δp=pHE−pHE+≈17.7%\Delta p = p_{\mathrm{HE}} - p_{\mathrm{HE+}}\approx 17.7\%
Δp 表示同一模型在增强前后通过率之差。差值越大,说明原版分数虚高得越厉害,水分被挤得越多。
  1. 原版通过率模型在 HumanEval 上的 pass@1,是“宽松考卷”的成绩。
    pHE=65.8%p_{\mathrm{HE}}=65.8\%
  2. 增强通过率同一模型在 HumanEval+ 上的 pass@1,是“严格考卷”的成绩。
    pHE+=48.1%p_{\mathrm{HE+}}=48.1\%
  3. 水分差值两率相减,量化虚高部分,就是被挤掉的水分。
    Δp=65.8%−48.1%=17.7%\Delta p=65.8\%-48.1\%=17.7\%

模型排名与能力:重新洗牌见真章

周考放榜那天,班里炸开了锅:好几个“常胜将军”跌出前十,一个平时被低估的学生挤进前三。林老师却一点都不意外——题目没变难,只是更全面了,谁在裸泳,一目了然。

模型排行榜也在经历同样的洗牌。有些模型在原始 HumanEval 上表现亮眼,是因为训练时见过相似样本,或恰好贴合原测试的输入分布;一旦换成 HumanEval+ 的“千题考卷”,这类“应试型”模型排名明显下滑,而真正泛化能力强的模型保住了位置。这种重排,直接暴露了模型对基准的过拟合。

排名位移量化了这个过程:以模型 m 为例,计算它在两套基准上的名次之差。位移为正,说明排名下滑,提示该模型可能对原基准存在过拟合;位移接近零,则说明能力稳健。这让排行榜从“热闹”变成“可信”,也让模型选型有了更扎实的依据。

榜单洗牌是好事——它把“会考试”和“会写代码”分开,让真正有实力的模型站上领奖台。这也是评测存在的终极意义:不是制造热闹,而是提供可靠的判断依据。

ρ(m)=rHE+(m)−rHE(m)\rho(m)=r_{\mathrm{HE+}}(m)-r_{\mathrm{HE}}(m)
ρ(m) 是模型 m 在增强排行榜与原排行榜之间的名次位移。正值越大,代表被挤掉的水分越多,过拟合嫌疑越大。
  1. 原榜名次模型 m 在宽松考卷 HumanEval 上的排名。
    rHE(m)r_{\mathrm{HE}}(m)
  2. 增强名次模型 m 在严格考卷 HumanEval+ 上的排名。
    rHE+(m)r_{\mathrm{HE+}}(m)
  3. 名次位移两排名之差揭示洗牌方向,正值代表下滑。
    ρ(m)=rHE+(m)−rHE(m)\rho(m)=r_{\mathrm{HE+}}(m)-r_{\mathrm{HE}}(m)

局限与未来趋势:严格考试的代价

严格考试并非没有代价。林老师的阅卷量暴涨了 100 倍,批一张卷子从一盏茶的功夫变成一整天;偶尔还会发现,某道题的“标准答案”本身就有问题——卧底也有看走眼的时候。

HumanEval+ 的局限主要有三。其一,计算成本:数百上千个测试 × 每题超时上限 × 多次采样,评测费用和时间显著上升。其二,依赖参考实现:如果参考答案本身带 bug,生成的期望输出会“继承”错误,测试可能把错误答案当成标准。其三,无法完全消除偏差:任何静态测试集都难以覆盖真实世界无限多变的需求。

趋势上,研究者正在探索动态测试生成、面向模型弱点的“个性化对抗”,以及结合运行时反馈的自适应测试。增强测试不是终点,而是“让评测跟上模型进化”这场持久战的开端——考题会越来越聪明,学生也会越来越强。

林老师最后还是坚持升级考卷——因为比起“考得舒服”,他更在意“判得准确”。评测的进化从来都是成本与可信度的博弈,而可信度,永远值得多付一点代价。

Ctotal=∑j=1164nj+×TtimeoutC_{\mathrm{total}}=\sum_{j=1}^{164}n_j^{+}\times T_{\mathrm{timeout}}
C_total 表示一次完整增强评测的总耗时或总成本,是“每题测试数 × 超时上限”的累加,直观解释了严格评测为什么更贵。
  1. 单题测试量每题新增的测试用例数量,增强后动辄成百上千。
    nj+n_j^{+}
  2. 超时上限每个测试允许的最大执行时间,防止死循环拖垮评测。
    TtimeoutT_{\mathrm{timeout}}
  3. 总成本累加所有题目的测试开销,得到一次完整评测的总代价。
    Ctotal=∑j=1164nj+×TtimeoutC_{\mathrm{total}}=\sum_{j=1}^{164}n_j^{+}\times T_{\mathrm{timeout}}

AI 应用场景

场景 1:大模型发布前的“严考”压测

阶段:模型评测与上线前验证

解决的问题:传统评测只看 HumanEval 等小样本基准,pass@1 虚高,模型上线后真实代码质量落差大。用增强测试能提前暴露边界缺陷,降低线上事故风险。就像小码的周考分数再高,也只有换了刁钻考卷才知道它真的会不会。

具体案例:某团队在发布代码大模型前,用 HumanEval+ 重新评估候选模型,发现一个在原始基准上排名第一的模型跌到第五——原因是它对空输入和极端数值处理不佳。团队据此针对性补充训练数据与 SFT 样本,最终发布版的边界用例通过率提升了 15%。

场景 2:自建代码评测集的“验毒”流程

阶段:数据与基准建设

解决的问题:团队自建 benchmark 时手工写测试,容易出现盲区与错误答案,评测结果不可信。引入变异测试的“卧底试考”机制,可以系统排查测试套件漏洞,确保每道题都经得起挑战。

具体案例:数据工程师为内部代码生成评测集编写增强测试后,用变异测试做质量检查:发现 32% 的变异体能存活,说明套件偏弱;随后补充边界用例并剔除 11 条期望输出有误的测试,变异分数从 0.68 提升到 0.95。

场景 3:CI 流水线中的代码生成回归测试

阶段:模型迭代与持续集成

解决的问题:模型每次迭代后,需要快速判断代码生成质量是否回退。小样本测试不稳定、噪声大;增强测试作为回归门禁,能稳定捕捉质量波动,防止劣化版本悄悄上线。

具体案例:MLOps 工程师将 HumanEval+ 的边界子集接入每日 CI,模型每次更新自动跑一遍。某次 prompt 调整导致全负数场景失败率上升 12%,回归门禁当场拦截,避免了劣化版本上线。

Python 演示

python109 行
"""HumanEval+ 增强测试用例设计演示 以找最大值函数为例,演示三件事:1. 原版少量测试如何放走错误代码(假阳性)2. HumanEval+ 式边界测试如何揪出 bug3. 变异测试如何检验测试套件本身的质量""" # 参考实现:标准答案def ref_max(values):    if not values:        return None    max_val = values[0]    for v in values[1:]:        if v > max_val:            max_val = v    return max_val # 模型生成的错版:初值取 0,遇到全负数会判错def buggy_max(values):    if not values:        return None    max_val = 0    for v in values:        if v > max_val:            max_val = v    return max_val # 原版测试:只用正数样例,覆盖面太窄ORIG_TESTS = [    ([1, 3, 2], 3),    ([5], 5),    ([42, 7, 99], 99),] # HumanEval+ 风格增强测试:补齐边界条件EDGE_TESTS = [    ([], None),    ([-1], -1),    ([-5, -2, -9], -2),    ([-3, -1, -2], -1),    ([0, -2, -1], 0),    (list(range(-500, 0)), -1),    (list(range(1, 500)), 499),] def run_suite(solver, suite):    # 任何一个用例不通过就算失败,异常也算失败    for inputs, expected in suite:        try:            result = solver(list(inputs))        except Exception:            return False        if result != expected:            return False    return True def make_mutants():    # 变异体 1:比较方向写反    def m_reverse(values):        if not values:            return None        max_val = values[0]        for v in values[1:]:            if v < max_val:                max_val = v        return max_val     # 变异体 2:去掉比较,无条件更新    def m_no_compare(values):        if not values:            return None        max_val = values[0]        for v in values[1:]:            max_val = v        return max_val     # 变异体 3:删掉空值保护    def m_no_guard(values):        max_val = values[0]        for v in values[1:]:            if v > max_val:                max_val = v        return max_val     return [m_reverse, m_no_compare, m_no_guard] def mutation_score(reference, suite):    slain = 0    total = 0    # 变异测试:让参考实现带着小 bug 去考试    for mutant in make_mutants():        total += 1        if not run_suite(mutant, suite):            slain += 1        else:            print("  存活变异体:", mutant.__name__, "-> 测试未覆盖其错误")    return slain / total def main():    orig_verdict = "通过 (假阳性!)" if run_suite(buggy_max, ORIG_TESTS) else "失败"    edge_verdict = "通过" if run_suite(buggy_max, EDGE_TESTS) else "失败 (成功揪出 bug)"    print("1) 原版测试对错版模型的判定:", orig_verdict)    print("2) 增强测试对错版模型的判定:", edge_verdict)    print("3) 原版测试的变异分数: %.2f" % mutation_score(ref_max, ORIG_TESTS))    print("4) 增强测试的变异分数: %.2f" % mutation_score(ref_max, EDGE_TESTS)) if __name__ == "__main__":    main()
目的:用“找最大值”函数模拟 HumanEval+ 的两大核心——边界测试增强与变异测试校验,直观看到假阳性如何产生、又如何被拆穿。
  1. def buggy_max(values):模拟模型输出的“看似正确”代码:初始值取 0,遇到全负数就会判错。
  2. ORIG_TESTS = [([1, 3, 2], 3), ...]原版少量测试全用正数,覆盖面太窄,让错版代码侥幸全过。
  3. EDGE_TESTS = [([], None), ...]增强测试补上空输入、全负数、超长序列等边界,专治“背样例”。
  4. result = solver(list(inputs))执行被测函数并捕获异常,异常视作失败,保证评测流程不崩溃。
  5. def mutation_score(reference, suite):变异测试入口:让带小 bug 的变异体“卧底考”测试套件。
  6. slain / total变异分数 = 被杀死的变异体占比,衡量测试套件的“毒性”与严谨度。

常见误区

误区既然要增强评测,那就疯狂生成测试用例,数量越多越好,反正量大管饱。质量什么的,不重要。

正解数量多不等于质量高。HumanEval+ 专门引入变异测试来“验毒”:如果多个变异体(带小 bug 的代码)都能通过测试套件,说明题目有漏洞。就像林老师请卧底试考——卧底都能考满分,考卷就得重出。衡量测试质量的指标是变异分数,而不只是总数。

为何常见:人容易把“量大”等同于“严格”,忽略了测试可能携带错误期望输出或存在覆盖盲区。

误区ChatGPT 从 65.8% 掉到 48.1%,是不是模型更新之后能力退化了?

正解分数下降不是模型退化,而是挤掉了原版测试不足造成的假阳性水分。更准确的理解是:增强测试把“部分靠运气”的分数还原为“真实能力”的估计。就像考试变严,学生成绩降了,但学习水平并没有变。同一个模型,只是测量尺子变准了。

为何常见:人们习惯用绝对分数衡量能力变化,忽略了基准本身的标准在变,误把“分数差”当成“能力差”。

误区测试都做到几千个用例了,评测结果应该绝对客观公正了吧?

正解偏差仍然存在:期望输出依赖参考实现,参考实现若有 bug,新测试会继承错误;静态测试集无法覆盖真实世界无限多变的需求;运行成本限制采样数量,也会引入统计波动。增强只能大幅降低偏差,无法归零。就像林老师的考卷再全,也测不出学生考场外的真实协作能力。

为何常见:“用例越多越客观”的直觉放大了对数量的信心,忽略了误差的残留来源。

误区HumanEval+ 不就是把原来的测试用例复制 N 份,凑够数量吗?复制粘贴我也会。

正解增强不是数量上的重复,而是覆盖上的拓展:构造边界输入(空、负、超大)、随机扰动、类型翻转,并用参考实现重新生成期望输出,最后用变异测试筛选。复制同样的用例只会重复同样的盲区,根本骗不过变异体——林老师出的可是新题,不是把旧题抄一百遍。

为何常见:只看到“数量变多”的表面,没看到“输入分布”和“期望输出”的重新构造才是增强的灵魂。

面试题

Q1. 以下是 HumanEval+ 最核心的增强手段

单选题 · easy

  • A.增大模型参数规模
  • B.大幅增加测试用例← 正确答案
  • C.改用中文提示词
  • D.扩充模型训练数据

答案:B。HumanEval+ 的“+“字精髓在于给每道题增加成百上千个测试用例,而不是改模型、改提示词或改训练数据。就像林老师升级考卷的核心动作,是把检测点从 7.7 个加码到约 774 个,用”多测”来压缩背题蒙混的空间。

Q2. 原版 HumanEval 每题平均约含多少个测试用例

单选题 · easy

  • A.约 7.7 个← 正确答案
  • B.约 77 个
  • C.约 774 个
  • D.约 7740 个

答案:A。论文统计原版 HumanEval 每题平均约 7.7 个测试用例,这正是假阳性的温床——检测点太少,背样例就能过关。约 774 个是 HumanEval+ 增强后的数据,两者相差约 100 倍。

Q3. “假阳性”在代码评测中指的是

单选题 · mid

  • A.代码运行时报错崩溃
  • B.错误代码却通过全部测试← 正确答案
  • C.正确代码被错误判为失败
  • D.测试用例运行时间超时

答案:B。假阳性 = 明明错了却被判对。原版测试用例少,错误代码碰巧通过了全部测试,就是假阳性。林老师用刁钻的新题拆穿的正是它——就像全负数输入让“初值取 0”的错误实现当场现形。

Q4. 变异测试在 HumanEval+ 中的主要作用是

单选题 · mid

  • A.让模型生成更多候选代码
  • B.检验测试套件能否抓住错误← 正确答案
  • C.加速测试用例的执行速度
  • D.扩充模型的预训练语料库

答案:B。变异测试是“验毒”环节:制造带小 bug 的变异体去考测试套件,杀不死变异体就说明测试太水。它的目的不是生成代码、加速测试或扩充语料,而是给测试套件本身做质量审计,确保新题经得起卧底挑战。

Q5. 以下哪些属于 HumanEval+ 覆盖的边界条件

多选题 · mid

  • A.空列表与空字符串输入← 正确答案
  • B.全负数与零值输入← 正确答案
  • C.超大数组与超长字符串← 正确答案
  • D.仅与样例一致的输入

答案:ABC。空输入、全负数、超大数组都是典型边界条件,是增强测试重点补强的对象。只测与样例一致的输入恰恰是原版的弱点,不属于增强边界。林老师出的新题专挑这些边角料,而不是重复样例。

Q6. 某模型 HumanEval 分数 66%,HumanEval+ 只有 48%,最合理的解读是

单选题 · hard

  • A.模型推理能力突然退化
  • B.原分数存在测试不足的水分← 正确答案
  • C.增强测试用例全部标注错误
  • D.测试环境出现随机性故障

答案:B。同一模型、同一份代码能力,增强前后分数相差约 18 个百分点,主要原因是原版测试太少造成假阳性,分数虚高。模型没有变笨,是测量标准变严了。就像小码周考高分,换了刁钻考卷才暴露真实水平。

Q7. 下列哪些现象说明测试套件本身质量差

多选题 · hard

  • A.变异分数明显偏低← 正确答案
  • B.大量变异体能存活通过← 正确答案
  • C.覆盖了众多边界条件
  • D.变异测试杀死全部变异体

答案:AB。变异分数低、变异体大量存活,说明测试连“明显错误”都抓不住,套件存在盲区,质量差。覆盖边界条件和杀死全部变异体是质量好的表现。卧底全都能满分,就是考卷太水的铁证。

Q8. HumanEval+ 中新增测试的期望输出主要来自

单选题 · mid

  • A.人工逐条标注正确答案
  • B.用参考实现运行得到← 正确答案
  • C.被评测模型自行生成
  • D.从训练集中随机抽取答案

答案:B。期望输出由参考实现运行输入得到,这样才能自动化生成大量测试。人工标注成本太高,让被测模型自己出答案则会导致“自己考自己”的标准偏差。就像标准答案要请最靠谱的优等生来写,而不是随机抽人。

Q9. HumanEval+ 目前存在的主要局限包括

多选题 · hard

  • A.大规模测试运行成本高← 正确答案
  • B.参考实现错误会被继承← 正确答案
  • C.完全消除了所有评测偏差
  • D.每题只生成少量测试用例

答案:AB。HumanEval+ 的局限包括测试规模带来的计算成本,以及期望输出依赖参考实现、其错误会被继承。它大幅降低偏差但无法完全消除。选项 C 把“降低”说成“消除”,过于绝对;D 与事实相反。

Q10. 若用于生成测试的参考实现带有 bug,会发生什么

单选题 · extreme

  • A.增强测试会继承同样的错误预期← 正确答案
  • B.变异测试可以自动修复错误
  • C.所有模型在该题的分数必然一致
  • D.该题测试会直接失效无法运行

答案:A。参考实现是期望输出的唯一来源,它带 bug 时,新生成的测试会把错误答案当成标准答案,即“继承错误”。变异测试能发现测试质量差、提示套件可能有问题,但它只能“验毒”,不能自动修复参考实现的 bug,也不能让所有模型分数一致——这正是 HumanEval+ 局限性的典型体现。