feat(复习):标准思维导图生成与回忆对比

- 新增 review_standard_mind_maps / review_recall_records 数据表
- BuiltinMindMapGenerator:从报告/残片/应用场景规则生成标准导图
- MindMapAiClient 接口 + RemoteAiMindMapClient 预留
- StandardMindMapService:生成/编辑/重新生成/回忆对比
- 对比算法:标题归一化 + Bigram Jaccard 模糊匹配
- ReviewController 新增 6 个端点
- MindMapTreeTool / MindMapNode / CompareResult 工具类
- 完整单元测试(10 个,全部通过)
- 更新 docs/review-module-design.md
This commit is contained in:
2026-07-03 08:53:51 +08:00
parent 5f3f35c53b
commit 32b247526b
34 changed files with 1890 additions and 153 deletions
+164
View File
@@ -0,0 +1,164 @@
# 复习模块设计说明
本文档是对复习功能当前实现边界的工程说明,不修改原始需求文档。
## 核心理解
复习模块包含两类不同层级的体验:碎片化提醒和围绕思维导图的主动回忆。二者都属于复习模块,但不是同一个业务流程。
## 碎片化提醒
碎片化提醒展示用户自己在学习过程中写下的学习报告和学习残片。
这些内容不是完整复习记录,而是日常滚动出现的记忆触发物。用户看到一段自己写过的内容时,如果能立刻回想起上下文,说明相关知识暂时不需要深入复习;如果想不起来,可以点击进入详情页回看,形成一次轻量提醒。
当前对应能力:
- `GET /review/feed`
- `GET /review/task/{taskNum}`
- `GET /review/report/{id}`
- `GET /review/fragment/{id}`
- 前端 `Review.vue`
- 前端 `ReviewDetail.vue`
## 当前阶段边界
当前阶段暂不追求完整的自动化复习分析,因为项目尚未引入 AI 来处理学习碎片和导图数据。
当前阶段复习模块只需要保留思维导图的基本结构能力:
- 保存任务对应的思维导图
- 支持用户上传外部导图文件
- 解析导图的基础节点结构
- 允许用户在碎片化提醒中回看学习报告和学习残片
这个阶段不应该强制用户逐条处理大量学习碎片。学习碎片很多时,逐条关联和对照会让复习过程变得漫长、枯燥,并违背复习模块“简单、不抵触、可随意围绕某个知识点复习”的初衷。
## 思维导图的意义
思维导图不是普通附件,也不是单纯的存储对象。它是复习模块的主要交互形式。
用户复习时,主要动作应该是围绕某个知识点进行回忆,并编写或重绘思维导图。导图的意义在于降低复习阻力:用户不需要按顺序处理所有碎片,而是可以从任意知识点出发,自由地把自己能想起来的内容组织成结构。
初版设计中已经提到:
- 后续复习时可以在脑子里重绘那张图
- 没有想起来的部分就是需要重新看的地方
- 如果顺利绘制出了好的思维导图,就替换原来的思维导图
- 如果能顺利用思维导图描述所学内容,复习效果就能体现在这个过程中
因此,导图应该是复习效果的表达方式,而不仅是文件存储。
## 应用场景的位置
应用场景不应归属复习模块。
应用场景更接近学习任务的最终目标:完成整个学习任务后,用户希望能做什么、产出什么、应用到哪里。它应该挂在学习任务模块下,而不是挂在复习流程或某条学习碎片下。
当前实现已将其迁移为任务级能力,由任务页面维护,并使用 `task_applications` 存储。
## 模块边界
学习执行模块产生学习报告和学习残片。
复习模块使用这些产物做两件事:
- 在碎片化提醒中滚动展示它们
- 在引入 AI 后,把它们整理进程序生成的知识网络
复习模块不要求用户手动逐条整理学习报告和学习残片。学习报告/残片是后续自动整理和对照分析的数据来源。
## 下一阶段设计:AI 生成导图与用户导图对比
下一阶段引入 AI 后,复习模块的目标应升级为:
1. 程序读取学习报告、学习残片、已有导图等数据。
2. 程序自动将碎片整理成一个具有关联关系的巨大思维导图。
3. 用户围绕某个知识点进行回忆,并绘制自己的导图。
4. 系统将用户导图与程序生成导图进行结构对比。
5. 系统定位用户忽略、遗漏、误解或尚未建立关联的内容。
6. 用户根据差异回看必要的学习报告或残片,而不是从头处理所有碎片。
这个设计可以解决当前手动复习流程的两个问题:
- 学习碎片很多时,不需要用户逐条筛选,避免复习过程漫长且枯燥。
- 思维导图不再只是存储对象,而是成为用户回忆结果和程序知识网络之间的对照媒介。
## 对初版设计的补充判断
初版设计没有忽略“思维导图用于复习”的方向,反而已经明确指出导图应承担脑内重绘、发现遗漏、体现复习效果的作用。
初版设计没有具体描述“AI 自动整理碎片为巨大导图,并与用户导图进行对比”的实现逻辑。这是当前讨论对初版设计的重要补充,适合放入下一阶段实现。
初版中提到”复习内容可以应用到什么地方”,但结合当前理解,应用场景应从复习模块中移出,归入学习任务的最终目标或验收目标。
## 第二阶段实现:标准思维导图与回忆对比(2026-07-03)
第二阶段将 AI 生成导图与用户导图对比的设计落地,引入以下能力:
### 核心概念
- **标准思维导图(Standard Mind Map)**:每个学习任务对应一份”标准”导图,由系统从该任务的已有学习报告、学习残片、应用场景中提取整理而成。它是用户回忆的对照基准,也可由用户手动编辑修正。
- **回忆对比(Recall Review)**:用户凭记忆以缩进大纲格式写下对该任务知识点的回忆,系统将其与标准导图进行树结构对比,定位已掌握、遗漏和额外回忆的内容。
### 内置生成器(BuiltinMindMapGenerator
当前阶段未接入外部 AI,由内置规则引擎生成标准导图:
- **根节点**:任务名称
- **一级分支**:按学习会话分组,以”日期 + 报告前60字摘要”为标题
- **子分支**:该会话下的每条报告、每条残片成为一个子节点
- **应用场景分支**:如有已创建的应用场景,附加为独立的”应用场景”分支
- **去重**:同级节点按标准化标题对比并合并
- **追溯**:每个节点携带 `sourceType`REPORT/FRAGMENT/APPLICATION)和 `sourceId`,前端可点击回看原文
### AI 客户端抽象(MindMapAiClient
预留了远程 AI 调用接口,供后续接入真实 AI 使用:
- 配置项 `lpt.ai.endpoint` / `lpt.ai.api-key`(当前均未配置)
- 未配置时自动回退到内置生成器
- 接口返回 `MindMapNode` 树结构,与内置生成器输出格式一致
### 回忆对比算法(StandardMindMapServiceImpl.compareTrees
对比标准导图与用户回忆大纲的树结构:
1. **展平**:前序遍历将两颗树分别展开为节点列表
2. **精确匹配**:对每个标准节点标题做归一化(去空格标点 + 小写),在回忆节点中查找完全匹配
3. **模糊匹配**:未精确匹配时,计算字符 Bigram Jaccard 相似度(阈值 0.6),容忍中文同义表达
4. **标注**:匹配的节点标注 `MATCHED`,遗漏的节点标注 `MISSED`,用户多写的内容归为 `EXTRA`
5. **统计**:计算回忆覆盖率 `recall_ratio = matched / (matched + missed)`
### 用户交互
- **回忆复习页**`/review/recall/:taskNum`):双栏布局。左栏为回忆大纲输入区(缩进文本)+ 对比结果展示,右栏为标准导图区(默认折叠防剧透)
- **标准导图编辑**:用户可展开查看、编辑大纲文本并保存,编辑后来源标记为 `USER`
- **重新生成**:如需从头生成新版本,可一键重新生成
- **遗漏项回溯**:对比后定位到的遗漏知识点自动列出,点击”查看原文”可直接跳转到对应的报告/残片详情页
- **回忆历史**:查阅历次回忆对比记录,查看覆盖率变化趋势
### 新增数据库表
- `review_standard_mind_maps`:每任务一行,存储标准导图的 JSON 树结构、大纲文本、生成元信息
- `review_recall_records`:存储用户每次回忆对比的原始大纲、对比结果 JSON、覆盖率等统计
未改动既有表的 schema,与原有 `review_mind_maps`(用户手动上传的导图文件)并存。
### 新增端点
| 方法 | 端点 | 说明 |
|------|------|------|
| GET | `/review/standard-mind-map/{taskNum}` | 获取或自动生成标准导图 |
| POST | `/review/standard-mind-map/{taskNum}/regenerate` | 强制重新生成 |
| PUT | `/review/standard-mind-map/{taskNum}` | 用户编辑标准导图 |
| POST | `/review/standard-mind-map/{taskNum}/recall` | 用户提交回忆大纲,返回对比结果 |
| GET | `/review/standard-mind-map/{taskNum}/recall-records` | 回忆对比历史列表 |
| GET | `/review/standard-mind-map/recall-records/{recordId}` | 单条回忆记录详情 |
### 下一步展望
- 接入真实 AI API(配置 `lpt.ai.api-key` 后切换为 AI 生成器,内置生成器作为降级)
- 可视化思维导图渲染(而非纯缩进文本展示)
- 对比结果中显示更精确的路径定位
- AI 驱动的用户导图评分与改进建议