# CS 知识应试强化 — 题目生成 Skill 从 `examination` 仓库生成符合 JSON Schema 的题目文件,自动校验、合并、更新元数据,推送到远程。 ## 前置条件 - Python 3.8+(用于校验和合并脚本) - SSH 访问 `git@47.121.181.112:222`(用于 clone/push) - `topics/index.json` 包含子主题索引 ## 仓库结构 ``` examination/ ├── schema/ │ ├── question.schema.json # 题目 JSON Schema (Draft-07) │ ├── prompt-template.md # 题目生成提示词模板 │ └── templates/ # 各题型示例 JSON ├── topics/ │ ├── index.json # 主题索引 │ └── {group}/{subtopic}/ │ ├── meta.json # 子主题元信息 │ ├── fill_blank.json # 填空题 │ └── single_choice.json # 单选题 └── exam/ # 本 skill 目录 ├── SKILL.md ├── schema/ │ └── question.schema.json └── scripts/ ├── validate.py ├── validate.mjs ├── merge_questions.py ├── update_meta.py ├── read_context.json └── validate_and_merge.json ``` ## 执行流程 > **重要:默认使用子代理(SubAgent)分批次处理。** 生成题目是 token 密集型任务,为避免主会话上下文爆炸,应将每批题目的生成工作委派给子代理执行。主会话负责规划、确认和汇总。 ### 阶段 0:与用户确认方案 **在执行任何操作之前,必须先与用户确认以下信息。** 不要假设默认值。 1. **子主题(subtopic)**:读取仓库中的 `topics/index.json`,列出可用的子主题供用户选择。如果用户已经指定了子主题,验证其是否存在。 2. **题型与数量**:询问用户需要生成哪些题型、每种多少道。可以一次性给出建议(如「建议先生成 10 道单选题 + 5 道判断题」),但最终必须等用户确认。 3. **展示确认摘要**:在开始生成前,向用户展示如下摘要并等待确认: ``` 📋 生成方案确认 ━━━━━━━━━━━━━━ 子主题:gc-jvm(JVM 垃圾回收) 分组: qunar-ai-fullstack 题型: 单选 × 10、判断 × 5 ━━━━━━━━━━━━━━ 确认后开始生成 ✅ ``` 用户确认后才进入下一阶段。 ### 阶段 1:克隆仓库 ```bash REPO_DIR=$(mktemp -d) git clone --depth 1 ssh://git@47.121.181.112:222/wonder/examination.git "$REPO_DIR" ``` ### 阶段 2:读取上下文(子代理) 派发一个子代理,执行以下任务: - 读取 `topics/index.json` 确认子主题存在 - 读取该子主题的 `meta.json`(获取 tags、已有题目信息) - 读取同类型已有的题目文件(获取已有 ID,避免重复) - 将汇总信息返回给主会话 使用本 skill 自带的批量脚本 `scripts/read_context.json` 可以一次完成上述读取: ``` run_tool_batch( file_path="/scripts/read_context.json", args={ "topics_dir": "/topics", "group": "<用户确认的分组>", "subtopic": "<用户确认的子主题>", "question_type": "<用户确认的题型>" } ) ``` ### 阶段 3:生成题目(子代理) > **这是 token 消耗最大的阶段,务必使用子代理处理。** 根据阶段 2 返回的上下文,**为每种题型分别派发子代理**来生成题目。每个子代理的任务是: 1. 根据子主题内容和已有题目,生成指定数量的新题目 2. 严格遵循 Schema 格式(见下方「题目格式规范」) 3. 将生成的 JSON 写入临时文件(如 `/tmp/exam_gen_{type}_{batch}.json`) **子代理提示词模板:** ``` 你是题目生成专家。请为子主题 "{subtopic_name}" 生成 {count} 道 {type_name} 题。 【上下文】 {从阶段 2 获取的 meta.json 和已有题目摘要} 【要求】 - 严格遵循 JSON Schema(见下方规范) - ID 从 {next_id} 开始递增(如 fb-001, fb-002...) - 难度分布在 1-5 之间,合理分布 - tags 参考子主题已有的 tags - explanation 必须详细,解释为什么对/错 - source 填 null,related 填空数组 【输出】 将完整 JSON 写入文件 /tmp/exam_gen_{type}_{batch}.json,格式: { "topic": "{subtopic_slug}", "type": "{question_type}", "schema_version": "1.0.0", "generated": "{ISO 8601 时间戳}", "questions": [ ... ] } ``` **如果题目数量较多(如 > 15 道),建议拆分成多个批次**,每批 5-10 道,分别派发子代理并行处理。 ### 阶段 4:校验、合并、更新元数据(子代理) 所有批次的题目生成完成后,派发子代理执行校验与合并: ``` run_tool_batch( file_path="/scripts/validate_and_merge.json", args={ "skill_dir": "", "topics_dir": "/topics", "group": "", "subtopic": "", "question_type": "", "generated_file": "/tmp/exam_gen_{type}_{batch}.json" } ) ``` 如果是多批次生成,需要对每个批次依次执行合并,或者先合并各批次为一个临时文件,再统一合并到已有文件。 ### 阶段 5:提交推送 ```bash cd "$REPO_DIR" git add -A git commit -m "feat: add {count} {type} questions for {subtopic}" git push origin main ``` ### 阶段 6:汇报结果 向用户展示生成结果摘要: ``` ✅ 题目生成完成 ━━━━━━━━━━━━━━━━━━━━━━ 子主题:gc-jvm 新增: 单选 × 10、判断 × 5 累计: 35 题(单选 20、判断 10、填空 5) 提交: feat: add 15 questions for gc-jvm ━━━━━━━━━━━━━━━━━━━━━━ ``` --- ## 批量脚本参数 ### read_context.json | 参数 | 说明 | 示例 | |------|------|------| | `topics_dir` | 仓库内 `topics/` 目录的绝对路径 | `/tmp/xxxxx/topics` | | `group` | 主题分组名 | `qunar-ai-fullstack` | | `subtopic` | 子主题 slug | `gc-jvm` | | `question_type` | 题型 | `single_choice` | ### validate_and_merge.json | 参数 | 说明 | 示例 | |------|------|------| | `skill_dir` | 本 skill 目录的绝对路径 | `/home/.../skills/exam` | | `topics_dir` | 同上 | 同上 | | `group` | 同上 | 同上 | | `subtopic` | 同上 | 同上 | | `question_type` | 同上 | 同上 | | `generated_file` | 生成的题目 JSON 文件绝对路径 | `/tmp/exam_gen_sc_1.json` | ## 批量执行失败处理 如果批量脚本执行失败: 1. 首先检查所有参数是否正确传入,尤其是 `args` 不能为空 2. 根据错误信息修正参数后重试 3. 如果脚本方式持续失败,回退到手动逐步执行(见下方「手动执行参考」) 4. 完成任务后告知用户:「批量执行遇到了问题,已手动完成。是否需要调整 skill 的批量脚本以便下次正常使用?」 --- ## 手动执行参考 ### 读取上下文 ```bash cat "$REPO_DIR/topics/index.json" cat "$REPO_DIR/topics/{group}/{subtopic}/meta.json" cat "$REPO_DIR/topics/{group}/{subtopic}/{type}.json" # 如果存在 ``` ### 校验 ```bash python3 /scripts/validate.py /tmp/exam_generated.json ``` ### 合并 ```bash python3 /scripts/merge_questions.py \ "$REPO_DIR/topics/{group}/{subtopic}/{type}.json" \ /tmp/exam_generated.json \ /tmp/exam_merged.json cp /tmp/exam_merged.json "$REPO_DIR/topics/{group}/{subtopic}/{type}.json" ``` ### 更新元数据 ```bash python3 /scripts/update_meta.py \ "$REPO_DIR/topics" {group} {subtopic} {type} ``` --- ## 题目格式规范 ID 格式:`{type_short}-{seq}`,序号从已有最大值 +1 开始,三位数补零。 | 题型 | type | type_short | 关键字段 | |------|------|------------|----------| | 填空 | `fill_blank` | `fb` | `answer: string[]`, `answer_rule: "any"/"all"/"ordered"` | | 单选 | `single_choice` | `sc` | `options: {A-D}`, `answer: string` | | 多选 | `multiple_choice` | `mc` | `options: {A-D}`, `answer: string[]` | | 判断 | `true_false` | `tf` | `answer: boolean` | | 简答 | `short_answer` | `sa` | `answer: string`, `keywords: string[]`, `scoring_rubric: string` | | 代码阅读 | `code_reading` | `cr` | `code`, `language`, `sub_questions[]` | | 场景分析 | `scenario` | `sn` | `context`, `sub_questions[]` | ### 通用字段 每道题必须包含: - `id` — 唯一标识,格式 `type_short-NNN` - `type` — 题型枚举值 - `difficulty` — 1 到 5 的整数 - `tags` — 标签数组,参考子主题 meta.json - `question` — 题目文本 - `explanation` — 详细解析 - `source` — 填 `null` - `related` — 填空数组 `[]` ### sub_questions 规范 `code_reading` 和 `scenario` 题型使用 `sub_questions` 数组,每个子问题需要: - `index` — 从 1 开始的序号 - `type` — 子问题的题型(通常是 `single_choice` 或 `short_answer`) - `question` — 子问题文本 - `answer` — 答案 - `explanation` — 解析 - 选择题类子问题还需 `options` 字段 --- ## 备注 - 校验脚本优先使用 `jsonschema` 库(Python),不可用时回退到基础校验 - Node.js 校验脚本(`validate.mjs`)为纯内置模块,无外部依赖,可作为备选 - 合并脚本自动去重(基于 question ID),不会覆盖已有题目 - 元数据更新脚本自动计算 `question_files` 和 `stats.by_type` 统计信息 - 所有脚本退出码:0=成功,1=有错误,2=用法错误 - Schema 文件已内置于 `/schema/question.schema.json`,与仓库版本一致