Article
如何设计高质量的编程题目:从题面到评估契约
高质量编程题不是更长的 prompt,而是能稳定暴露能力边界的评估契约。本文从 Bloom 层级、难度校准、任务契约、测试设计和题库治理出发,说明如何为 AI Coding Mentor 构建可复现的题目体系。
版权声明与免责声明 本文基于 Bloom 认知分类法、APPS 基准测试设计方法、LiveCodeBench 评估框架等多项研究进行综合解读。原文版权归各自作者与研究机构所有。
观点归属声明 本文提出的分层设计框架、难度分级标准、测试用例设计原则和防套路策略,为作者基于理论研究和工程实践的原创综合。
原文参考
- Bloom Taxonomy — Benjamin Bloom et al.
- APPS Benchmark — Hendrycks et al., Stanford
- LiveCodeBench Methodology — Jain et al., UC Berkeley
原创性质 本文不是逐段翻译,而是将教育学理论与 AI 评估实践结合,重建适合实际应用的题目设计方法论。
开头:好题不是描述更长,而是约束更清楚
很多团队第一次评估 AI 编程能力时,会自然地从一道“看起来像编程题”的需求开始:写一个排序函数,实现一个缓存,做一个表单校验,或者修复一段已有代码。这样的题目能快速启动实验,却很难支撑长期评估。原因不在题目太简单,而在题面没有把任务边界、输入输出、约束条件、验收标准和失败判定说清楚。
对人类工程师来说,模糊需求还有二次澄清的机会。候选人可以反问排序字段、稳定性、异常输入、性能要求和业务优先级。AI 编程助手通常不会稳定地追问,它会直接补全缺失信息:默认语言、默认数据结构、默认边界处理、默认异常策略。看起来它完成了任务,实际只是把题目没有写出来的部分替团队做了假设。
这正是 Coding Mentor 视角下题目设计的核心问题:一道人类觉得“差不多能懂”的题,对 AI 未必是一个可评估任务。可评估任务必须减少隐式假设,让模型的输出主要反映能力,而不是反映它碰巧猜中了出题人的意图。
一条有效的判断标准是:题面能否被不同的人、不同模型、不同时间点重复执行,并得到可比较的评分结果。如果不能,题目就不是评估资产,只是一次性的交互材料。
评估边界:从传统出题到能力层级
为什么传统出题方法不能直接迁移到 AI 评估
传统编程题常常服务于教学、面试或训练。它们默认人类读题者具备上下文理解能力,也默认评价者可以在过程中追加解释、追问思路、观察调试过程。AI 评估的环境不同:模型输入是题面,输出是代码、解释或修复补丁,评分通常依赖测试、静态检查、人工 rubric 或多轮反馈记录。
这会带来三个差异。
第一,题目需要封闭。人类题可以留一些解释空间,AI 评估题不能把关键条件藏在语气里。比如“合理处理异常”不是可评分要求;“当输入为空时返回空列表,当页码越界时返回空结果并保留总数”才是可评分要求。
第二,题目需要抗模式匹配。模型见过大量公开算法题和常见业务片段。题面只要落入熟悉模板,它可能不真正分析需求,而是调用记忆里的标准解法。高质量题目不追求故意刁难,而是通过业务约束、组合边界和验证机制,让模板解法的漏洞暴露出来。
第三,题目需要可校准。AI 能力更新很快。同一道题在不同模型、不同工具权限、不同上下文预算下,通过率可能变化明显。题目难度不能只靠“出题人感觉”,而要绑定评估设置、通过率分布、失败类型和版本记录。
因此,给 AI 设计编程题,不只是写题面,而是在设计一份评估契约。契约的作用是把“我希望模型会什么”转换成“我能观察到什么证据”,再转换成“我如何判断它是否达标”。
从知识点到能力层级:Bloom 分类法的工程化用法
Bloom 认知分类法把学习目标拆成六个层级:记忆、理解、应用、分析、评价和创造。它本来是教育学框架,但在 AI 编程评估里有很强的工程价值,因为它提醒出题者不要把所有题目都写成“实现某个函数”。
不同层级对应不同能力证据。
| Bloom 层级 | 编程能力证据 | 适合观察的问题 | AI 评估风险 |
|---|---|---|---|
| 记忆 | 回忆语法、API、概念名词 | 是否知道某个语言特性或库函数 | 容易被训练语料覆盖,区分度低 |
| 理解 | 解释概念差异和适用场景 | 是否能说明浅拷贝、事务隔离、幂等等概念 | 答案可能流畅但缺少工程约束 |
| 应用 | 按明确要求实现算法或业务逻辑 | 是否能把已知方法落到代码 | 最适合自动化测试,但容易被模板命中 |
| 分析 | 拆解复杂需求、定位瓶颈和边界 | 是否能识别依赖、状态、失败路径 | 需要更细的 rubric 和证据记录 |
| 评价 | 在多个方案之间取舍并说明理由 | 是否能做技术判断和风险权衡 | 不能只用单元测试评分 |
| 创造 | 设计新结构、协议或系统方案 | 是否能组织开放问题并形成架构 | 必须引入人工复核和长期评估 |
多数 AI 编程评估失败,并不是因为题目不够难,而是能力层级混乱。题面说要考“架构能力”,测试却只验证了一个函数是否返回正确列表;题面说要考“问题分解”,评分却只看代码是否运行;题面说要考“工程判断”,rubric 却没有区分安全性、可维护性、性能和可观测性。
Coding Mentor 在出题前应先回答一个问题:这道题到底要观察哪一种能力证据?如果目标是应用层级,就应该给出清晰接口、输入输出和自动化测试;如果目标是评价层级,就必须给出多个候选方案、约束冲突和决策依据;如果目标是创造层级,就要明确架构边界、非功能需求、复核标准和不可接受风险。
难度与任务契约
难度分级体系:从Easy到Hard的设计标准
难度不是题面长度,也不是参考答案行数。一个 20 行函数可能因为边界状态复杂而很难,一个 200 行脚手架也可能只是机械填空。对 AI 评估更有意义的难度定义,是模型在固定评估预算下需要完成多少判断、组合多少约束、暴露多少失败模式。
这里可以把难度拆成两层口径。
第一层是人类参考口径,用来估算题目规模。比如一个熟练工程师完成参考实现大约需要 15 分钟、45 分钟还是更久。这能帮助团队判断题目是否过重,但不能直接套用到 AI。AI 不会按人类时间工作,它的实际能力受上下文长度、工具调用、测试反馈、重试次数和模型类型影响。
第二层是 AI 评估口径,用来固定实验条件。比如是否允许模型读取多文件上下文,是否允许运行测试,是否提供失败日志,是否允许一次修复,是否允许访问外部文档。没有这些条件,所谓 Easy、Medium、Hard 就无法比较。
| 维度 | Easy | Medium | Hard |
|---|---|---|---|
| 目标能力 | 单一概念的正确应用 | 多概念组合和边界处理 | 复杂状态、跨模块约束或方案取舍 |
| 人类参考规模 | 通常 15 分钟以内 | 通常 15 到 45 分钟 | 通常超过 45 分钟 |
| AI 评估预算 | 单轮生成,不提供测试反馈 | 单轮生成加一次测试反馈 | 允许多文件上下文、工具调用和有限修复 |
| 概念数量 | 1 个核心概念 | 2 到 3 个核心概念 | 4 个以上概念或多个子系统 |
| 参考实现形态 | 一个短函数或局部逻辑 | 一个函数组或小模块 | 多函数、多状态或跨模块改动 |
| 边界条件 | 空输入、单元素、重复值 | 多条件组合、分页越界、排序稳定性 | 极值数据、退化路径、并发或一致性问题 |
| 自动化评分 | 单元测试基本可覆盖 | 单元测试加边界与性能测试 | 测试、rubric、人工复核或轨迹审查组合 |
| 预期通过率 | 在目标模型上稳定较高 | 能拉开模型差距 | 主要用于暴露能力边界 |
Easy 题的价值不是证明模型“会写代码”,而是建立基线。它适合检查语法、接口遵循、简单边界和基本测试通过率。高质量 Easy 题也要写清楚输入范围和异常策略,否则通过率高没有意义。
Medium 题是最适合长期评估的主体。它不要求模型做开放式架构设计,但需要在多个规则之间保持一致。例如筛选、排序和分页组合;缓存淘汰和容量控制组合;解析、校验和错误报告组合。Medium 题能比较稳定地暴露模型在边界、复杂度和状态更新上的差异。
Hard 题不应该只是把需求写得更长。真正的 Hard 来自状态空间、约束冲突和评估方式的升级。事务型 KV 存储、批处理任务调度、跨模块重构、并发安全修复、性能瓶颈定位,都属于 Hard 的典型形态。此时只靠“所有测试通过”往往不够,还需要记录模型的计划质量、风险识别、修改范围控制和验证策略。
一个常见错误是用人类难度标签替代 AI 难度标签。某道题对人类是 Medium,但如果模型训练语料里存在大量近似模板,它对 AI 可能只是 Easy。反过来,一道业务规则很简单的题,如果题面存在隐式优先级、异常输入和状态回滚,对 AI 可能已经进入 Hard。难度必须从实际通过率和失败类型中校准,而不是由题目名称决定。
高质量题目的六层任务契约
高质量题目可以被看成六层契约。每一层都回答一个评分问题:模型该做什么、在什么边界内做、怎样证明做对、怎样识别做错。
第一层是任务目标。目标不应停留在“实现一个功能”,而要说明该功能服务的工程场景。场景不是为了增加故事感,而是为了明确优先级。例如同样是排序,运营后台关注稳定性和可解释性,实时推荐关注延迟和吞吐,数据导出关注全量一致性。场景不同,正确解法也不同。
第二层是接口契约。接口契约包括函数签名、参数含义、返回值、错误处理、空值策略和可变性约束。AI 很容易在接口不明确时自行设计数据结构,导致答案看似正确却无法进入统一测试。接口越稳定,评分越可复现。
第三层是数据约束。输入规模、字段范围、唯一性、排序规则、时间格式、编码规则、并发假设,都应显式写入题面。数据约束决定算法选择,也决定测试是否能排除暴力解、隐式类型转换和偶然正确。
第四层是行为约束。行为约束说明遇到边界、冲突和异常时应该怎样处理。例如排序是否稳定,分页页码越界是否报错,重复请求是否幂等,事务失败是否回滚,缓存容量为 0 时如何处理。这一层最容易被忽略,却最能区分“能跑”和“符合工程要求”。
第五层是示例契约。公开示例不是答案提示,而是题意校准。好的示例应该覆盖正常路径、至少一个边界路径和一个容易误解的规则。示例解释应说明为什么输出是这样,而不是只给输入输出。这样可以降低模型靠猜测题意通过的概率。
第六层是验收契约。验收契约说明评分由哪些部分组成:公开测试、隐藏测试、性能测试、静态检查、人工 rubric、日志审查或修改范围审查。只要评分维度没有提前定义,后续评价就容易变成主观印象。
这六层契约不是模板字段,而是出题时必须完成的工程判断。题面可以很短,但这六层不能缺位。缺少任务目标,模型不知道优先级;缺少接口契约,测试无法统一;缺少数据约束,算法选择无法判定;缺少行为约束,边界处理无法评分;缺少示例契约,题意容易被误读;缺少验收契约,结果无法复盘。
从能力目标到测试证据
面向 AI 的题目设计:不要测试模板,要测试判断
AI 编程助手在常见算法题上的表现,往往高于它在真实工程任务中的表现。原因并不神秘:公开题库、博客讲解、题解仓库和训练数据里充满了标准模板。题面越像经典题,模型越容易调用记忆里的套路。
题目设计的目标不是故意设置陷阱,而是让关键判断无法被模板绕过。
第一种方法是加入业务约束。不要只问“实现 LRU 缓存”,而要说明容量为 0、重复写入、读取后是否更新热度、异常 key 如何处理、统计信息是否参与状态。业务约束能迫使模型处理题面中的具体规则。
第二种方法是组合多个普通概念。筛选、排序、分页单独看都不难,组合后就会暴露顺序错误:先分页再排序、先排序再筛选、总数统计位置错误、稳定性被破坏。组合题比孤立题更接近工程任务。
第三种方法是设计对抗性边界。对抗不等于冷门,而是针对常见错误。比如最大输入规模验证复杂度,重复元素验证稳定性,空结果验证返回契约,退化输入验证算法假设,并发调用验证共享状态。
第四种方法是区分题面事实和模型建议。对开放题而言,模型可以提出建议,但不能把建议当成事实。题目应明确哪些约束不可改变,哪些方案可以取舍,哪些风险必须说明。这样才能评价模型是否尊重任务边界。
第五种方法是保留失败证据。一次测试失败本身不是坏事,坏的是失败后没有结构化记录。失败类型、触发输入、违反的契约层、模型修复方式和最终结果,都应进入题目校准过程。长期看,这些失败证据比单次得分更有价值。
一个 Medium 题应该如何从能力目标长出来
题目设计不应该从“我想让模型写什么代码”开始,而应该从“我想观察什么能力证据”开始。
假设目标能力是多条件业务逻辑组合。一个合适的 Medium 题可以围绕商品列表的筛选、排序和分页展开。这个场景足够常见,模型不需要额外理解行业知识;同时它又包含多个容易出错的规则,能观察模型是否真正维护了任务契约。
能力目标可以拆成四项。
| 能力目标 | 可观察证据 | 常见错误 |
|---|---|---|
| 多条件筛选 | 能同时处理价格、评分、分类等条件 | 条件之间误用或关系,空条件处理错误 |
| 稳定排序 | 相同排序键时保留原始相对顺序 | 使用不稳定排序或二次排序破坏结果 |
| 分页语义 | 返回当前页数据和筛选后的总数 | 先分页后筛选,或把当前页数量当总数 |
| 边界处理 | 空列表、空结果、越界页码行为一致 | 抛出未声明异常或返回结构不一致 |
有了能力目标,题面就可以围绕任务契约展开:给出商品字段,说明筛选条件可以为空,说明排序字段只允许白名单,说明分页从 1 开始,说明总数是筛选后的总数,说明当页码越界时返回空列表但总数不变。这里每一句规则都不是装饰,它们都会对应测试或 rubric。
公开示例不需要堆很多。一个正常示例展示多条件筛选和排序,一个边界示例展示空结果或越界页码,一个解释说明总数为什么不是当前页数量。对读者来说,这比展示大段参考代码更有价值,因为它说明了题目真正要评价的判断点。
隐藏测试则围绕常见错误设计。比如把分类条件设为空,验证模型是否把空列表理解成不过滤还是过滤为空;构造同价格同评分的商品,验证稳定排序;构造最后一页之后的页码,验证分页契约;构造十万条商品,验证复杂度。每个隐藏用例都应能回答一个问题:它在防哪一种错误?
如果这道题只要求模型实现一个函数,它仍然是 Medium。如果把它放进已有代码库,要求模型理解现有数据结构、修改测试、保持 API 兼容,并解释为什么没有改动公共类型,它就可能升级为 Hard。难度变化的根本原因不是业务场景变了,而是任务边界、上下文依赖和验证责任变了。
测试用例设计:公开示例不是评估集
公开示例用于解释题意,隐藏测试用于验证能力,性能测试用于排除错误算法,对抗测试用于暴露常见误解。把这几类测试混在一起,会让题目失去校准价值。
一套健康的测试集通常包含五类用例。
| 测试类型 | 主要作用 | 设计重点 |
|---|---|---|
| 基础用例 | 验证主路径是否正确 | 覆盖最常见输入,不追求刁钻 |
| 边界用例 | 验证契约是否完整 | 空输入、单元素、重复值、越界和空结果 |
| 组合用例 | 验证多规则顺序 | 筛选、排序、分页、状态更新等规则组合 |
| 压力用例 | 验证复杂度和资源使用 | 最大规模、退化分布、长字符串或大图 |
| 对抗用例 | 验证是否套错模板 | 针对已知错误模式构造输入 |
测试比例不必固定。初始题库可以让基础和边界用例占较高比例,后续根据失败分布调整。如果模型主要错在边界处理,就提高边界用例权重;如果模型经常超时,就增加压力用例;如果模型反复套用错误模板,就加入更明确的对抗用例。
测试还需要和评分解释绑定。只给一个失败日志,很难沉淀 Mentor 信号。更好的做法是把失败映射到契约层:接口不匹配、数据约束违反、行为规则错误、复杂度不达标、异常策略不一致、修改范围越界。这样一来,题目不仅能给出分数,还能告诉团队模型到底不会什么。
Rubric:把主观评价变成可学习信号
自动化测试适合评价确定性行为,但不能覆盖所有编程能力。代码审查、架构设计、调试过程、风险判断、迁移策略和性能分析,都需要 rubric。
高质量 rubric 不是“代码质量好”“结构清晰”这类泛化评价,而是把评价拆成可观察条件。比如可维护性可以拆成命名是否表达领域概念、是否避免重复规则、是否把边界条件集中处理、是否保持公共接口稳定。安全性可以拆成输入校验、权限边界、敏感日志、并发状态和失败回滚。性能可以拆成复杂度、热点路径、内存占用和退化输入表现。
Rubric 还需要区分合格线和优秀线。合格线回答“是否可以接受”,优秀线回答“是否体现了更强工程判断”。如果只给满分标准,评分者会在中间情况上摇摆;如果只给缺陷清单,优秀方案又无法被稳定识别。
在 Coding Mentor 场景里,rubric 的另一个作用是沉淀训练信号。一次人工评价如果只留下“这次回答不好”,没有长期价值;如果记录为“违反排序稳定性契约,触发用例为同价格同评分商品,根因是二次排序覆盖原始顺序”,它就可以进入错误类型库、评估集、反馈协议,甚至成为后续 SFT 数据的候选来源。
题目库治理与常见反模式
题目库治理:让题目随模型迭代继续有效
题目一旦进入长期使用,就不再只是 Markdown 文件,而是评估资产。评估资产需要治理,否则很快失效。
最基本的治理单位是题目元数据。每道题至少应该记录题目 ID、能力层级、难度标签、领域标签、语言或框架、评估预算、公开测试数量、隐藏测试数量、预期通过率区间、污染风险、版本号和最近校准时间。这些信息不一定全部写在题面里,但必须能被题库系统查询。
难度校准应该周期性进行。团队可以选择几类代表模型:主力闭源模型、成本友好模型、本地开源模型、带工具调用的 agent、无工具的基础模型。每次复跑后记录通过率和失败类型。如果某道 Medium 题在主力模型上长期稳定高于目标通过率,它可能应该降级,或增加更能暴露能力边界的约束。如果某道题长期几乎无人通过,它可能不是 Hard,而是题面不清、测试过窄或验收不合理。
污染风险也必须治理。公开发布的题面、测试、参考实现和题解,都会进入未来模型的训练语料或检索结果。用于公开文章的题目可以服务教学,但不应直接作为私有评估集。真正用于模型选择、内部验收和训练闭环的题目,需要控制暴露范围,并记录哪些部分已经公开。
版本记录同样重要。题面改一个边界条件,测试新增一个隐藏用例,评分脚本修改一个异常判定,都会影响历史分数。如果没有版本号,团队很容易把不同版本的结果放在一起比较,最后得出错误结论。
常见反模式
第一种反模式是把题目写成需求故事,却没有验收契约。场景写得很像真实业务,但输入输出、异常策略和测试标准都不明确。这样的题能激发模型生成大量解释,却很难评分。
第二种反模式是把题目写成代码模板填空。模板能降低实现波动,但过度模板化会把评估变成格式遵循,模型只要补齐局部逻辑就能通过。它适合训练入门能力,不适合评估真实工程判断。
第三种反模式是只看公开示例。公开示例越多,模型越容易从示例反推规则,却不一定理解完整契约。公开示例应该帮助读者理解题意,不能替代隐藏测试和边界覆盖。
第四种反模式是难度标签不校准。题库里标着 Hard 的题,也许只是题面很长;标着 Easy 的题,也许包含隐式状态和异常路径。难度标签如果不绑定评估预算和实际通过率,就会误导模型选择和能力判断。
第五种反模式是把人工评价留在评论区。人工反馈如果没有结构化,就无法复用。好的反馈应能进入错误分类、rubric 修订、测试补充和训练候选样本,而不是停留在“这个答案感觉不行”。
结语:出题能力就是评估能力
给 AI 设计高质量编程题,本质上是在为能力评估搭建可复现环境。题目不是越长越好,也不是越难越好,而是越能稳定暴露目标能力边界越好。
从 Coding Mentor 的角度看,一道好题至少要完成四件事:明确要观察的能力层级,写清任务契约,设计能暴露错误模式的测试,保留可进入治理闭环的失败证据。只要这四件事成立,题目就不再是一次性交互,而是可以沉淀、复跑、比较和改进的组织资产。
下一篇会进入更直接的评估实践:当题目、测试和 rubric 已经准备好,团队如何系统性地评估 AI 的编程能力,并把评估结果转化为可执行的 Mentor 反馈。
参考与致谢
- Bloom’s Taxonomy — Benjamin Bloom et al.
- APPS Benchmark Design — Hendrycks et al., Stanford
- LiveCodeBench Methodology — Jain et al., UC Berkeley
Series context
你正在阅读:AI Coding Mentor 系列
当前为第 3 / 9 篇。阅读进度只写入此浏览器的 localStorage,用于回到系列页时定位继续阅读入口。
Series Path
当前系列章节
点击章节会在此浏览器记录本地阅读进度;刷新后可继续阅读。
- 为什么你需要给AI当Coding Mentor? 当AI编程助手成为标配,真正的竞争力不再是会不会使用AI,而是能不能判断、校准和约束AI的工程输出。本文从信任缺口、反馈协议、评估标准和能力闭环出发,建立“人类作为Coding Mentor”的核心框架。
- AI编程能力评估全景:从HumanEval到SWE-bench,基准测试的演进与选择 公开基准不是模型排行榜的装饰,而是理解AI编程能力边界的测量工具。本文从HumanEval、APPS、CodeContests、SWE-bench、LiveCodeBench和Aider等基准出发,说明如何读榜、如何选择基准,以及如何把公开评估转化为团队自己的Coding Mentor评估体系。
- 如何设计高质量的编程题目:从题面到评估契约 高质量编程题不是更长的 prompt,而是能稳定暴露能力边界的评估契约。本文从 Bloom 层级、难度校准、任务契约、测试设计和题库治理出发,说明如何为 AI Coding Mentor 构建可复现的题目体系。
- AI能力评估四步法:从一次测试到持续评估系统 给AI当Coding Mentor不是做一次模型测评,而是建立一套能持续暴露能力边界、记录失败证据、驱动专项改进和支撑协作决策的评估运营系统。
- 与AI协作的最佳实践:任务协议、对话控制与反馈闭环 给AI当Coding Mentor的核心技能不是写更长的提示词,而是设计任务协议、控制对话节奏、识别错误模式,并把协作过程沉淀为可验证、可复用的反馈信号。
- 实战案例:反馈协议、评估闭环、代码审查与编程教育数据 案例研究不应该停留在“如何更会用AI工具”。本文用模型选型评估、反馈协议设计、代码审查信号沉淀和编程教育数据闭环四个工程场景,说明人类如何把AI协作过程转化为可评估、可训练、可复用的导师信号。
- 从交付到训练:如何把AI编程协作变成Coding Mentor数据闭环 AI编程助手真正的组织价值,不只是提高交付速度,而是在每一次需求拆解、代码生成、评审修正、测试验证和上线复盘中沉淀可训练、可评估、可复用的导师信号。本文重构AI训练、AI辅助产品工程化交付、高质量SFT数据沉淀与模型评估的闭环框架。
- 从工程实战到训练数据:AI工程化自动产出SFT数据的系统化方法 承接第7篇的数据闭环,本文聚焦如何将已筛选的工程资产加工为高质量SFT样本,并接入可治理、可评估、可迭代的训练流水线。
- 未来展望:AI编程评估的演进趋势与长期思考 作为系列收官篇,本文以工程决策视角重构 AI Coding Mentor 的未来路线:评估对象如何演进、组织能力如何分层、治理边界如何前置。
Reading path
继续沿这条专题路径阅读
按推荐顺序继续阅读 AI 编程评估 相关内容,而不是只看同专题的随机文章。
Next step
继续深入这个专题
如果这篇内容对你有帮助,下一步可以回到专题页继续系统阅读,或者订阅后续更新。
正在加载评论...
评论与讨论
使用 GitHub 账号登录参与讨论,评论将同步至 GitHub Discussions