┌─────────────────────────────────────────────────────────────────────────────┐
│ ExamTypeStrategy::buildParams() - 根据 assembleType 构建组卷参数 │
├─────────────────────────────────────────────────────────────────────────────┤
│ 0,9 摸底 → buildChapterDiagnosticParams() │
│ 1,8 智能组卷 → buildChapterIntelligentParams() │
│ 2 知识点组卷 → buildKnowledgePointAssembleParams() ← 含 QuestionExpansionService │
│ 3 教材组卷 → buildTextbookAssembleParams() │
│ 4 通用 / 5 错题本 → buildGeneralParams / buildMistakeParams │
└─────────────────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────────────────┐
│ LearningAnalyticsService::generateIntelligentExam() │
│ 1. 获取 kp_codes、exclude_question_ids │
│ 2. 优先获取错题(如有) │
│ 3. getQuestionsFromBank() - 从题库按知识点/章节/难度选题,应用 exclude_question_ids │
│ 4. selectQuestionsByMastery() - 按掌握度/题型/难度二次筛选 │
│ 5. applyTypeAwareDifficultyDistribution() - 题型感知难度分布 │
└─────────────────────────────────────────────────────────────────────────────┘
| 层级 | 含义 | 典型触发场景 |
|---|---|---|
| 整体不足 | 指定 kp_codes 下题目总数 < total_questions | 知识点组卷、教材组卷、智能组卷 |
| 某难度范围不足 | 基础/中等/拔高某一档题目不够 | QuestionLocalService 难度分布 |
| 某题型不足 | 选择/填空/解答某一题型不够 | IntelligentExamGeneration、applyTypeAwareDifficultyDistribution |
| 去重后不足 | selectQuestionsByMastery 去重后数量变少 | 重复题目被去除 |
| 措施 | 所在位置 | 说明 |
|---|---|---|
| QuestionExpansionService 扩展 | buildKnowledgePointAssembleParams(assembleType=2) |
仅在知识点组卷时,基础题池不足会扩展:Step1 直接知识点 → Step2 同知识点 → Step3 子知识点(1层) → Step4 薄弱点 → Step5 子知识点(2层) |
| 教材组卷 | buildTextbookAssembleParams |
不做扩展,严格按章节关联知识点 |
| 摸底/智能组卷 | buildChapterDiagnosticParams / buildChapterIntelligentParams |
最终调用 buildKnowledgePointAssembleParams,依赖扩展逻辑 |
| 措施 | 条件 | 说明 |
|---|---|---|
智能补充 getSupplementaryQuestionsForGrade |
totalNeeded > 0 && count < totalNeeded && grade !== null |
从同年级同教材的其他知识点补充题目,避免超纲 |
| 返回所有可用题目 | 无条件 | 不再做 limit 截断,把所有符合条件的题目交给上层 |
⚠️ 重要限制:grade === null 时不会触发智能补充,只返回当前知识点能查到的题目。
| 措施 | 说明 |
|---|---|
| 数量不足时全用 | count(questions) < totalQuestions 时打 warning,但仍使用所有可用题目 |
| 去重后不足时补充 | 从 selectedQuestions 中选未选过的题目补齐到目标数量 |
| 措施 | 说明 |
|---|---|
| 难度范围不足时记录 | 某难度档题目不够时打 warning,不截断,继续选 |
| 从剩余题目补充 | 按 getSupplementOrder 的次级桶顺序补充 |
| 次级桶仍不足 | 从未使用题目中随机补齐 |
| 措施 | 说明 |
|---|---|
| 题型内补充 | 某题型难度分布不满足目标时,从该题型剩余题目补充 |
| 跨题型补充 | 总数不足时,按 fill → choice → answer 优先级跨题型补足 |
| 措施 | 说明 |
|---|---|
| 批量生成题目 | 题库不足时调用 batchGenerateQuestions() 生成题目 |
| 题型不足时跨题型补充 | 某题型可用数量不足,从 choice/fill/answer 其他题型补充 |
实现:
buildTextbookAssembleParams 在 grade 缺失时从 textbooks 表根据 textbook_id 推断 grade。grade 缺失时从教材推断。grade。实现:教材组卷在题目不足时触发 getSupplementaryQuestionsForGrade 智能补充,且仅从同教材前章节(textbookCatalogNodeIds + textbook_id)补充,未学章节不会补充。
现状:selectQuestionsByMastery 按知识点分组、按掌握度排序,但没有「某知识点题目不足时」的显式策略。
影响:当希望每个知识点都有一定题量时,若某知识点题目很少,可能被其他知识点挤占,导致该知识点覆盖不足。
建议:
selectQuestionsByMastery 中增加按知识点最小题数的保障逻辑(例如每知识点至少 1 题,再按掌握度/题型等补足总题量)。实现:getSupplementaryQuestionsForGrade 已新增 exclude_question_ids 参数,智能补充时排除学生已做题目。
实现:当传入 textbookCatalogNodeIds 时,通过 getEarlierChapterNodeIds 限制补充范围为同教材中「选中章节及之前」的节点(sort_order <= max(选中章节)),避免补充未学章节的题目。
现状:组卷一律使用 exclude_question_ids 排除已做题目,没有「允许重复」的开关。
建议:
allow_repeat 之类参数;当 allow_repeat=true 时,不传或清空 exclude_question_ids。知识点组卷(assembleType=2):
ExamTypeStrategy
→ QuestionExpansionService 扩展(直接 KP → 子 KP → 薄弱点)
→ getStudentAnsweredQuestionIds → exclude_question_ids
LearningAnalyticsService
→ getQuestionsFromBank(有 grade 时触发智能补充)
→ selectQuestionsByMastery(不足时用全部可用题目 + 去重后补充)
→ applyTypeAwareDifficultyDistribution(题型/难度不足时跨题型/跨难度补充)
教材组卷(assembleType=3):
ExamTypeStrategy
→ 按章节获取 kp_codes,无扩展
→ getStudentAnsweredQuestionIds → exclude_question_ids
LearningAnalyticsService
→ getQuestionsFromBank(有 grade/textbook_id 时触发智能补充)
→ 若 grade 缺失,智能补充不生效
摸底 / 智能组卷(0/9, 1/8):
最终走 buildKnowledgePointAssembleParams
→ 有 assembleType=2 时走 QuestionExpansionService
→ 其余同上
当前组卷流程对「题目不足」已有较完整的应对链路:
getQuestionsFromBank 在 grade 有值时,会从同年级同教材其他知识点智能补充。selectQuestionsByMastery 在数量不足时使用全部可用题目,并在去重后补齐。主要改进方向:
grade / textbook_id,以启用智能补充。exclude_question_ids,避免补充已做题目。