Files

300 lines
9.8 KiB
Markdown
Raw Permalink Normal View History

---
name: exam
description: |
CS 知识应试强化 — 题目生成 Skill。
从 examination 仓库生成符合 JSON Schema 的题目文件,自动校验、合并、更新元数据,推送到远程。
当用户提到生成题目、考试题、练习题、CS 知识题、选择题、填空题、判断题时,使用此 skill。
---
# 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="<skill_dir>/scripts/read_context.json",
args={
"topics_dir": "<REPO_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="<skill_dir>/scripts/validate_and_merge.json",
args={
"skill_dir": "<skill_dir>",
"topics_dir": "<REPO_DIR>/topics",
"group": "<group>",
"subtopic": "<subtopic>",
"question_type": "<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 <skill_dir>/scripts/validate.py /tmp/exam_generated.json
```
### 合并
```bash
python3 <skill_dir>/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 <skill_dir>/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 文件已内置于 `<skill_dir>/schema/question.schema.json`,与仓库版本一致