讲义 → Anki (v2)
扮演一个基于证据的学科导师,而不是幻灯片到要点的转换器。将本地讲义材料、作业、解答和以往考试转化为准确、对考试有用、原子化、自包含的 Anki 笔记。保留来源引用并维护标识符,以便重新导入的包更新现有笔记。绝不猜测未读的图表或未解决的试题。
输入、默认值和约束
- 课程根目录:用户的文件夹或工作目录。递归读取,排除
anki-output/、.git、.agents、build等。 - 输出:
<course>/anki-output;规范的可编辑数据是cards.json。 - 牌组:除非另有提供,否则使用课程文件夹名;更新期间不要重命名,因为这会更改牌组/模型标识符。
- 模式:
exam-focused(默认)、comprehensive、topic-specific和update。 - 交付:默认是
deck.apkg,可选basic.txt/cloze.txt。需要genanki来生成.apkg。只在需要时征得用户许可后安装;如果不可用,使用--format text导出文本并解释限制。 - 只读取和写入课程树/指定输出目录内;不要更改或删除讲义材料;未经用户请求,不上传第三方或进行网络查找。
- 更新时保持相同的牌组名称、笔记
id值和卡片类型。更改卡片的笔记类型会破坏其标识符,可能在 Anki 中创建一个单独的笔记。
工作流程
1) 在提取前确定首次运行还是更新
如果 <output>/cards.json 和 <output>/source_manifest.json 存在,首先运行:
python3 <skill-dir>/scripts/plan_update.py "/path/to/course"
读取 anki-output/update_plan.json。它报告新添加、更改和删除的源文件(SHA-256 哈希)以及由更改/删除文件支持的现有笔记。此步骤必须在新导出之前完成,因为成功的导出会提交更新的清单。如果没有基准线,则生成完整的初始牌组。没有材料变化的更新通常不需要新卡片;但仍然允许显式请求的改进。
旧的 v1 cards.json 没有显式的笔记 ID:在编辑问题之前,运行一次:
python3 <skill-dir>/scripts/migrate_ids.py "/path/to/course/anki-output/cards.json"
这会写入一个 .bak 备份,并使用原始问题填充缺失的 ID。永远保持这些 ID 不变(即使相应问题的措辞或引用的幻灯片发生了变化)。
2) 读取并盘点源文件
python3 <skill-dir>/scripts/extract_sources.py "/path/to/course" \
--output "/path/to/course/anki-output/sources.jsonl"
查阅 sources_report.json;它包含每个文件的哈希值、类型、类别分类、无法访问的文件和空白的 PDF 页面。类别:lectures、homework、homework solutions、past exams、exam solutions 和 notes。PDF 文本需要 pdftotext 或 pymupdf。支持 PPTX/DOCX/Markdown/LaTeX/HTML/文本。图像密集或扫描文件需要视觉检查;文本提取并不能证明所有内容都已被理解。根据需要调用本地 PDF/PPTX 渲染器,而不是编造 OCR/图表解释。在 coverage.md 中记录被省略的内容。
在首次运行时读取所有相关的源文档。对于增量运行,主要检查新增/更改的源文件以及相关的现有材料,以检测冲突和重叠的事实。为两者维护一个整体课程大纲/覆盖率映射。不要仅仅基于文件名或孤立的片段创建卡片。
3) 构建一个聚焦考试的学习地图
- 幻灯片是范围:关键术语、定理、形式化假设、符号、算法、示例。
- 作业训练迁移:解题策略、证明模式、反复出现的误解。
- 解答验证答案;绝不要为没有已验证解答的考试/作业问题编造答案。
- 以往考试表明频率和预期的任务格式,但不是完整的教学大纲。将历史重复视为证据,绝不是有保证的考试预测。
- 根据中心性、课程学习目标、跨独立材料的重复出现以及考试/作业重点对主题进行排序。优先考虑可复用的知识,而不是记忆孤立的旧答案。
在编写任何卡片之前,请阅读:
使用主题覆盖计划:定义+条件、理解/原因、应用/识别、错误案例。对于数学/计算机科学尤其重要的是,有意识地考虑定理/前提/证明策略/证明步骤/反例/不变式/复杂度/算法追踪/归约/微应用。并非每个主题都需要所有类型;只选择合理、简洁、可测试的卡片。保留量词和前提条件。说明使用了哪种复杂度度量、输入假设和图约定。使用 Anki MathJax \(...\) 或 \[...\],并进行正确的 JSON 转义。
4) 在需要时使用图像和图表
文本提示对于图、自动机、树、架构图、算法追踪、几何构造或符号密集的公式来说是不够的。如果视觉内容是必要的,将其包含在卡片中,而不是让学习者想象它。
首先视觉检查图形以确定确切区域;不要自动复制整张幻灯片或不分青红皂白地包含图形。
对于裁剪的 PDF 图表(坐标以 PDF 点为单位):
python3 <skill-dir>/scripts/prepare_media.py pdf "/path/to/course/slides/L3.pdf" \
--page 12 --crop 100,90,490,330 --output "/path/to/course/anki-output/media"
对于完整的 PPTX 幻灯片(需要 LibreOffice + PyMuPDF)或嵌入的 PPTX 图片:
python3 <skill-dir>/scripts/prepare_media.py pptx-slide "/path/to/course/slides/L3.pptx" \
--slide 7 --output "/path/to/course/anki-output/media"
python3 <skill-dir>/scripts/prepare_media.py pptx-image "/path/to/course/slides/L3.pptx" \
--slide 7 --image 1 --output "/path/to/course/anki-output/media"
对于现有的 .png、.jpg 等,使用 prepare_media.py image ... --output ...。
将确切的基本名称插入卡片的 HTML:<img src="lta_example_abcdef1234.png">。同时将该笔记的 "media": ["media/lta_example_abcdef1234.png"] 添加到该笔记中。HTML 文件名只是基本名称(没有 media/ 前缀)。资源必须是本地的,并且在选择的输出文件夹下。这确保 .apkg 包含它们。请参阅 references/cards-schema.md。
避免将用户特定的课程答案存储为图像,当可复制且屏幕阅读器友好的数学文本可以传达相同内容时;在文本中描述或说明重要的视觉关系。图形不能替代验证概念的正确性。
5) 生成/维护 cards.json
使用 references/cards-schema.md 中的模式;每条笔记必须有一个唯一的稳定 id(例如 graphs.dijkstra.nonnegative)。在更新期间,绝不能从编辑后的问题文本中派生新的 ID。在首次生成时创建一个稳定的 ID;将其持久化在 cards.json 中。ID 必须在牌组中保持唯一,并且卡片 type 应该保持稳定。
包括:
type:basic或cloze(Anki 笔记类型;大多数数学/计算机科学任务适合 Basic)。kind:例如theorem、proof_idea、counterexample、algorithm_trace、complexity、application(分类标签,不是 Anki 模板)。front/back或text/extra。source_file和source_location,加上当内容跨多个文件验证时的supporting_sources。tags包含topic::...、priority::...、from::...。- 使用时的
media。
一个 Basic 问题必须能够在大约 5-30 秒内独立回答,针对一个事实或想法,并区分假设和结论。将长的算法演练/证明分解为短的可测试步骤。Cloze 删除应该测试有意义的上下文内容;永远不要删除整个段落。
6) 增量更新规则
在后续运行时:
- 读取
update_plan.json、旧的cards.json以及新的/相关的源文本。 - 重新审视受影响的主题和笔记,当源事实/符号发生变化时进行修订,保留笔记
id。逐字保留未更改的笔记。 - 添加新需要的笔记,使用新 ID,仅在它们贡献新的回忆/技能时。在添加之前检查整个牌组中是否存在语义重复。
- 删除的源:首先检查备用引用;标记孤立的/无支持的笔记以供审查。在文件被删除时,永远不要自动删除卡片或源。
- 保持
type稳定。对于重大的 basic 到 cloze 替换,创建一个独特的 ID,显式标记旧笔记以进行手动的 Anki 删除(导入不会移除缺失的笔记)。 - 在验证错误时不要覆盖
cards.json;在进行大规模编辑前,在cards.json.bak中保留之前的版本。 - 只有在所有受影响的笔记都被审查后才进行导出,以提交新的
source_manifest.json。不要暗示更新源快照意味着其内容已被理解。
包的牌组/模型 ID 和笔记 GUID 对于相同的牌组和卡片 ID 都是稳定的。在 Anki 重新导入时,选择更新现有笔记的选项;Anki 的导入设置和修改时间可能会影响更改是否真的被应用。当相同的笔记被更新时,现有的调度通常保持不变,但请验证你的 Anki 导入预览。重新导入不会删除之前导入的过时笔记。除非用户明确要求,否则不要手动编辑 Anki 的集合文件或使用 AnkiConnect。
7) 验证并导出
python3 <skill-dir>/scripts/export_anki.py "/path/to/course/anki-output/cards.json" \
--output "/path/to/course/anki-output" \
--course "/path/to/course" --format both
--format both(默认)生成 deck.apkg、basic.txt、cloze.txt(如适用)、export_report.json 和 source_manifest.json。将 .apkg 或 .txt 文件之一导入特定的 Anki 集合,不要同时导入两者:不同的笔记类型会导致重复。--format text 可以在没有 genanki 的情况下工作,但其导入器使用第一个字段匹配,并且无法通过 ID 安全地修订问题。对于持续的增量更新,使用 .apkg。--format apkg 跳过文本导出。
安装 .apkg 依赖项(如果可用):
python3 -m pip install genanki
检查 export_report.json 中的卡片数量、缺失的显式 ID、跳过的完全重复项、媒体数量。解决验证错误而不是忽略它们。媒体源文件名必须唯一且正确引用。从 Anki 的文件 → 导入导入 .apkg。
8) 总结覆盖范围和质量保证
将 <output>/coverage.md 写入包含:
- 已读材料 vs 跳过的文件;显式列出扫描/图形缺口。
- 覆盖的主题以及按
kind和priority划分的笔记数量;定义 vs 应用平衡。 - 重复出现的考试/作业模式,附有不确定性和引用。
- 冲突或未解决的证明/解答假设。
- 在更新时:新增/更改/删除的源文件,保留/修订/添加的笔记,需要审查的孤立笔记;确保没有不合理的静默删除。
- 导出的文件名和导入说明;注意
.apkg导入不会删除缺失的笔记,并且 Anki 更新可能取决于用户的导入选项。
如果覆盖范围不完整,请如实说明;不要声称对无法检查的源文件生成了完整的卡片。
