Coding 评测
Coding 评测通过编译、测试和真实仓库任务衡量代码生成与修改能力。它覆盖从给定描述生成函数、到在多文件仓库中定位并修复缺陷的多种场景。
代码能力评测的演进反映了模型能力边界的迁移:早期以 HumanEval(164 道手写函数题)和 MBPP 为代表的「函数补全」任务,衡量模型从 docstring 生成单个函数的能力;随着模型能处理更长上下文与真实工程问题,评测重心转向 SWE-bench 这类「给定 GitHub issue、产出能通过测试的补丁」的仓库级任务;而 LiveCodeBench 则通过持续采集时间截止点之后的竞赛新题,缓解公开题集被训练数据污染的问题。这一脉络从「单函数正确性」走向「多文件工程正确性」与「防污染」,是理解代码评测差异的主线。
快速开始¶
在隔离容器固定语言版本、依赖、时间限制和隐藏测试;记录无效代码、超时与安全违规。
评测环境应是一个干净的隔离容器,预装固定的语言运行时和依赖版本,并禁用或严格限制网络,防止模型在执行阶段拉取外部代码或依赖。每道题都要配置隐藏测试,即评测时模型不可见的单元测试或集成测试,用于判定功能正确性。
对每次生成的代码,先尝试编译或解释执行,记录三类结果:无法解析或无法编译的无效代码、执行超时或内存超限、以及通过或未通过测试。安全方面还要监控进程是否尝试越权访问文件、发起外联或执行危险命令,并在受限权限下运行代码。
一个可复现的最小流程是:用同一套题集、同一提示模板和同一采样参数运行两次,比较 pass@1 是否稳定;若波动明显,说明采样或环境仍有未固定因素。以下是一个固定关键参数的最小评测配置:
TASK = "humaneval"
MODEL = "checkpoint-ckpt"
SAMPLING = {"temperature": 0.8, "top_p": 0.95, "samples_per_problem": 20}
RUNTIME = {"image": "python:3.11-slim", "timeout_sec": 3, "network": "off"}
验证成功的标准:同一配置下连续两次运行得到的 pass@1 差值应在统计噪声范围内;对同一道题用同一随机种子重跑,判定结果必须一致。
指标¶
pass@k 衡量多次采样至少一次通过的概率。不同 k、推理预算和工具权限对应不同成本,不能直接比较。
pass@k 的标准定义来自 Codex 论文 Evaluating Large Language Models Trained on Code:对一道题独立采样 n 个答案,其中 c 个通过测试,则「从 n 个里任取 k 个、至少有一个正确」的无偏估计为:
其中 \(\binom{n}{k}\) 为组合数,表示从 n 个样本中选 k 个的方案数;\(\binom{n-c}{k}\) 是「k 个样本全部来自 n-c 个失败样本」的方案数,二者之比即「k 个全错」的概率,1 减去它得到「至少一个对」的概率。它刻画的是「允许重试 k 次时至少一次成功」的概率,而非单次正确率,因此 pass@1 和 pass@10 的含义差异很大。HumanEval 的官方做法是每题采样 n=200 次,再代入上式估计,而不是真的只生成 k 个。
随着 k 增大,pass@k 单调上升,但成本也成倍增加,因为每次采样都要重新执行测试。推理预算和工具权限同样影响可比性:允许模型运行测试并在失败后修正(迭代式或工具增强式)的配置,与一次性生成后再统一判分的配置,其 pass@k 完全不可直接对比。
报告结果时应同时注明 k、采样次数 n、温度等采样参数、是否提供执行反馈,以及测试集是否公开。公开题集若已被训练数据覆盖,分数会被抬高,此时应补充去污染处理或使用时间后新题(如 LiveCodeBench)验证。
案例¶
同一题集在无工具和可运行测试两种设置下评测,分别报告成功率与平均执行次数,区分模型能力和环境辅助。
场景一为纯生成:模型只输出代码,不执行、不获得任何运行时反馈,评测方统一编译并跑测试。场景二为工具增强:模型可以在沙箱里运行测试,读取报错后多次修改,直到通过或达到步数上限。
对两种场景分别统计任务成功率,并额外记录场景二的平均执行次数与「通过前尝试次数」。若场景二显著更高,只能说明模型能从错误反馈中迭代修复,而不能把提升归因于更强的生成能力;真正衡量模型能力的应是场景一的 pass@1。
一段最小判分逻辑如下:
import math
def pass_at_k(n, c, k):
if n - c < k:
return 1.0 # 失败样本不足 k 个,任取 k 个必然含正确样本
return 1.0 - math.comb(n - c, k) / math.comb(n, k)
# n=20, c=12, k=1 -> 单次正确率 0.6
print(pass_at_k(20, 12, 1)) # 0.6
print(pass_at_k(20, 12, 10)) # 1.0
其中当 \(n-c < k\) 时分子组合数为 0,「k 个全错」概率为 0,pass@k 直接取 1;这体现了「样本里已正确答案足够多」的边界情形。
常见失败点包括:隐藏测试覆盖了公开测试未触及的边界条件、模型针对公开测试过拟合、以及超时导致本该通过的实现被判失败。排查时应先确认隐藏测试的正确性与覆盖范围,再归因于模型。