餐厅要在三天内从十位应聘厨师里挑出一个能上岗的,你会怎么考核?让每个人都做一桌国宴显然不现实。更聪明的办法是:先让他们各自炒一盘西红柿炒蛋——材料简单、步骤固定,但火候、调味、出锅时机全都藏在这道家常菜里。AI代码模型也面临同样的选拔问题:模型那么多,不可能每个都用最难的考题去测。于是,就需要一套“入门考核菜”。 这套考核菜就是我们要讲的 MBPP 基准。MBPP(Mostly Basic Python Problems,大多是基础Python题)由 Google Research 在 2021 年提出,包含 974 道入门级 Python 编程题。它像一份标准化的“西红柿炒蛋考核”:题目描述简单,只需实现十几行以内的基础函数,评测系统用自动测试用例代替评委打分,一次性判断大模型是否真的会写基础代码。 当然,光考一盘菜还不够。MBPP 分数高,只能说明基本功扎实,不能说明能当主厨。所以业内通常把它和更难基准(如 HumanEval)搭配使用,还要警惕“厨师提前背过菜谱”的数据污染问题。读完这篇文章,你会掌握这套入门考核的题目设计、评分公式与防作弊手段。
对 AI 从业者而言,MBPP 是代码大模型评测的“第一道门槛”:掌握它能让你快速完成模型初筛、读懂各类榜单分数,并避开数据污染这个最常见的刷分陷阱。
目录
可视化演示
展示MBPP基准的pass@k指标计算过程(k次采样至少一次通过的概率),以及MBPP与HumanEval基准的多维度对比。
本节配有交互动效(进入视口后自动加载,约 3KB)。
pass@k指标计算 采样生成:模型对每题生成k个候选答案 通过判定:每个答案通过全部测试用例才算成功 概率计算:k次中至少1次通过的概率 pass@k = 1 - C(n-c,k)/C(n,k) k越大通过概率越高
基准概览:一张“入门考核试卷”长什么样
餐厅后厨要招人,老板拿出一套统一的“入门考核试卷”——不考满汉全席,而是考西红柿炒蛋、酸辣土豆丝这类家常菜。为什么要统一?因为如果每个厨师做不同的菜,分数就没法比。MBPP 基准就是 AI 界的这套“入门考核试卷”:它给所有大模型出同一批基础 Python 题,让分数变得可比。
MBPP 的全称是 “Mostly Basic Python Problems“,意为”大多是基础 Python 问题“。它由 Google Research 在 2021 年提出,最初出现在 ”Program Synthesis with Large Language Models” 这篇论文中。研究者在探索大模型能否自动写代码时,意识到需要一套标准化的入门级考题,于是从网上公开的代码片段和教程中整理出 974 道基础编程题,并请人类专家逐一验证,确保每道题都可解、表述没有歧义。
这 974 道题被划分为训练、验证和测试三个子集。每道题都是一个“函数级小任务”:包含一句自然语言描述、一个函数签名、一个参考答案,以及约 3 个自动生成的测试用例。评测时,模型根据描述和签名写出函数体,评测器把函数体与测试用例拼在一起运行,测试全部通过才算做对。
所以,当你看到某个模型在 MBPP 上拿到分数,其实是在看它“西红柿炒蛋考核”的成绩单。这张成绩单虽然不能说明它会做满汉全席,但至少能告诉你:它有没有基本的厨房基本功。
- D_MBPP 是数据集记号MBPP 基准的数学记号,代表整个评测题库。
- 每个三元组对应一道题每道题由题目描述、函数签名和测试用例三部分组成。
- 下标 i 遍历全部题目i 从 1 到 974,说明题库中共有 974 道这样的题。
题目设计:每道菜都写着“新手友好”
翻开这份“家常菜考核菜谱”,你会发现菜色都很基础:煮个蛋、切个丝、抓把盐。MBPP 的题目设计也是这样“新手友好”——它刻意避开了复杂的算法与数据结构,让每一道题都能在几十秒内读懂。
MBPP 的绝大多数题目属于“函数级入门题”:要求模型根据自然语言描述,补全一个函数体。常见考点包括:基本的算术运算、字符串拼接与替换、列表的增删查改、简单的条件判断与循环。这些能力对应程序员日常编码中最频繁的“肌肉记忆”,就像厨师的基本刀工和火候。
以一道典型题目为例:“编写一个函数 add,输入两个整数,返回它们的和。” 模型需要输出的代码是 def add(a, b): return a + b。配套的测试用例会断言 add(1,2)==3、add(0,0)==0、add(-1,1)==0。题目设计的关键是“每个任务都有明确的输入输出、有限的状态空间、可自动验证”——这正是它适合做大模型评测的原因。
正是这样一道道“看一眼就知道怎么做”的题,让 MBPP 成了厨房里的“基本功摸底”:不考花活,只考手上功夫。
- T_add 是测试集add 函数配套的测试用例集合。
- 每条映射是一条断言输入 1 和 2 时,期望输出 3;其余两条类似,都是“给定输入,检查输出”。
- 映射覆盖边界情况三组映射分别验证正数、零与负数的输入,保证函数不是“蒙对”。
HumanEval 对比:家常菜与创意菜的分工
餐厅考核有两种:一种是家常菜考核,看基本功;另一种是创意料理考核,看算法和构思。在 AI 编程评测里,MBPP 是前者,HumanEval 就是后者。
HumanEval 由 OpenAI 在 2021 年提出,包含 164 道手写的编程题。这些题目更偏算法思维:链表反转、二叉树遍历、动态规划、递归都能看到。而 MBPP 的 974 道题则聚焦基础语法和常见标准库。如果把 HumanEval 比作“法餐考核”,MBPP 就是“家常菜考核”——两者难度明显不同。
具体差异体现在三个维度:题量上,974 对 164,MBPP 几乎是 HumanEval 的 6 倍,统计上更稳定;难度上,MBPP 大多是 10 行以内的简单函数,HumanEval 则需要多步推理,模型在 MBPP 上的 pass@1 普遍高出 15~30 个百分点;考核侧重上,MBPP 看重“能否调用正确的 API”,HumanEval 看重“能否构造正确的算法”。因此业界常把它们搭配使用:先用 MBPP 筛基层次,再用 HumanEval 拉开差距。
所以别用西红柿炒蛋的分数去评判一个厨师会不会做惠灵顿牛排——MBPP 与 HumanEval,一个是基础功底,一个是进阶实力,各有各的考法。
- 分子是 MBPP 题量MBPP 题库包含的题目数量。
- 分母是 HumanEval 题量HumanEval 题库包含的题目数量。
- 比值约等于 6说明 MBPP 题量约是 HumanEval 的 6 倍,样本更多,统计误差更小。
pass@k 指标:给厨师多次出菜的机会
考核时如果只让厨师炒一次蛋,不小心手抖糊了,能说明他不会炒吗?更公平的办法是让他炒 k 次,只要有一次成功就算过关。pass@k 就是这么一回事。
pass@k 是代码生成评测最核心的指标,指“模型生成 k 个候选答案,其中至少一个通过所有测试用例的概率”。常见口径有 pass@1 和 pass@100。k 越大,对模型越宽容,体现的是模型在“多次试错”下的上限;pass@1 则贴近真实使用中“只生成一次”的体验。
直接枚举所有 k 子集在计算上很昂贵,论文给出一个高效的无偏估计器:让模型对每道题生成 n 个候选,假设其中有 c 个通过测试,则 pass@k 的估计公式如下:
所以说,pass@k 是“给你 k 次机会”的宽容考核,而 pass@1 是“只给一次机会”的实战考核。两个人汇报成绩时,最好把两个数字都亮出来,才不会被漂亮的 k 值迷惑。
- 生成 n 个候选答案对一道题,让模型采样 n 个不同的候选实现,n 要不少于 k。
- 统计通过数 c逐个运行测试用例,通过测试的候选数量记为 c,则失败数为 n-c。
- 求“随机抽 k 个全失败”的概率从 n 个候选中抽取 k 个,全部落在失败集合里的可能性。
- 取补集得 pass@k用 1 减去该概率,并跨题目取期望,就得到无偏估计。
评测规范:评委的标准化评分表
有了考核试卷,还得有严格的评分流程:评委不能尝一口就拍板,而是对着标准答案逐项打分。MBPP 的评测规范就扮演了这个角色。
MBPP 评测是“全自动”的:模型输出代码后,评测系统把它和题目配套的测试用例放到同一段代码中运行,只有全部断言通过,这道题才算得分。整个过程不依赖人工打分,避免了主观偏差——就像评委不看菜品的摆盘,只按固定标准尝味道。
评测系统有几个硬性要求:第一,运行环境要与外界隔离(沙箱),避免候选代码访问网络或文件系统;第二,每道题有超时限制(通常 3~5 秒),防止死循环拖垮整个评测;第三,要用统一的解释器版本和依赖环境,保证不同模型得分可比;最后,结果按题目汇总,统计通过题数占总题数的比例,得到最终的 pass 率。
有了这套标准化评分表,哪怕是不同团队来评测,只要按规矩走,分数都可复现、可比较——就像所有厨师用同一把尺子量刀工。
- 单题得分取 0 或 1模型在第 i 道题上的成绩是一个二元变量。
- 全过才记 1 分该题所有测试用例都通过,才记 1 分。
- 否则记 0 分任一用例失败、运行超时或抛出异常,均记 0 分。
数据污染:偷看过菜谱的“作弊厨师”
如果考核前一天,某位厨师偷偷拿到了菜谱和答案,第二天他当然能轻松过关——但这份高分经不起推敲。MBPP 评测中最常见的坑,就是这种“偷看答案”的数据污染。
数据污染指的是:大模型的预训练语料中混入了 MBPP 的测试题目(比如网上公开的 GitHub 仓库、评测集原文),导致模型在训练阶段就“见过”考题。被污染模型的 MBPP 分数会严重虚高,却并不能反映真实的代码生成能力——就像背过答案的学生,换一套新题就露馅。
检测污染有多种手段:最常用的是 n-gram 重叠检测——把 MBPP 的题目与训练语料切分成连续片段,统计有多少题目在训练语料中出现过;还可以用嵌入向量的余弦相似度,找出“语义相似但字面不同”的变体。防护措施包括:定期发布新题目、对测试集做严格去重、监控模型在时间轴上的分数是否异常跳升。
所以,看到一份高得离谱的 MBPP 榜单时,先别急着赞叹,多问一句:“这位厨师是不是提前看过菜谱?”——防污染,才是评测可信的底线。
- 总测试题量测试集中题目的总个数。
- 可疑命中题量与训练语料比对后“疑似见过”的题目数量。
- 计算污染率命中数除以总数再乘 100%,得到百分比形式的污染率。
应用定位:用入门考核做选型地图
考完西红柿炒蛋,老板心里有了底:这道菜都不及格的厨师,肯定不能要;但拿了满分的人,也未必就能掌勺婚宴大席。MBPP 在模型选型中的定位,正是这样一道“过滤菜”。
在代码大模型选型中,MBPP 适合做第一道快速初筛:候选模型众多(Code Llama、StarCoder、DeepSeek-Coder、GPT-4 等),全部用复杂基准评测成本很高,先跑一遍 MBPP,把基础能力不达标的候选直接排除,再用更难基准对通过者做精测。
同时要清醒认识 MBPP 的局限:第一,入门题多,模型分数容易饱和(一流模型的 pass@1 已达 85% 以上),区分度下降;第二,存在数据污染风险;第三,它不测代码安全性、可维护性等生产关切。因此业界通常采用“组合打榜”:MBPP + HumanEval + 更难的专项基准(如 SWE-bench、LiveCodeBench),综合判断模型能力。
MBPP 就像招聘流程里的第一轮笔试:题目不难,但能高效筛出“连基本功都不过关”的简历。过了这一关,后面还有更难的面试轮次等着——这才是它的正确打开方式。
- 基础能力分模型在 MBPP 上的 pass@1,代表基本功。
- 进阶能力分模型在 HumanEval 上的 pass@1,代表算法实力。
- 加权求和得综合分用 alpha 控制两个分数的权重,得到面向业务侧重的总分。
AI 应用场景
代码模型选型初筛
阶段:模型评测与选型
解决的问题:团队要在 Code Llama、DeepSeek-Coder 等多个开源代码模型中选一个接入 IDE 插件,传统方式是人工写几条测试用例试一把,主观且覆盖不足。用 MBPP 跑一遍,能自动对比各模型的基础代码生成能力,几小时就能筛掉明显不行的候选。
具体案例:某公司选型时用 MBPP 对 3 个开源模型做 pass@1 评测,发现模型 A 在字符串处理类题目上明显落后,模型 B 综合通过率最高,最终选定模型 B 进入下一轮 HumanEval 精测。
模型迭代回归测试
阶段:模型训练 / 微调后评估
解决的问题:微调后的模型不确定是否学到了新技能,甚至可能丢失原有能力(灾难性遗忘)。定期在 MBPP 上做回归测试,用跑分曲线追踪能力变化,是代码模型团队的标准动作。
具体案例:某大模型团队对代码模型做指令微调后,发现 MBPP 的 pass@1 从 62% 掉到 58%,立即定位到是新增数据破坏了基础函数生成能力,回滚后重新调整数据配比。
数据集污染自查
阶段:数据质量管理
解决的问题:开源模型厂商在构建预训练语料时,如果不小心把 MBPP 测试题也收录进去,模型分数就会虚高,对外发布的报告也失去公信力。用 n-gram 重叠检测做污染自查,是发布榜单前必须走的一步。
具体案例:某评测团队在发布大模型代码能力报告前,用 13-gram 重叠检查 MBPP 测试题与训练语料的匹配度,发现并过滤了 37 道疑似重复题,重新评测后分数下降了 4 个百分点。
Python 演示
# MBPP风格Python函数评测器:运行代码 + 测试用例 + pass@k 估计import randomfrom math import comb # 模拟MBPP的迷你数据集:每道题只有函数签名与若干断言MBPP_LIKE = [ { "signature": "def add(a, b):", "tests": ["assert add(1, 2) == 3", "assert add(0, 0) == 0"], }, { "signature": "def is_even(n):", "tests": ["assert is_even(4) == True", "assert is_even(3) == False"], }, { "signature": "def max_list(nums):", "tests": ["assert max_list([1, 5, 3]) == 5", "assert max_list([]) == None"], },] def safe_run(code, tests): """在受限命名空间中执行候选代码与测试,返回是否全部通过""" namespace = {} try: exec(code, namespace) for test in tests: exec(test, namespace) return True except Exception: return False def estimate_pass_at_k(n, c, k): """pass@k 无偏估计:1 - C(n-c, k) / C(n, k)""" if n - c < k: return 1.0 return 1.0 - comb(n - c, k) / comb(n, k) def dummy_model(signature): """扮演一个'小模型':根据函数签名猜实现,偶尔偷懒写错""" if random.random() < 0.2: return "def _fake():\n pass" if "add" in signature: return "def add(a, b):\n return a + b" if "is_even" in signature: return "def is_even(n):\n return n % 2 == 0" if "max_list" in signature: return "def max_list(nums):\n return max(nums) if nums else None" return "# 无法实现的空代码" def evaluate(model, dataset, n_samples=8, k=1): """每道题生成n_samples个候选,返回平均pass@k""" total_pass = 0.0 for task in dataset: codes = [model(task["signature"]) for _ in range(n_samples)] c = sum(1 for code in codes if safe_run(code, task["tests"])) total_pass += estimate_pass_at_k(n_samples, c, k) return total_pass / len(dataset) if __name__ == "__main__": print("单题示例:生成8个候选,通过5个 => pass@1 =", round(estimate_pass_at_k(8, 5, 1), 4)) print("模拟MBPP平均 pass@1 =", round(evaluate(dummy_model, MBPP_LIKE), 3))
exec(code, namespace)在一张全新的“白纸”命名空间里执行候选代码,避免污染评测环境for test in tests: exec(test, namespace)逐个追加运行测试断言,任一断言失败都会抛异常if n - c < k: return 1.0失败候选数不足 k 时,抽 k 个必然能抽到通过样本,直接返回 11.0 - comb(n - c, k) / comb(n, k)用组合数计算“抽 k 个全失败”的概率,再取补集codes = [model(task["signature"]) for _ in range(n_samples)]让模型对同一道题生成 n 个候选答案c = sum(1 for code in codes if safe_run(code, task["tests"]))统计这些候选中通过测试的个数total_pass += estimate_pass_at_k(n_samples, c, k)把每道题的 pass@k 累加,最后除以题数得平均分
常见误区
误区我给模型测了 MBPP,拿到了 80 分,说明这个模型编程很厉害,其他基准都不用看了,直接上线吧。
正解MBPP 全是入门题,高分只说明基础能力扎实。就像西红柿炒蛋得了满分,不代表能处理满汉全席。必须配合 HumanEval、LiveCodeBench 等更难基准一起看,才能判断模型的真实水平,否则容易被“基础好”误导成“能力强”。
为何常见:MBPP 分数直观、被各类榜单广泛引用,大家容易把“基准分高”直接等同于“模型能力强”,忽略了基准本身的难度定位。
误区反正 pass@k 是给多次机会,我把 k 设成 100,分数肯定最高,榜单上最好看,就这么报给领导。
正解pass@k 衡量的是模型在多次尝试下的通过率,k 越大代表给的机会越多,并不代表模型单次生成质量。实际生产环境中通常只生成一次,pass@1 才更贴近真实体验。发布结果时应同时报告 pass@1 与合适的 pass@k,并说明采样规模 n。
为何常见:看到 k 增大、分数上涨,就误以为是“模型变强了”,其实是混淆了评估口径与模型能力。
误区两个都是测代码生成的基准,名字听起来也像,随便选一个跑完就能交差了,省时间。
正解MBPP 入门、HumanEval 进阶,两者难度和侧重不同:MBPP 偏基础 API 与简单逻辑,HumanEval 偏复杂算法与递归推理。它们的相关性并不完美,就像考驾照,科目一和科目三都得过,单测一项无法完整评估驾驶员能力。
为何常见:两个基准都被归类为“代码生成评测”,表面看很相似,容易让人忽略难度与考察维度的差异。
误区MBPP 每道题都配了测试用例,我的代码全部 assert 通过,说明这段代码没有任何问题。
正解MBPP 每题只有约 3 个测试用例,覆盖非常有限。通过测试只说明“在给定样例上成立”,可能存在边界 bug 或逻辑漏洞。评测本质是“样本验证”而非“形式证明”——就像评委尝一口好吃,不代表整锅菜每个细节都没问题。
为何常见:把自动化测试当作完全验证,忽略了测试覆盖率天然有限的现实。
面试题
Q1. MBPP 基准的题目定位是什么?
- A.算法竞赛级难题
- B.入门级基础函数题← 正确答案
- C.系统设计类题目
- D.机器学习理论题
答案:B。MBPP 的全称是"Mostly Basic Python Problems",题目基本都是十几行以内的入门级函数题,考察基础语法与常见 API,而不是算法竞赛或系统设计。
Q2. MBPP 基准大约包含多少道题?
- A.约160道
- B.约970道← 正确答案
- C.约一万道
- D.约十七万道
答案:B。MBPP 数据集包含 974 道题,远多于 HumanEval 的 164 道。约 970 道是正确量级,一万道和十七万道都明显偏离。
Q3. 关于 pass@k 指标,下列说法正确的是?
- A.全部候选都要通过才算过
- B.至少一个候选通过的概率← 正确答案
- C.只允许一次生成机会
- D.k 越大代表模型越强
答案:B。pass@k 指“生成 k 个候选答案,至少一个通过测试”的概率。它衡量多次尝试下的通过率,k 大不代表单次生成质量高,更不能简单说模型更强。
Q4. 关于 MBPP 与 HumanEval 的区别,下列说法正确的有?
- A.MBPP 题量更大约 974 道← 正确答案
- B.MBPP 难度更低偏基础← 正确答案
- C.HumanEval 以基础函数为主
- D.HumanEval 题目数更多
答案:AB。MBPP 有 974 道题、难度更低,偏基础语法与标准库;HumanEval 只有 164 道、偏算法推理。C 和 D 都把两者特点搞反了。
Q5. pass@k 的无偏估计公式是下列哪一个?
- A.1 减失败组合数除以总组合数← 正确答案
- B.失败组合数除以总组合数
- C.通过样本数除以采样总数
- D.失败样本数除以采样总数
答案:A。pass@k = 1 - C(n-c,k)/C(n,k),即“随机抽 k 个候选全失败”的概率取补。B 算的是全失败概率,C 只是通过率,D 是失败率。
Q6. 评估 MBPP 时需要注意哪些事项?
- A.防止预训练数据混入测试集← 正确答案
- B.在隔离沙箱中运行被测代码← 正确答案
- C.同时报告 pass@1 与 pass@k← 正确答案
- D.评测时不需要设置超时
答案:ABC。数据污染会让分数虚高,沙箱隔离能防止恶意代码,同时报告多个口径更全面。超时控制必不可少,否则死循环会卡死评测,所以 D 错误。
Q7. MBPP 的题目通常以什么形式呈现?
- A.自然语言描述加测试用例← 正确答案
- B.仅给出输入输出样例
- C.完整工程项目代码框架
- D.编译型语言伪代码
答案:A。每道 MBPP 题包含自然语言任务描述、函数签名和若干测试用例,模型需要据此补全函数体。“仅输入输出样例”和“工程框架”都不符合它的设计。
Q8. 如果模型在训练时见过 MBPP 测试集,会导致什么?
- A.会导致评测分数虚高← 正确答案
- B.会导致评测分数偏低
- C.对评测结果没有影响
- D.会导致程序运行报错
答案:A。训练数据包含测试集就是数据污染,模型相当于提前背过答案,MBPP 分数会显著虚高,不能反映真实能力。
Q9. 关于 MBPP 在模型选型中的定位,正确的理解是?
- A.适合代码模型快速初筛← 正确答案
- B.能评估复杂算法能力
- C.应与 HumanEval 结合使用← 正确答案
- D.分数饱和后区分度下降← 正确答案
答案:ACD。MBPP 入门题为主,适合快速初筛,但它测不了复杂算法;一流模型分数接近饱和,区分度下降,所以要和更难基准配合使用。
Q10. 若模型生成 8 个候选样本,其中 5 个通过测试,n=8,c=5,k=1 时 pass@1 是多少?
- A.0.55 的通过概率
- B.0.625 的通过概率← 正确答案
- C.0.70 的通过概率
- D.0.80 的通过概率
答案:B。pass@1 = 1 - C(n-c,k)/C(n,k) = 1 - C(3,1)/C(8,1) = 1 - 3/8 = 0.625。k=1 时它恰好等于通过样本比例 5/8。