AI 辅助题库建设:用 LLM 自动生成题目变体与测试用例 AI 辅助题库建设用 LLM 自动生成题目变体与测试用例一、深度引言与场景痛点造题比刷题难十倍刚开始做刷题系统时我以为最难的部分是写判题引擎。后来才发现最难的是持续产出高质量的题目和测试用例。手动造一道好题的过程是这样的先想一个核心算法点设计输入输出格式编写题目描述构造 10~20 组测试用例包括边界条件再用多种语言写一遍参考答案。这一套下来一道中等难度的题至少要 4 个小时。如果题库目标是 500 道一个人全职做也需要近一年。但问题的另一面是LLM 在生成变体这件事上表现出奇地好。给一个经典题目如两数之和它能生成多个变体三数之和、最接近的三数之和、四数之和并且保持核心算法思路的一致性。本文记录我在实践中使用 LLM 辅助题库建设的完整方案。二、底层机制与原理深度剖析LLM 自动生成题目的核心链路如下这条流水线的核心思想是LLM 负责发散自动化校验负责收敛。LLM 在发散阶段可以产生大量候选题目校验层则像一道滤网确保只有真正可用的题目才进入题库。三、生产级代码实现与最佳实践题目变体生成的提示词设计# LLM 题目变体生成器 —— 核心在于提示词的约束设计 import json from openai import OpenAI class ProblemVariantGenerator: 基于种子题目使用 LLM 生成多个变体 SYSTEM_PROMPT 你是一位资深算法竞赛出题人。你的任务是根据给定的种子题目生成 {count} 个变体。 必须严格遵守以下规则 1. 变体必须保留种子的核心算法思想但可以改变场景、数据范围或约束条件 2. 每道变体必须有一个独特的角度不能是简单的参数修改 3. 测试用例必须覆盖正常情况、边界情况空输入、极值、单元素、性能极限情况 4. 输出必须是合法的 JSON格式与输入一致 5. 如果生成过程中发现无法产生有意义的变体在这个位置返回 null def __init__(self, api_key: str, model: str gpt-4): self.client OpenAI(api_keyapi_key) self.model model self.validator ProblemSchemaValidator() def generate_variants( self, seed_problem: dict, count: int 3, temperature: float 0.8 ) - list[dict]: 生成题目变体列表 Args: seed_problem: 种子题目的完整 JSON count: 期望生成的变体数量 temperature: 创造性参数0.8 在多样性和可控性间取得平衡 Returns: 通过校验的变体列表可能少于 count部分被过滤 user_prompt self._build_variant_prompt(seed_problem, count) response self.client.chat.completions.create( modelself.model, messages[ {role: system, content: self.SYSTEM_PROMPT.format(countcount)}, {role: user, content: user_prompt} ], temperaturetemperature, # response_format 确保返回合法 JSON减少格式解析失败的概率 response_format{type: json_object} ) raw_output json.loads(response.choices[0].message.content) variants raw_output.get(variants, []) # 校验 过滤 valid_variants [] for v in variants: if v is None: continue try: self.validator.validate(json.dumps(v)) valid_variants.append(v) except Exception as e: print(f[变体被过滤] 原因: {e}) return valid_variants def _build_variant_prompt(self, seed: dict, count: int) - str: return f种子题目: json {json.dumps(seed, ensure_asciiFalse, indent2)}请为这道题生成 {count} 个变体。返回格式如下:{{ variants: [ {{...}}, // 变体 1 的完整题目 JSON {{...}}, // 变体 2 的完整题目 JSON null // 如果无法生成更多变体用 null 占位 ] }}变体设计要点:每个变体的 id 使用新的编号P{seed[id][1:]}X1 ~ P{seed[id][1:]}X{count}difficulty 可以与种子不同如果变体引入了新的复杂度测试用例至少 10 组其中至少 3 组是边界条件description 必须完整不能引用同种子题目之类的表述### 测试用例的交叉验证 python # 测试用例交叉验证器 —— 确保测试用例本身是正确的 class TestCaseValidator: 验证生成的测试用例是否自洽 def validate_cross(self, problem: dict, reference_solution: str) - dict: 交叉验证用参考答案逐个运行测试用例 核心逻辑 1. 用已知正确的参考答案执行每个测试用例 2. 如果参考答案的输出与 expectedOutput 不一致 说明测试用例本身有误输入或期望输出写错了 3. 这可以过滤掉 LLM 幻觉产生的不一致数据 test_cases problem.get(testCases, []) results {passed: [], failed: [], error: []} for i, tc in enumerate(test_cases): try: actual run_code_with_input( reference_solution, tc[input], timeout_ms2000 ) expected tc[expectedOutput].strip() # 考虑到浮点数精度问题使用模糊比较 if self._fuzzy_match(actual, expected): results[passed].append(i) else: results[failed].append({ index: i, expected: expected, actual: actual }) except TimeoutError: results[error].append({ index: i, reason: 参考答案执行超时测试用例可能过大 }) except Exception as e: results[error].append({ index: i, reason: str(e) }) return results def _fuzzy_match(self, actual: str, expected: str, eps: float 1e-6) - bool: 模糊匹配处理浮点数精度问题 actual actual.strip() expected expected.strip() if actual expected: return True # 尝试按数值比较 try: actual_nums [float(x) for x in actual.split()] expected_nums [float(x) for x in expected.split()] if len(actual_nums) ! len(expected_nums): return False for a, e in zip(actual_nums, expected_nums): if abs(a - e) eps: return False return True except ValueError: return False四、边界分析与架构权衡LLM 生成的质量控制实践中发现LLM 生成的题目有三个常见问题测试用例逻辑错误LLM 在生成测试用例时有时会写一个输入然后拍脑袋写一个输出——这个输出不一定是正确的。必须用参考答案交叉验证否则这些错误用例会被用户当作标准答案。题目描述的前后矛盾比如In the first line...后面又说Each line contains...。这个问题在长文本生成中很常见目前没有完美的自动检测方案必须人工审核。难度标注不准LLM 倾向于把大多数题标为 MEDIUM。需要额外的难度评估模型这个在下一篇会详细讲。成本分析以 GPT-4 为例每生成 10 个变体含完整测试用例Token 消耗约为输入~3000 tokens种子题目 提示词输出~8000 tokens10 道变体单次生成成本约 $0.30。当题库达到 500 道时采用此方案比纯人工节省约 90% 的时间成本。人工审核不能省略自动化流水线的目标是减少人工工作量而不是消除人工审核。每道 AI 生成的题目在加入题库前仍然需要至少一个人过一遍。但审核 10 道 AI 生成的题目每道约 2 分钟远比手写 10 道题每道约 4 小时快。五、总结用 LLM 辅助题库建设的核心经验是让 LLM 做它擅长的事发散生成用规则和代码做它不擅长的事精确校验。这个方案的三个关键环节精心设计的提示词控制变体的多样性和质量多层自动校验Schema 校验 交叉验证 难度评估必过人工审核最后的兜底防线题库的质量永远是第一位的——宁可少 100 道题也不要有 10 道错题混进去。AI 只是加速器不是质量保证的替代品。