# 课程内容包 JSON 格式 > 对应《学习引擎规格》第 5 节。本文说明 A1–B1 单元内容包的文件位置、字段和程序校验规则。A0 仍按《A0 初始核心课程包》,不在此格式内。 ## 1. 文件与工具 | 路径 | 内容 | |---|---| | `kouyu_english/assets/courses/course-map.json` | 主题地图:等级、单元顺序、每级的数量范围、名称白名单 | | `kouyu_english/assets/courses/<等级>/<单元ID>.json` | 单元内容包,一个单元一个文件 | | `kouyu_english/tool/courses/lexicon/` | 锁定的 CEFR-J 数据与 `SOURCES.md` | | `kouyu_english/tool/courses/pools/` | 等级词池(`build_word_pools.py` 生成) | | `kouyu_english/tool/courses/validate.dart` | 校验全部内容包,报告词池覆盖率 | | `kouyu_english/test/course_content_test.dart` | 在 `flutter test` 中要求校验零错误 | ```sh cd kouyu_english dart run tool/courses/validate.dart # 错误和覆盖率 dart run tool/courses/validate.dart --uncovered B1 # 按主题列出未覆盖的词池词 dart run tool/courses/validate.dart --levels B1-U14 # 打印条目的计算等级 ``` 内容包目前只是资源文件,尚未加入 `pubspec.yaml`,运行时也还不读取。 ## 2. 当前内容(2026-09-17,全部为 `draft`) | 等级 | 单元 | 产出核心 | 理解词 | 听读材料 | 词池覆盖 | |---|---|---|---|---|---| | A1 | 21 | 265 | 598 | 42 | 840/933(90.0%) | | A2 | 15 | 217 | 862 | 44 | 1040/1078(96.5%) | | B1 | 14 | 206 | 1121 | 42 | 1345/1552(86.7%) | 全部由 AI 起草、程序校验通过,尚未经过独立审核和用户确认,不能冻结。 ## 3. course-map.json ```jsonc { "schemaVersion": 1, "goal": "日常生活与旅行", "sources": ["CEFR-J Vocabulary Profile 1.5(…)", "CEFR-J Grammar Profile 20180315(…)"], "minimumPoolCoverage": 0.85, // 等级词池覆盖下限 "alwaysAllowedWords": ["oh", "ok", …], // 任何文本都可用的语气词 "names": ["tom", "london", "mr", …], // 全局专名、缩写 "levels": [{ "id": "B1", "title": "独立应对大多数情况", "coreRange": [10, 15], "receptiveRange": [70, 110], "materials": {"count": [2, 3], "listeningWords": [250, 550], "readingWords": [300, 500]}, // A1 的材料较短,且可选 "unknownTolerance"(默认 0.02)放宽超纲词占比 "units": [{"id": "B1-U01", "file": "B1/B1-U01.json", "title": "…", "categories": ["旅行"], "canDo": "…"}] }] } ``` 各等级范围: | 等级 | 产出核心 | 理解词 | 听读材料 | 听力词数 | 阅读词数 | |---|---|---|---|---|---| | A1 | 10–15 | 20–35 | 2 篇 | 60–120 | 80–150 | | A2 | 10–15 | 40–65 | 2–3 篇 | 120–280 | 150–250 | | B1 | 10–15 | 70–110 | 2–3 篇 | 250–550 | 300–500 | A1 材料短、面向零基础,`unknownTolerance` 设为 0.08(听读材料默认 0.02):允许更多“课程尚未正式教、但零基础者需要”的常用词,前提是每个都写进 `glosses` 给出中文,问题选项用中文以免受“选项须在原文出现”的限制。 `units` 的顺序就是推荐学习顺序,校验“已教的词”时按此顺序累积。 ## 4. 单元文件 ### 4.1 ID 规则 所有 ID 都以单元 ID 开头,序号从 1 连续编号: | 前缀 | 对象 | 例子 | |---|---|---| | `W` | 产出核心:单词 | `B1-U14-W01` | | `P` | 产出核心:词块或句型 | `B1-U14-P01` | | `R` | 理解词 | `B1-U14-R01` | | `S` | 教学段 | `B1-U14-S1` | | `C` | 场景 | `B1-U14-C1` | | `T` | 任务 | `B1-U14-T1` | | `M` | 听读材料 | `B1-U14-M1` | ### 4.2 顶层字段 ```jsonc { "schemaVersion": 1, "id": "B1-U14", "revision": 1, "level": "B1", "title": "写说明与投诉", // title/categories/canDo 必须与 course-map 一致 "categories": ["日常", "旅行"], "canDo": "写邮件说明经过并提出要求", "status": "draft", // draft / reviewed / frozen "meta": { "draftedBy": "claude-opus-5", "draftedAt": "2026-09-17", "sources": ["CEFR-J Vocabulary Profile 1.5", "CEFR-J Grammar Profile 20180315"], "reviews": [], // 审核记录 "frozenAt": null }, "names": ["seaview", "palace"], // 本单元专名,小写 "grammar": [{"id": "142", "use": "active"}, {"id": "215", "use": "receptive", "reason": "…"}], "coreItems": […], "receptiveWords": […], "segments": […], "scenes": […], "tasks": […], "materials": […], // A1 起(A1 为短材料) "rubric": {"dimensions": […]}, // A2 起(A1 无开放任务评分标准) "excluded": [{"en": "…", "reason": "…"}] } ``` ### 4.3 coreItems(产出核心) ```json { "id": "B1-U14-P08", "type": "phrase", "en": "I would like to request a full refund.", "zh": "我想申请全额退款。", "sceneWord": false, "match": [["request a full refund", "request a refund"]], "example": {"en": "I would like to request a refund for the second night.", "zh": "我想申请退还第二晚的费用。"}, "review": {"prompt": "在邮件里提出退款要求。"} } ``` - `type`:`word` / `phrase` / `pattern`。 - `match`:判定用户是否用到本项。外层数组之间为“且”,内层为“或”;每个词条按连续短语匹配(缩写展开、忽略大小写和标点)。`en` 和 `example.en` 都必须满足。 - `sceneWord`:高于本等级或 CEFR-J 未收录、但场景必需的词句设为 `true`,并写 `sceneReason`;每单元不超过产出核心的 1/3。 - `review.prompt`:复习时的中文任务,不能直接包含英文答案。 ### 4.4 receptiveWords(理解词) ```json {"id": "B1-U14-R01", "en": "furthermore", "zh": "此外"} ``` - 不高于本等级加一级(B1 单元最高 B2)。 - 不能是 A0 或之前单元已教的词(按词形还原比较)。 - 必须出现在本单元的教学段、场景或听读材料文本中。 ### 4.5 segments(教学段) 每单元 2–4 段,每段 8–15 分钟、最多 6 个新产出核心: ```jsonc { "id": "B1-U14-S1", "title": "说明写信目的", "minutes": 12, "itemIds": ["B1-U14-P01", "B1-U14-P02"], "listening": {"text": "…", "question": "…", "options": ["正确", "干扰", "干扰"]}, "speaking": [{"text": "…", "tip": "可选的发音提示"}], "reading": {"text": "多行用 \n", "question": "…", "options": ["…", "…", "…"]}, "writing": {"prompt": "…", "example": "…", "itemIds": ["B1-U14-P01"]}, "independent": {"prompt": "…", "itemIds": ["B1-U14-P02"]} } ``` - 选项恰好 3 个,第一个是正确答案(界面随机排序);选项不能互为子串。英文选项至少两个在原文出现,且正确选项必须出现。 - `writing.example` 必须用到它引用的每个产出核心。 ### 4.6 scenes 与 tasks ```jsonc { "id": "B1-U14-C1", "kind": "main", // 恰好 1 个 main,另有 2–3 个 variant "title": "…", "learnerRole": "客人", "aiRole": "酒店客服经理", "setting": "…", "turns": [ // 4–7 轮 {"ai": "AI 说的话", "goal": "本轮目标", "model": "学习者示范回答", "zh": "示范的中文", "itemIds": ["B1-U14-P01"]} ] } ``` ```json {"id": "B1-U14-T1", "sceneId": "B1-U14-C1", "goal": "…", "itemIds": ["B1-U14-P01"], "slots": ["目的", "经过", "结果", "要求"]} ``` - `model` 必须用到本轮 `itemIds` 引用的产出核心。 - 每个场景至少有一个任务,每个任务至少 1 个信息槽。 - 每个产出核心都要出现在教学段、场景示范和任务中。 ### 4.7 materials(A1 用短材料,A2、B1 更长) ```jsonc { "id": "B1-U14-M1", "mode": "reading", "title": "投诉邮件和回复", "text": "…", "glosses": {"balcony": "阳台"}, "questions": [{"type": "gist", "question": "…", "options": ["正确", "干扰", "干扰"]}] // 2–4 道,gist/detail/inference } ``` - 每单元听和读都要有。 - 超纲词(见第 5 节)按词次不超过该级 `materials.unknownTolerance`(默认 2%,A1 为 8%),每个超纲词都要写进 `glosses`。 - A1 材料应尽量把本单元的理解词织进听读文本,让理解词在教学段之外再复现一次(本级平均单元内复现率约 77%);本单元的产出核心与理解词都算已教词,写进材料不计超纲。 ### 4.8 rubric(A2 起) ```json {"dimensions": [{"name": "说明经过", "bands": ["经过说不清", "能按顺序说明经过,但缺少结果", "按顺序说明经过、结果,并附上证据"], "pass": 1}]} ``` 至少 2 个维度,每维至少 3 档;`pass` 是及格档在 `bands` 中的下标(从 0 起),须大于 0。 ## 5. 文本用词检查 “已知词”包括:`alwaysAllowedWords`、功能词、A0 已教的词、推荐顺序在前的单元的产出核心和理解词、本单元的产出核心和理解词(均按词形还原),以及全局与本单元的 `names`。数字不计。 | 文本 | 允许的未知词 | |---|---| | 教学段的听、说、读、写示范,场景的 AI 句和示范句 | 0 | | 听读材料 | ≤ `materials.unknownTolerance`(默认 2%,A1 为 8%),且全部有 `glosses` | 注意:等级低于本单元、但还没有被任何单元教过的词(如 `history`、`culture`)同样算未知词。要在文本中使用,须改写,或把它加为本单元的理解词。 ## 6. 等级与覆盖 - 语法:`active` 语法项不高于本等级,否则写 `reason`。 - 产出核心中的词不高于本等级,除非是场景词。 - 覆盖率:等级词池(`tool/courses/pools/`)中,被产出核心、`match` 词块或理解词覆盖的词(含 A0 已教)占比须 ≥ `minimumPoolCoverage`。 ## 7. 状态流转 `draft`(AI 起草、校验通过)→ `reviewed`(独立审核后,在 `meta.reviews` 记录审核模型、日期和问题清单)→ `frozen`(用户确认,填 `frozenAt`)。已冻结单元的 ID 不复用;修改须提升 `revision` 并遵循《学习引擎规格》5.5 的 stageVersion 规则。