@zhouchangui/math-ati 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.html CHANGED
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>学生数学提分 Agent</title>
7
- <script type="module" crossorigin src="/assets/index-CS-PgjYi.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index--Um9OfFu.css">
7
+ <script type="module" crossorigin src="/assets/index-w2k_4Owd.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-CJkqklO7.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhouchangui/math-ati",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Local ATI math learning loop for printable practice, PDF grading, and mastery tracking.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -35,6 +35,7 @@
35
35
  "release:npm": "node scripts/release-npm.js",
36
36
  "preview": "vite preview --host 127.0.0.1",
37
37
  "extract:knowledge": "node scripts/extract-knowledge.js",
38
+ "init:knowledge": "node scripts/init-knowledge.js",
38
39
  "pipeline:check": "node scripts/pipeline-check.js",
39
40
  "generate:coverage": "node scripts/generate-coverage.js",
40
41
  "combine:coverage": "node scripts/combine-coverage.js",
@@ -67,9 +68,11 @@
67
68
  "katex": "^0.16.25",
68
69
  "lucide-react": "^0.562.0",
69
70
  "multer": "^2.0.2",
70
- "vite": "^7.3.1",
71
71
  "react": "^19.2.3",
72
- "react-dom": "^19.2.3"
72
+ "react-dom": "^19.2.3",
73
+ "vite": "^7.3.1"
73
74
  },
74
- "devDependencies": {}
75
+ "optionalDependencies": {
76
+ "@zhouchangui/math-ati-curriculum-rj-7a": "^0.1.3"
77
+ }
75
78
  }
@@ -105,7 +105,9 @@
105
105
  "comment": "string",
106
106
  "referenceAnswer": "string",
107
107
  "solutionMethod": ["string"],
108
- "teachingHint": "string"
108
+ "teachingHint": "string",
109
+ "understandingLevel": "rote|procedural|conceptual",
110
+ "evidenceForUnderstanding": "string"
109
111
  }
110
112
  ]
111
113
  }
@@ -0,0 +1,75 @@
1
+ # Prompt Contract: 章节结构分析 Agent
2
+
3
+ ## 1. Mission
4
+
5
+ 快速浏览章节的所有页面图片,输出章节的整体结构框架,为后续逐页详细提取提供全局视角参考。
6
+
7
+ ## 2. Inputs
8
+
9
+ 调用方会提供:
10
+
11
+ - `context.chapter`:章节元信息(id、title、track)。
12
+ - 当前请求附带多张章节图片(抽样)。
13
+
14
+ ## 3. Operating Principles
15
+
16
+ - 只做结构概览,不做详细知识提取。
17
+ - 关注的是"本章整体在讲什么、分几个部分、各部分逻辑关系",而不是逐句提取。
18
+ - 不确定的内容标注为"待确认"。
19
+ - 不要补充图片中没有出现的知识。
20
+ - 如果有页面看不清,在相应位置标注原因。
21
+
22
+ ## 4. SOP
23
+
24
+ 1. 快速浏览所有图片,建立章节整体印象。
25
+ 2. 识别本章的核心概念(3-5 个最骨干的知识主题)。
26
+ 3. 识别本章的主要公式/法则(如果有)。
27
+ 4. 识别本章常见的易错类型(如果有)。
28
+ 5. 判断每页的大致角色:概念引入、定义说明、公式推导、例题演示、总结复习等。
29
+ 6. 输出 Markdown 结构分析。
30
+
31
+ ## 5. Output Format
32
+
33
+ 只输出 Markdown,不输出 JSON,不输出解释性前后缀。
34
+
35
+ ```markdown
36
+ # 章节结构分析
37
+
38
+ ## 章节主题
39
+ 用一两句话概括本章的核心内容。
40
+
41
+ ## 核心概念
42
+ - 概念1:一句话说明
43
+ - 概念2:一句话说明
44
+ - ...
45
+
46
+ ## 主要公式/法则
47
+ - 法则1
48
+ - ...
49
+
50
+ ## 常见易错类型
51
+ - 类型1
52
+ - ...
53
+
54
+ ## 页面分工
55
+ - page-001: 角色 | 涉及的核心概念
56
+ - page-002: 角色 | 涉及的核心概念
57
+ - ...
58
+
59
+ ## 结构备注
60
+ - 跨页延续关系(如 page-003 是 page-002 的续页)
61
+ - 疑难点或前备知识依赖
62
+ - 其他有助于后续逐页提取的线索
63
+ ```
64
+
65
+ ## 6. Self-check
66
+
67
+ - 核心概念是否控制在 3-5 个?
68
+ - 每页是否标注了大致角色?
69
+ - 是否没有补充图片外的知识?
70
+ - 不确定的地方是否标注为"待确认"?
71
+
72
+ ## 7. Failure Policy
73
+
74
+ - 如果所有页面都无法识别:输出标题和原因,不要编造结构。
75
+ - 如果只有部分页面看不清:在"页面分工"中标注该页为"待确认",其余正常分析。
@@ -43,7 +43,8 @@
43
43
  4. 将常见误判、特殊值、限制条件放入 `易错题专项` section。
44
44
  5. 给每个 point 生成稳定 id。
45
45
  6. 给每个 point 补齐 `summary`、`formulas`、`pitfalls`、`examples`、`questionTemplates`、`sources`。
46
- 7. `review` 中说明合并情况、疑似遗漏和是否通过。
46
+ 7. 为每个知识点总结教学提示 `teachingTips`:写出 1-2 条孩子常见的具体误解(不是标签,是具体描述),以及 1 条可以检查孩子是否真正理解的问法。
47
+ 8. 在 `review` 中说明合并情况、疑似遗漏和是否通过。
47
48
 
48
49
  ## 6. Few-shot Example
49
50
 
@@ -71,6 +72,11 @@
71
72
  "pitfalls": ["漏掉 $0$ 的相反数"],
72
73
  "examples": ["$7$ 与 $-7$"],
73
74
  "questionTemplates": [["写出 $-7$ 和 $0$ 的相反数。", "$7$,$0$", "特殊值遗漏"]],
75
+ "teachingTips": {
76
+ "commonMisconceptions": ["认为 $0$ 没有相反数——实际上 $0$ 的相反数还是 $0$。"],
77
+ "scaffoldingOrder": ["先在数轴上找到对称点", "再抽象为\"改符号\"的规则", "最后处理 $0$ 这个特殊情况"],
78
+ "checkUnderstandingQuestions": ["一个数的相反数的相反数等于什么?为什么?"]
79
+ },
74
80
  "sources": ["page-001.png"]
75
81
  }
76
82
  ]
@@ -98,6 +104,11 @@
98
104
  "pitfalls": ["string"],
99
105
  "examples": ["string"],
100
106
  "questionTemplates": [["stem", "answer", "expectedErrorType"]],
107
+ "teachingTips": {
108
+ "commonMisconceptions": ["string"],
109
+ "scaffoldingOrder": ["string"],
110
+ "checkUnderstandingQuestions": ["string"]
111
+ },
101
112
  "sources": ["image filename"]
102
113
  }
103
114
  ]
@@ -120,6 +131,7 @@
120
131
  - 是否把易错点放入专项 section?
121
132
  - 是否控制在可教学颗粒度?
122
133
  - 每个 point 是否有稳定 id 和 questionTemplates?
134
+ - 每个 point 是否有 teachingTips,至少包含 1 条常见误解和 1 条理解检查问法?
123
135
  - `sources` 是否保留?
124
136
 
125
137
  ## 9. Failure Policy
@@ -32,6 +32,7 @@
32
32
  - `solutionMethod` 只需要给错误、部分正确、无法识别但可讲解的题;正确题可以为空数组。
33
33
  - `errorTypes` 优先从题目的 `expectedErrorTypes` 中选择,也可以补充更具体错因。
34
34
  - 正确题也要尽量给短的 `positiveFeedback`,用于正向反馈。
35
+ - 对每道题判断学生的理解深度 `understandingLevel`:`rote`(机械套公式)、`procedural`(步骤正确但可能不理解原理)、`conceptual`(表现出概念理解);并在 `evidenceForUnderstanding` 中写出判断依据。
35
36
  - 只输出 JSON,不输出 Markdown 或解释。
36
37
 
37
38
  ## Status
@@ -64,7 +65,9 @@
64
65
  "mistakeSummary": "string",
65
66
  "referenceAnswer": "string",
66
67
  "solutionMethod": ["string"],
67
- "teachingHint": "string"
68
+ "teachingHint": "string",
69
+ "understandingLevel": "rote|procedural|conceptual",
70
+ "evidenceForUnderstanding": "string"
68
71
  }
69
72
  ]
70
73
  }
@@ -38,6 +38,8 @@
38
38
  "referenceAnswer": "string",
39
39
  "solutionMethod": ["string"],
40
40
  "teachingHint": "string",
41
+ "understandingLevel": "rote|procedural|conceptual",
42
+ "evidenceForUnderstanding": "string",
41
43
  "reviewReason": "string"
42
44
  }
43
45
  ```
@@ -0,0 +1,154 @@
1
+ # Prompt Contract: 答案补全 Agent
2
+
3
+ ## 1. Mission
4
+
5
+ 为已定稿的练习题目补全标准答案、解题步骤和批改要点,不改变题目本身。
6
+
7
+ ## 2. Inputs
8
+
9
+ 调用方会提供:
10
+
11
+ - `context.chapter`:章节元信息。
12
+ - `context.questions`:已定稿的题目列表,每题包含 `id`、`stem`、`questionKind`、`difficulty`、`knowledgePointIds`、`knowledgePoints`、`expectedErrorTypes`、`score`、`answerSpaceLines`,以及能力评估题的 `abilityIds`、`skillAtoms`、`expectedAbilityErrors`。
13
+
14
+ 答案元数据会写入练习 JSON 的 `questions[]` 中。
15
+
16
+ ## 3. Context Reading Order
17
+
18
+ 1. 先读每道题的 `stem` 和 `questionKind`,确定题目类型和解题需求。
19
+ 2. 再读 `knowledgePoints` 和 `expectedErrorTypes`,用于写讲解时的错因提示。
20
+ 3. 最后读 `difficulty` 和 `score`,用于确定讲解深度和 rubric 分值分配。
21
+
22
+ ## 4. Operating Principles
23
+
24
+ - 不改变题目 ID、题干、题型、难度、knowledgePointIds、knowledgePoints、expectedErrorTypes、abilityIds、skillAtoms、expectedAbilityErrors、score、answerSpaceLines、svg 或 imagePrompt。
25
+ - `answer` 必须是可核对的标准答案:选择题写正确选项和简短结论,填空/问答题写完整答案。
26
+ - `solutionSteps` 分级策略:
27
+ - 简单选择题/填空题:只写 1 条简短说明,说明本题考察什么和关键辨析点。
28
+ - 需要推导、几何观察或多步判断的题:写 2-4 条解题要点。
29
+ - 不要重复标准答案,不要写成批改标准;语言要像给孩子看的讲解。
30
+ - `rubric` 必须可用于批改,至少包含关键结论和关键过程;各项 score 之和应接近题目 score。
31
+ - 公式使用 LaTeX 分隔符(`$...$`),并保留完整反斜杠(`\\triangle`、`\\angle`、`\\perp`、`\\parallel`、`\\text{}`)。
32
+
33
+ ## 5. SOP
34
+
35
+ 1. 逐题阅读 `stem` 和 `questionKind`。
36
+ 2. 解出标准答案。
37
+ 3. 根据题目复杂度决定 solutionSteps 条数:简单题 1 条,复杂题 2-4 条。
38
+ 4. 根据题目的 score 分配 rubric 中各项分值。
39
+ 5. 输出 JSON。
40
+
41
+ ## 6. Few-shot Example
42
+
43
+ ### 选择题
44
+
45
+ ```json
46
+ {
47
+ "id": "q1",
48
+ "stem": "下列各组数中,互为相反数的是( )\nA. $-7$ 与 $7$\nB. $-7$ 与 $-7$\nC. $7$ 与 $0$\nD. $0$ 与 $7$",
49
+ "questionKind": "choice",
50
+ "difficulty": "basic",
51
+ "knowledgePointIds": ["chapter-01-kp-05"],
52
+ "knowledgePoints": ["相反数的概念"],
53
+ "expectedErrorTypes": ["概念混淆", "特殊值遗漏"],
54
+ "score": 6
55
+ }
56
+ ```
57
+
58
+ 正确输出:
59
+
60
+ ```json
61
+ {
62
+ "questions": [
63
+ {
64
+ "id": "q1",
65
+ "answer": "A,$-7$ 与 $7$ 互为相反数。",
66
+ "solutionSteps": [
67
+ "判断相反数只需看符号:符号不同、数字相同的两个数互为相反数。$0$ 的相反数是 $0$。"
68
+ ],
69
+ "rubric": [
70
+ { "point": "选择正确选项 A", "score": 4 },
71
+ { "point": "能说出判断依据(符号不同、数字相同)", "score": 2 }
72
+ ]
73
+ }
74
+ ]
75
+ }
76
+ ```
77
+
78
+ ### 计算推导题
79
+
80
+ ```json
81
+ {
82
+ "id": "q3",
83
+ "stem": "计算:$-3 + 5 - (-2)$,并写出每一步的运算过程。",
84
+ "questionKind": "short_answer",
85
+ "difficulty": "medium",
86
+ "knowledgePointIds": ["chapter-01-kp-01", "chapter-01-kp-03"],
87
+ "knowledgePoints": ["正数和负数的定义", "有理数的加法"],
88
+ "expectedErrorTypes": ["符号错误", "去括号错误"],
89
+ "score": 8
90
+ }
91
+ ```
92
+
93
+ 正确输出:
94
+
95
+ ```json
96
+ {
97
+ "questions": [
98
+ {
99
+ "id": "q3",
100
+ "answer": "$-3 + 5 - (-2) = 2 + 2 = 4$",
101
+ "solutionSteps": [
102
+ "第一步:从左到右先算 $-3+5=2$(正数和负数相加,取绝对值较大的数的符号)。",
103
+ "第二步:减去 $-2$ 相当于加上它的相反数 $2$,所以 $2 - (-2) = 2 + 2 = 4$。",
104
+ "关键点:去括号时\"减一个负数\"变成\"加一个正数\"。"
105
+ ],
106
+ "rubric": [
107
+ { "point": "第一步 $-3+5$ 计算正确,得 $2$", "score": 3 },
108
+ { "point": "处理 $-(-2)$ 转化为 $+2$", "score": 3 },
109
+ { "point": "最终结果 $4$ 正确", "score": 2 }
110
+ ]
111
+ }
112
+ ]
113
+ }
114
+ ```
115
+
116
+ ## 7. Output Schema
117
+
118
+ 只输出 JSON,不输出 Markdown,不输出解释性前后缀。
119
+
120
+ ```json
121
+ {
122
+ "questions": [
123
+ {
124
+ "id": "q1",
125
+ "answer": "string",
126
+ "solutionSteps": ["string"],
127
+ "rubric": [
128
+ {
129
+ "point": "string",
130
+ "score": 2
131
+ }
132
+ ]
133
+ }
134
+ ]
135
+ }
136
+ ```
137
+
138
+ ## 8. Self-check Rubric
139
+
140
+ 输出前确认:
141
+
142
+ - 是否只输出了输入中已有题目的 id、answer、solutionSteps、rubric?
143
+ - 是否没有改变题目 id、题干、题型、难度或任何其他字段?
144
+ - 选择题的 answer 是否包含正确选项和简短结论?
145
+ - solutionSteps 条数是否符合分级策略(简单题 1 条,复杂题 2-4 条)?
146
+ - solutionSteps 语言是否像给孩子看的讲解,而不是批改标准?
147
+ - rubric 各项 score 之和是否接近题目 score?
148
+ - LaTeX 反斜杠是否完整保留?
149
+
150
+ ## 9. Failure Policy
151
+
152
+ - 如果题目 stem 信息不足以唯一确定答案:在 answer 中给出最合理的参考答案,并在 solutionSteps 第一条说明假设前提。
153
+ - 如果题目 questionKind 未识别:默认按 short_answer 处理。
154
+ - 不要跳过任何输入中的题目;每道题都必须输出。
@@ -0,0 +1,112 @@
1
+ # Prompt Contract: 覆盖缺口修复 Agent
2
+
3
+ ## 1. Mission
4
+
5
+ 在不新增题目、不删除题目的前提下,修复定稿题目的知识点覆盖缺口,让 missingPointIds 中的知识点被已有题目尽可能覆盖。
6
+
7
+ ## 2. Inputs
8
+
9
+ 调用方会提供:
10
+
11
+ - `context.student`:学生画像。
12
+ - `context.chapter`:章节元信息。
13
+ - `context.options`:生成目标。
14
+ - `context.knowledgeDoc`:章节知识点字典。
15
+ - `context.targetKnowledgePoints`:本次出题允许的知识点范围。
16
+ - `context.practiceDraft`:当前定稿题目(已通过初评和修订)。
17
+ - `context.localCoverageCheck`:本地覆盖检查结果(`coveredPointIds`、`missingPointIds`)。
18
+ - `context.missingTargetKnowledgePoints`:缺失覆盖的知识点对象列表。
19
+
20
+ ## 3. Context Reading Order
21
+
22
+ 1. 先读 `context.missingTargetKnowledgePoints`,理解哪些知识点尚未被覆盖。
23
+ 2. 再读 `context.practiceDraft.questions`,逐题分析每题覆盖的知识点和题干内容。
24
+ 3. 最后读 `context.localCoverageCheck`,确认缺口确实存在。
25
+
26
+ ## 4. Operating Principles
27
+
28
+ - 不新增题目,不删除题目,不改变题目 ID。
29
+ - 优先选择概念最接近的已有题目,小幅修改题干使其同时覆盖缺失知识点。
30
+ - 如果找不到概念接近的题目,替换一道诊断价值最低的题(由你判断哪道题对孩子掌握情况的区分度最低)。
31
+ - 不能硬塞不相关的知识点;如果确实无法自然覆盖,保留缺口并在 `revisionSummary` 中说明。
32
+ - 修改后的题干必须学生仍可作答、答案唯一。
33
+ - 遵守通用出题规则。
34
+
35
+ ## 5. SOP
36
+
37
+ 1. 遍历 `missingTargetKnowledgePoints` 中的每个缺失知识点。
38
+ 2. 对每个缺失知识点,在已有题目中找概念最接近的题(对比题目的 `knowledgePointIds`、`questionKind` 和 `stem` 内容)。
39
+ 3. 对最接近的题,小幅修改题干使其也能考察缺失知识点(例如增加一个子问、修改条件使其涉及缺失概念)。
40
+ 4. 更新题目的 `knowledgePointIds`、`knowledgePoints`、`expectedErrorTypes`。
41
+ 5. 如果修改导致题干语义变化,必须同步调整题干确保可作答。
42
+ 6. 如果需要视觉信息,补充或调整 SVG。
43
+ 7. 在 `revisionSummary` 中说明修改了哪些题、覆盖了哪些知识点。
44
+
45
+ ## 6. Few-shot Example
46
+
47
+ 输入:
48
+ - `missingTargetKnowledgePoints`: [{ `id`: "chapter-01-kp-05", `title`: "相反数的概念" }]
49
+ - `practiceDraft.questions`: 已有题目 q1 覆盖 "正数和负数",q2 覆盖 "数轴上的点"。
50
+
51
+ 修正策略:q2 "在数轴上画出 -3 和 3 的位置" 与相反数概念直接相关(数轴上对称点)。修改题干为 "在数轴上画出 3 和它的相反数的位置,并指出它们到原点的距离有什么关系",同时将 `knowledgePointIds` 增加 "chapter-01-kp-05"。
52
+
53
+ 输出片段:
54
+
55
+ ```json
56
+ {
57
+ "revisionSummary": "q2 题干小幅修改,新增覆盖缺失知识点 chapter-01-kp-05(相反数概念),同时保留原数轴知识点覆盖。",
58
+ "questions": [
59
+ {
60
+ "id": "q2",
61
+ "stem": "在数轴上画出 $3$ 和它的相反数的位置,并指出它们到原点的距离有什么关系。",
62
+ "knowledgePointIds": ["chapter-01-kp-03", "chapter-01-kp-05"],
63
+ "knowledgePoints": ["有理数与数轴上的点", "相反数的概念"],
64
+ "expectedErrorTypes": ["数轴方向混淆", "特殊值遗漏"]
65
+ }
66
+ ]
67
+ }
68
+ ```
69
+
70
+ ## 7. Output Schema
71
+
72
+ 只输出 JSON,不输出 Markdown,不输出解释性前后缀。
73
+
74
+ ```json
75
+ {
76
+ "title": "string",
77
+ "personalizationBasis": ["string"],
78
+ "revisionSummary": "string",
79
+ "questions": [
80
+ {
81
+ "id": "q1",
82
+ "stem": "plain text with LaTeX delimiters; only question",
83
+ "questionKind": "choice|blank|short_answer",
84
+ "difficulty": "basic|medium|challenge",
85
+ "knowledgePointIds": ["chapter-01-kp-01"],
86
+ "knowledgePoints": ["plain Chinese tag label, no LaTeX delimiters or HTML"],
87
+ "expectedErrorTypes": ["plain Chinese tag label, no LaTeX delimiters or HTML"],
88
+ "svg": "optional inline SVG string",
89
+ "imagePrompt": "optional gpt-image-2 prompt",
90
+ "score": 6,
91
+ "answerSpaceLines": 2
92
+ }
93
+ ]
94
+ }
95
+ ```
96
+
97
+ ## 8. Self-check Rubric
98
+
99
+ 输出前确认:
100
+
101
+ - 是否没有新增或删除题目?
102
+ - 是否所有修改的题仍可唯一作答?
103
+ - 是否所有 `knowledgePointIds` 都来自 `targetKnowledgePoints`?
104
+ - 缺失知识点是否尽可能被覆盖了?
105
+ - 是否没有为了覆盖而硬塞不相关的知识点?
106
+ - `knowledgePoints` 和 `expectedErrorTypes` 是否是纯文本标签?
107
+
108
+ ## 9. Failure Policy
109
+
110
+ - 如果某个缺失知识点确实无法被已有题目自然覆盖:保留原题不变,在 `revisionSummary` 中说明"xx 知识点无法被已有题目覆盖,建议下次生成时用显式 knowledgePointIds 指定"。
111
+ - 如果所有缺失点都找不到接近的题:输出原题目不动,`revisionSummary` 说明情况。
112
+ - 不要为了强行覆盖而破坏题目的可作答性。
@@ -63,7 +63,44 @@ Source of Truth:`targetKnowledgePoints` 高于 `knowledgeDoc`,不要引用
63
63
  - 出题草稿任务只生成题目字段和知识点绑定,不输出标准答案、解题步骤和评分要点。
64
64
  - 答案补全任务只为已定稿题目输出 `id`、`answer`、`solutionSteps`、`rubric`;不要改题干、题型、知识点或分值。`solutionSteps` 面向讲解卷阅读:简单题只给 1 条考察说明,需要推导/观察/多步辨析的题才给 2-4 条解题要点。
65
65
 
66
- ## 5. SOP
66
+ ## 5. 多知识点综合题设计策略
67
+
68
+ 一道好题应该尽可能覆盖多个紧密相关的知识点,而不是为每个知识点单独设计一道题。以下四种策略可以用来设计"少题高覆盖"的综合诊断题。
69
+
70
+ ### 策略 A:概念链串联
71
+ 当知识点 A → B → C 有递进推导关系时,设计一道包含多个子问的题,逐步深入:
72
+ - 第 1 问考察 A(基础判断)
73
+ - 第 2 问考察 B(在 A 的基础上)
74
+ - 第 3 问考察 C(综合应用)
75
+
76
+ **示例**:先判断一个数的相反数(A),再求相反数的绝对值(B),最后计算与原数的和(C)。三个知识点分别对应 `chapter-01-kp-05`、`chapter-01-kp-06`、`chapter-01-kp-03`。
77
+
78
+ ### 策略 B:易错点捆绑
79
+ 当多个知识点有相似的易错模式时,设计一道需要同时避免多个陷阱的题:
80
+
81
+ **示例**:计算 $-(-3) + |-5| - (-2)$。这道题同时涉及:
82
+ - 相反数处理(去括号"减负变加正")
83
+ - 绝对值运算(符号判断)
84
+ - 减法转加法(符号规则)
85
+ - 每个步骤都可能触发不同的预期错因。
86
+
87
+ ### 策略 C:对比辨析
88
+ 当两个概念容易混淆时,设计一道需要同时区分的题:
89
+
90
+ **示例**:"判断以下说法是否正确,并说明理由:(1) 一个数的倒数等于它的相反数;(2) 互为相反数的两个数之和为 0。"这道题同时考察相反数概念和倒数概念,要求学生区分二者。
91
+
92
+ ### 策略 D:数形结合
93
+ 将计算/代数知识点和图形/数轴知识点结合起来:
94
+
95
+ **示例**:"在数轴上标出 $-2$ 和 $3$ 的位置,然后计算这两点之间的距离。"这道题同时覆盖数轴表示(A)和有理数减法/绝对值(B)。
96
+
97
+ ### 策略选择原则
98
+ - 优先使用策略 A(概念链串联),因为递进式子问最能暴露学生在哪个环节卡住。
99
+ - 如果知识点之间有易错重叠,使用策略 B。
100
+ - 如果两个知识点经常被学生混淆,使用策略 C。
101
+ - 如果章节包含数轴/图形,使用策略 D 增加视觉理解维度。
102
+
103
+ ## 6. SOP
67
104
 
68
105
  1. 判断模式:如果有 `knowledgePointId`,这是单知识点探测;如果没有,就是章节知识点覆盖卷。
69
106
  2. 章节覆盖卷先读取全部 `targetKnowledgePoints`、`history.mastery`、`recentMistakes`,按概念、公式、计算方法、易错点分组,规划最少题量。
@@ -75,7 +112,7 @@ Source of Truth:`targetKnowledgePoints` 高于 `knowledgeDoc`,不要引用
75
112
  8. 检查 `knowledgePoints` 和 `expectedErrorTypes` 是否都是纯文本标签,没有 `$`、LaTeX 分隔符或 HTML。
76
113
  9. 输出 JSON。
77
114
 
78
- ## 6. Few-shot Examples
115
+ ## 7. Few-shot Examples
79
116
 
80
117
  单知识点选择题输入:
81
118
 
@@ -105,7 +142,7 @@ Source of Truth:`targetKnowledgePoints` 高于 `knowledgeDoc`,不要引用
105
142
  }
106
143
  ```
107
144
 
108
- ## 7. Output Schema
145
+ ## 8. Output Schema
109
146
 
110
147
  只输出 JSON,不输出 Markdown,不输出解释性前后缀。
111
148
 
@@ -140,7 +177,7 @@ Source of Truth:`targetKnowledgePoints` 高于 `knowledgeDoc`,不要引用
140
177
  }
141
178
  ```
142
179
 
143
- ## 8. Self-check Rubric
180
+ ## 9. Self-check Rubric
144
181
 
145
182
  输出前确认:
146
183
 
@@ -153,10 +190,13 @@ Source of Truth:`targetKnowledgePoints` 高于 `knowledgeDoc`,不要引用
153
190
  - 如果当前任务是答案补全:每题是否输出了可核对的 `answer`、适合题目复杂度的 `solutionSteps`、可批改的 `rubric`?
154
191
  - 是否避开历史重复题?
155
192
  - 题目是否能暴露一个明确错因?
193
+ - 是否使用了多知识点综合题设计策略(概念链、易错点捆绑、对比辨析、数形结合),而不是简单的一题一知识点?
194
+ - 每道题的诊断价值自检:如果孩子做对了这道题,能在多大程度上确信他真正掌握了相关知识点?(1=几乎不能,5=完全确信。目标≥3分。)
195
+ - 选择题的每个干扰项是否对应一个明确的预期错因?
156
196
  - LaTeX 反斜杠是否完整保留,没有出现 `riangle`、`angle`、`perp`、`parallel`、`ext{}` 这类丢反斜杠错误?
157
197
  - 几何/数轴/SVG 题的题干、图中标签、角弧、垂直/平行/长度标注是否互相一致?
158
198
 
159
- ## 9. Failure Policy
199
+ ## 10. Failure Policy
160
200
 
161
201
  - 如果目标知识点缺失:输出空 `questions`,并在 `personalizationBasis` 说明缺失,不要编造知识点 id。
162
202
  - 如果历史题太相似:换数字、换问法、换题型,但不要改变目标知识点。
@@ -0,0 +1,61 @@
1
+ # 通用出题规则库
2
+
3
+ 本文档定义出题、评审、修订、覆盖修复、答案补全各阶段共享的通用规则。各 Agent prompt 只需引用规则编号,无需复制规则文本。
4
+
5
+ ---
6
+
7
+ ## 题干规范
8
+
9
+ **R01**:题干只放题目,不放解题过程。题面不给学生显示分值,不要在题干里写"本题多少分"。
10
+
11
+ **R02**:题目使用纯文本加 LaTeX 分隔符(`$...$`、`$$...$$`、`\\(...\\)` 或 `\\[...\\]`)。可以使用 Markdown 表格,但不能使用 HTML `<table>`。
12
+
13
+ **R03**:题目之间不能重复,也不要和历史题干高度相似。
14
+
15
+ ## LaTeX 规范
16
+
17
+ **R04**:LaTeX 命令必须保留完整反斜杠,例如 `\\triangle`、`\\angle`、`\\perp`、`\\parallel`、`\\text{}`。禁止输出 `riangle`、`angle`、`perp`、`parallel`、`ext{}` 或把 `\\t` 变成制表符。
18
+
19
+ ## 标签规范
20
+
21
+ **R05**:`knowledgePoints`、`expectedErrorTypes` 是讲解版胶囊标签,只能输出纯中文短标签。禁止使用 `$...$`、`\\(...\\)`、`\\[...\\]`、HTML 或长公式。需要提到 0、-0、1/2 时直接写普通文本,例如"特殊值 0 误判""负号整体判断遗漏"。
22
+
23
+ **R06**:`skillAtoms`、`expectedAbilityErrors` 也是讲解版胶囊标签,只能输出纯中文短标签。禁止使用 `$...$`、`\\(...\\)`、`\\[...\\]`、HTML 或长公式。
24
+
25
+ ## 题型规范
26
+
27
+ **R07**:`questionKind` 为 `auto` 时,自主组合 `choice`、`blank`、`short_answer`。`choice` 适合概念辨析,`blank` 适合公式/结论/计算结果,`short_answer` 适合方法、步骤、辨析和综合小题。
28
+
29
+ **R08**:选择题必须恰好 1 个正确选项 + 3 个有教学意义的干扰项。干扰项不能机械重复,每个干扰项应对应一个明确的预期错因。
30
+
31
+ **R09**:填空题必须有明确可判分答案,不能只是抄定义后留空。
32
+
33
+ **R10**:问答题必须有明确任务、条件和作答要求。
34
+
35
+ ## 知识点绑定规范
36
+
37
+ **R11**:`knowledgePointIds` 必须来自 `targetKnowledgePoints`,不能引用范围外知识点 ID。一道题可以覆盖多个紧密相关知识点(概念链、计算链、易错链)。
38
+
39
+ **R12**:每题必须填写 `knowledgePointIds`、`knowledgePoints`、`expectedErrorTypes` 字段。
40
+
41
+ ## 视觉信息规范
42
+
43
+ **R13**:出题时必须先判断本题是否需要视觉信息才能作答。不是所有几何题都要配图;纯概念辨析、定义判断、特征归类等题,如果题干信息完整、唯一可答,可以不配图。
44
+
45
+ **R14**:如果没有图,题干必须仍然信息完整、唯一可答、无需学生凭想象补出位置关系或图形结构;否则必须使用 `svg` 字段提供完整内联 SVG,或把题目改写成纯文字可答题。
46
+
47
+ **R15**:展开图、折叠、图形甲/乙、点线面位置、直线/射线/线段位置、角、垂直、平行、中点、延长线、交点数量、方格拼图等通常需要视觉判断,但这不是固定清单;最终以本题是否依赖视觉信息为准。
48
+
49
+ **R16**:几何、数轴或 SVG 图形题必须保证题干、图中标签、角弧、垂直/平行/长度标注完全一致;如果题干问 `\\angle 2`、切点、垂足、某条边或某个展开图,SVG 中对应位置必须准确。
50
+
51
+ **R17**:SVG 必须简洁可打印,标签不能遮挡线段、角弧、表格或答题区域。优先使用简单清晰的线图。黑白打印也能看清,不依赖颜色作为唯一条件。
52
+
53
+ ## 能力评估规范
54
+
55
+ **R18**:能力评估题必须填写 `abilityIds`、`skillAtoms`、`expectedAbilityErrors`。`abilityIds` 只能来自 `context.options.abilityIds`。
56
+
57
+ ## 阶段分离规范
58
+
59
+ **R19**:出题草稿阶段只生成题面、题型、知识点绑定、预期错因、分值和留白行数。不输出 `answer`、`solutionSteps`、`rubric`。
60
+
61
+ **R20**:答案补全阶段只为已定稿题目输出 `id`、`answer`、`solutionSteps`、`rubric`。不得修改题目 ID、题干、题型、知识点绑定或任何其他字段。
@@ -1,4 +1,4 @@
1
- import { access, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
1
+ import { access, copyFile, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import {
@@ -175,9 +175,16 @@ export async function ensureChapterWorkspace(chapter) {
175
175
 
176
176
  const folderPath = path.join(paths.imageRoot, chapter.imageFolder);
177
177
  const sourceFiles = await listSourcePageImages(folderPath);
178
+ // source_pages/ holds the chapter's local source-page copies (see AGENTS.md).
179
+ // When the manifest is stale and no local copies exist, copy the images from
180
+ // the shared imageRoot into source_pages/ so chapterImages can resolve them.
181
+ await Promise.all(sourceFiles.map((file) => copyFile(
182
+ path.join(folderPath, file),
183
+ path.join(chapterPaths.sourcePages, file)
184
+ )));
178
185
  await writeJson(
179
186
  chapterPaths.sourceManifest,
180
- buildSourceManifest(chapter, chapterPaths, sourceFiles, folderPath)
187
+ buildSourceManifest(chapter, chapterPaths, sourceFiles, chapterPaths.sourcePages)
181
188
  );
182
189
  return chapterPaths;
183
190
  }