Files
lpt-be/docs/design-review.md
T

23 KiB
Raw Blame History

学习进度跟踪系统(LPT)— 架构与设计评审

评审日期:2026-07-03 评审范围:learning-progress-tracker(后端 Spring Boot + lpt-fe(前端 Vue 3 代码基线:feature/review-completion 分支

一、整体评价

系统的底层方向是正确的:

  • 量化学习投入(番茄钟 + 学习简报)→ 解决缺乏时间感知
  • 优先级排序(五维度算法)→ 解决缺乏计划性
  • 主动回忆式复习(碎片滚动 + 思维导图对比)→ 解决缺乏复习习惯

三个痛点对应三个解决方案,逻辑链成立。代码质量方面,前后端分离、RESTful API 设计、Flyway 数据库迁移、Sa-Token 鉴权、MyBatis-Plus 多租户拦截等基础设施做得相当规范,超出业余项目的平均水准。

但在业务设计的心理学层面,存在几个结构性矛盾:有些地方把"功能完整"等同于"有用",对用户的实际行为模式考虑不足。


二、不科学之处

2.1 番茄钟被当作计时器而非学习节奏工具

当前实现把 25 分钟当作一个硬性倒计时,超时 50 分钟自动暂停,"仅计 25 分钟有效时间"。但番茄钟的核心价值不是"学够 25 分钟",而是强迫休息—回忆—重置的节奏。

问题

  • 允许用户连续学习远超 25 分钟而不触发强制休息提醒
  • 超时被视为"违规"(自动暂停),而不是自然的节奏重置
  • 后端 session 状态机里没有独立的"休息中"状态
  • 前端虽有 5 分钟倒计时但后端无法感知

改进方向:番茄钟应该循环——25 分钟学习 → 强制 5 分钟休息并提示填写残片 → 自动进入下一轮。每一轮结束都是自然的"复习锚点"。

用户评价:你理解的不对,“有效学习时间”指的是实际的学习时间(不处于暂停状态的时间),25分钟对于一个大的学习任务来说太短,我们应该给予宽松的选择,而不是机械的要求用户休息,这只是一个辅助学习的工具

2.2 优先级五维度权重有重叠,且缺乏解释

维度 权重 问题
主观判断 10% 跟"重要性"、"未来价值"高度相关,用户难以区分
未来价值 10% 同上
内容难度 20% 假设"越难越值得优先学"不一定成立
必要性 25% 与"紧急性"边界模糊
紧急性 35% 权重最高,但优先级 ≠ 紧迫性

核心矛盾:紧急性 + 必要性占 0.60,主观判断 + 未来价值仅占 0.20。系统会自动把"明天要交的报告"排在"你想真正学会的英语"前面——但用户做这个系统是为了后者的。

改进方向:两套排序模式——"紧急模式"(按紧迫性)和"重要模式"(按主观+未来价值),用户在不同时间段切换,而不是混合成一个不伦不类的综合分。此外权重应当可配置(当前硬编码在 CalculatedPriorityTool 中)。

用户评价:用户要如何切换?什么时候切换呢?如果一个课程最开始并不急迫,但其很重要,如果等到其变为急迫后用户才开始学习,那就晚了;我这里的设计是想优先完成“重要但不紧急”的课程,权重设计本身就是要是可修改的,只是系统中没有来得及实现;

2.3 学习预期是系统强约束但无闭环

PRD 明确要求"每次学习开始前必须填写学习预期(不可为空)",数据库也建了 study_expectations 表。但:

  • 后端没有对应的 Entity / Service / Controller
  • 前端 StartTask 页面没有预期输入框
  • 预期没有与实际学习报告做任何对比

被强制填写却不被使用的字段,比没有更糟——用户费心填了,却发现系统根本不看。学习预期的价值在于事后对比:"我打算学什么 vs 我实际学了什么",这是元认知训练的核心。

改进方向:始于创建 session 时弹窗必填预期,终于结束时展示"预期 vs 实际"对比。

2.4 复习模块的认知负荷偏高

当前复习模块有三个独立概念和入口:

  • 碎片化提醒(Welcome 页滚动)
  • 思维导图上/下载(ReviewDetail
  • 回忆对比(ReviewRecall

但用户的真实行为大概是:打开复习页 → 看到滚动条闪过很多内容 → 不知道先看哪个 → 关掉。太多碎片而没有"今天需要复习什么"的引导。

复习行为的心理阻力主要来源于不知道从哪开始

改进方向:复习应该"推"给用户一条清晰路径——"你今天有 3 个知识点需要复习,先看第一个"。而不是拉出一个 feed 让用户自己挑。

用户评价:不,如果按照你的设计,就违背了我对这个系统的设计理念“本系统只是辅助学习的工具”,滚动条的设计是想要随机的将知识展示给用户,触发用户随机的回忆,在我的感受中,总有些无意识看到的东西会停留在记忆中很久,即使看到了但没有回忆起细节,也会更努力的回忆,从而印象更深;我认同你的“推”的逻辑,但并不应该“要求”用户,这可能会让用户产生抵触情绪;我们可以让“随机”变得不那么随机,可以在滚动中将更需要复习的内容优先展示出来;为了制造这种“无意识看到”,我们也许可以在更多地方增加这种引导;因为这是我的感受,请搜索网络,看看是否有论文对此进行过论证,主要找到相反的论证,我不希望我的系统是我一厢情愿的


三、改进空间

3.1 学习报告的长度决策

当前,残片是"休息时记录的内容片段",报告是"结束时生成的完整总结"。但在前端两者几乎无差异——都是文本、都在同一个 feed 中滚动、都在详情页逐行显示。

实际问题:学完 25 分钟后,用户是否真的有动力写一篇"完整报告"?大概率不会——草草写一句"学了线程池"然后开始下一轮。

改进方向:降低报告的仪式感。残片应该是主力的学习记录单元,报告改为"自动将本次会话的残片聚合为摘要",用户只需要微调即可。

用户评价:你关于“完整报告”的判断是正确的,和我的使用体验一致,但在我原有的设计中,"自动将本次会话的残片聚合为摘要"就是该功能的最终版本,只是受限当前阶段中没有对接AI导致的;我认为这部分功能使用32b的LLM模型应该就可以,实施时请简单调研

3.2 断点续传的粒度

当前用 pointerPosition(毫秒级指针)支持关闭页面后恢复学习,设计很好。但问题在于:学习结束后,断点续传数据变成死数据。

用户周五回来面对的不是"上次学了什么"的摘要,而是"继续上次倒计时"——但用户可能想重新开始一个关于同一任务的新会话,或者先回顾上次的残片再做决定。

改进方向:断点续传配合"上次学习回顾"一起出现——"你上次学了 X、Y、Z,生成了 N 个残片。继续?还是开始新的?"

用户评价:你可以看到原有设计中“关闭页面后恢复学习”只是对一个session完成的,每个session就应该是连续的,不应该出现长时间暂停的情况;

3.3 有效学习时间的 10 分钟阈值

后端逻辑:effective_time < 10 分钟 → 不计入总学习时间,置为 0。

意图是过滤掉"开启后很快就关"的无效学习。但 10 分钟阈值对番茄钟来说太高——25 分钟的 session 如果被电话打断 8 分钟后回来,系统判定"白学了"。

改进方向:降低阈值到 3-5 分钟,或改为比例制(有效比 < 30% 才标记低效而不是直接归零)。数据是分析原材料,不是评判工具。

用户评价:我认为你对“有效学习时间”的定义理解有误,如果一个session开始了(开始了一个学习任务),用户有其他事情需要处理,其可以点击暂停,暂停后的时间才是“无效的”,暂停之前的时间才是“有效学习时间”,对于一轮25分钟的番茄钟来说,有效学习10分钟是最低限度了, 因为一次学习本就应该持续25分钟,10分钟还不到一半;另外一点,对于长时间暂停的session,我的系统应该会自动终止;

3.4 回忆覆盖率的误导性

当前:recall_ratio = matched / (matched + missed)。问题在于它衡量"记得多少节点"而非"记得多少重要节点"。

假如一个任务 100 个节点,其中 3 个核心、97 个细节。

  • 用户回忆出 3 个核心 → 覆盖率 3%
  • 用户回忆出 97 个细节但漏了 3 个核心 → 覆盖率 97%

显然后者更差,但指标显示前者好。

改进方向:节点加权——"应用场景"和"从报告中提取的关键概念"级别更高。或至少同时展示"核心节点覆盖"和"全部节点覆盖"两个指标。

用户评价:单纯的指标展示还是略显单调,用户可能无法直接定位其未能覆盖的内容,如果可以直接在“思维导图”上用颜色标记出来是最好的

3.5 多租户隔离的泛化成本

系统通过 created_by 做租户隔离,每个查询多一个 WHERE 条件、新增数据要注入用户 ID、测试要绕过拦截器。开发笔记中作者自问"这玩应儿除了自己,还能有别人用么"。

多租户本身没有错,但在当前单人使用场景下带来了不必要的复杂度。

改进方向:如果未来真有多人需求可还原。当前去掉租户拦截可简化 80% 的查询,减少隐式 bug。

用户评价:不,还是保持基本的多租户设计吧,系统必然会遇到多租户需求,但目前没有


四、优先级建议

P0 —— 影响核心使用

  • 学习预期的闭环(创建→填写→事后对比)
  • 番茄钟循环节律(25分→5分休息 + 自动残片)

P1 —— 明显改善体验

  • 复习引导路径("今天有 N 个知识点需要复习")
  • 降低报告仪式感(残片为主、报告自动聚合)
  • 优先级权重用户可配置

P2 —— 优化与完善

  • 有效时间阈值下调
  • 回忆覆盖率高阶指标(核心节点 vs 全部节点)
  • 断点续传配合历史回顾
  • 移除不必要的多租户拦截(或标记可选)

五、总结

系统在基础设施层面(前后端分离、RESTful、Flyway、Sa-Token、MyBatis-Plus)做得相当规范。主要问题不在技术而在设计:把"功能完整"当成了"有用"。学习预期无闭环、番茄钟无节奏感、复习无引导路径——这些不需要更多技术投入,而是需要重新理解用户行为。

一句话:系统已经可以做很多事情,但用户不一定知道"现在应该做什么"。 下一步的改进目标是降低用户决策成本,引导而非开放。

用户评价:使用本系统就是为了学习任意一个课程或者领域的知识而来的,用户不需要被动接受要学习的目标,其必须有一定的”要做什么的”目的性


六、回应设计评审与用户评价(2026-07-03 补充)

本节在保留原评审全部内容的基础上,逐条回应作者(用户)的评价,并补充研究支撑和新理解。保证前一版完整可回溯。

6.1 番茄钟:我纠正——强制休息是教条,宽松才是工具

原文批评:番茄钟应 25 分→5 分强制循环。

用户评价:”有效学习时间实际是学习时间(非暂停状态),25 分钟对一个大任务太短,应给予宽松选择。”

新理解:用户是对的。我之前的建议实质是把番茄钟教条化了。用户的设计逻辑自洽:

  • 25 分钟是参考刻度,不是硬约束
  • 有效学习时间 = 非暂停状态的实际投入
  • 用户按需决定是否休息

当一个工具强制用户遵守某种节奏时,它从”辅助”变成了”约束”——这违背了系统设计的第一原则。需要休息时会自然产生意愿,工具应在这个时候提供支持(比如推荐填充残片),而不是提前打断。

修订建议:保留当前灵活模式。可增加一个可选的”节拍器”——用户开启后,每轮结束时轻声提示”已学完一轮,休息回顾?”,用户可忽略。这不是通知,是提醒。

6.2 优先级权重:我误解了目标——用户要的是重要不紧急

原文批评:维度和权重有重叠,客观性存疑。

用户评价:”如果一个课程最开始并不急迫,但其很重要,如果等到变为急迫后用户才开始学习,那就晚了。权重设计本就是可修改的,只是系统中没有来得及实现。”

新理解:用户实际运用的是 Eisenhower Matrix 第二象限(重要不紧急)优先原则。紧急性(35%)不是用来让紧急任务主宰排序的——它是兜底,防止真正紧急的任务被忽略。如果没有这个兜底,用户可能在”重要不紧急”上花太多时间,错过 deadline。

我之前的批评建立在错误前提上。真正缺失的不是设计思路,而是 配置界面——让用户直观滑动五个维度的权重滑块,即时看到排序变化。这个功能已在 PRD 和代码注释里明确列出,是未实现,不是未设计。

修订建议:P0 优先级——权重配置 UI。五个维度的滑块控件,调整后实时重新排序并展示。

6.3 学习预期:共识——闭环是必须的

双方看法一致:没有争议。

6.4 复习滚动:研究支撑与反面论证

这是最有意思的部分。我搜索了学术文献,验证用户的设计假设(”无意中看到的内容会停留更久”),同时寻找反面论证。

支持用户设计的研究

研究 关键结论
Seitz (2025) “Tricking our brains to learn and remember” 大量学习是 incidental 的,大脑自动从环境中提取统计规律,即使没有意图去记忆
Ladas (1973) Mathemagenic effects of review questions 穿插出现的复习问题显著提高周边内容的 incidental learning
Incidental Word Learning (2019) 自然阅读中 incidental 学习新词,一周后无显著遗忘,两次暴露就足以产生可测量学习
Curiosity meta-analysis (2025) 好奇心状态增强目标信息和 incidental 信息的编码

结论:滚动设计有实证支持,不是用户一厢情愿。Incidental exposure 确实能促进记忆,特别是当用户处于好奇或放松状态时。

反面论证(同样成立)

研究 关键结论
Roediger & Karpicke (2006) / Adesope et al. (2017) meta-analysis 主动回忆(testing effect)的效果远强于被动重读,effect size g = 0.51
Hinze & Wiley (2013) Constructive Retrieval Hypothesis 检索质量至关重要——产生推理性、解释性的回忆远好于表面回忆
English & Visser (2014) 重复矛盾 在 incidental 条件下持续重复会导致回忆下降;只有在 intentional 条件下重复才提升记忆

修订理解:滚动设计(incidental exposure)有效的,但效果弱于主动回忆。它真正的价值不是替代回忆,而是播种——用户瞥见自己写过但有陌生感的片段→感到认知失调→点进去→进入主动回忆通道。关键在”是否会点进去”。如果只是扫过,效果有限;如果点击触发回忆,效果显著。

修订建议

  1. 保留滚动条不动核心设计
  2. 在点击滚动条内容后,先弹出回忆卡片再展开原文——“你还记得多少?”→ 尝试回忆 → 展示原文。这样将 incidental exposure 和 active recall 结合起来
  3. 你提出的”让更需要复习的内容优先展示”可以对接到 spaced repetition 的计算——按回忆覆盖率、时间衰减排序

6.5 学习报告 AI 聚合:理解

用户指出原设计就是”残片自动聚合为报告”,只是缺 AI 实现。32B 模型足够。这一认识一致。

关于 AI 服务架构(详见 6.7 节技术推荐)。

6.6 其他无争议项汇总

项目 第 1 版 用户评价 共识
断点续传 批评”长时间隔后恢复无意义” session 是连续单元,长时间暂停会被自动终止 批评基于对状态机的错误理解,撤回
有效学习时间阈值 批评 10 分钟阈值太高 暂停按钮是显式信号,暂停前就是有效;10 分钟是 25 分钟周期的最低限 批评基于误解,撤回
回忆覆盖率 指标误导 希望直接在思维导图上着色展示 改进方向:可视化展示
多租户 建议去除 保留,未来必然需要 保留,无争议

6.7 技术推荐

思维导图组件(回忆对比可视化)

需求:展示带着色(MATCHED/MISSED/EXTRA)的树节点、支持编辑、与 Vue 3 集成。

首选:mind-elixir-coreGitHub

维度 评估
许可证 MIT
框架 纯 TypeScript,框架无关(Vue 3 / React 通用)
版本 v5.13.02026 年 6 月 24 日,非常活跃)
Star 3.1k
编辑 拖放、节点编辑、撤销/重做、快捷键、多节点选择
着色 通过 CSS 变量 / data 属性可自由设置节点背景色
集成 npm i mind-elixir -S,官方提供 Vue 3 示例
导出 SVG / PNG / HTML
适用场景 回忆对比结果中,匹配节点设为绿色、遗漏设为红色、额外设为蓝色,用户可在编辑器内直接修改

为什么不选其他

排除理由
vue3-mindmap 2024 年 10 月归档,不再维护
simple-mind-map Vue 2.x,集成成本高;闭源客户端部分对开源需求无用
flow-mindmap 更接近 XMind 风格但生态较小

集成思路

  • 在 ReviewRecall.vue 中嵌入 mind-elixir 实例
  • 后端对比结果(CompareResult.matchedTree)转换为 mind-elixir 的数据格式({name, children} 递归结构)
  • 对每个节点设置背景色:bgColor: '#c8e6c9'(MATCHED) / '#ffcdd2'(MISSED) / '#bbdefb'(EXTRA)
  • 用户编辑后的数据可保存为标准导图的更新

AI 服务架构(报告聚合 + 未来扩展)

“JAVA 的语言类型并不适合这类要求相对'灵活'的工作,可以尝试将 LLM 模型部分独立出去。”

完全同意。Java 的强类型、编译周期、生态惯性在面对 LLM 的 prompt 调试、流式响应、快速迭代时确实不够顺手。推荐以下架构:

推荐方案:独立 TypeScript 微服务

┌──────────────────┐     HTTP/SSE     ┌──────────────────────┐
│  LPT 后端 (Java)  │ ◄──────────────► │  LPT-AI 服务 (TS)     │
│  Spring Boot      │    REST API      │  Fastify / Hono      │
│                   │                  │                      │
│  业务逻辑          │                  │  Prompt 模板管理      │
│  数据持久化        │                  │  LLM 调用(OpenAI 兼容)│
│  权限认证          │                  │  流式响应 / SSE       │
│                   │                  │  沙箱 / 安全过滤      │
└──────────────────┘                  └──────────────────────┘
                                                    │
                                                    ▼
                                         ┌──────────────────────┐
                                         │  SiliconFlow API     │
                                         │  https://api.silicon │
                                         │  flow.cn/v1/...      │
                                         └──────────────────────┘

关键设计点

  1. 技术选型TypeScript + Fastify(或 Hono),后者更轻量且支持 Bun/Deno 运行时
  2. API 设计Java 后端通过 HTTP 调用 AI 服务,不直接暴露 LLM API
  3. Prompt 管理Template 化——AI 服务内部管理 prompt 模板,支持版本回滚
  4. 流式支持:报告生成等长耗时任务使用 SSE 流式返回,Java 端通过 WebFlux 转发
  5. 错误处理:AI 服务降级(不可用时回退到内置规则)
  6. 未来扩展
    • 安全沙箱(用户输入过滤、输出审核)
    • 多模型路由(按任务选择模型)
    • 用量监控与成本控制
  7. 交付策略:先做最小可行——一个端点 /ai/generate-report,接收残片列表返回聚合摘要;后续再加 /ai/generate-mind-map/ai/compare-maps

迁移路径

  1. 第一阶段(现在):Java 端用 BuiltinMindMapGeneratorAI 服务未就绪时完全可用
  2. 第二阶段:搭建 TS 服务,接入 /ai/generate-reportprompt 调优
  3. 第三阶段:AI 生成标准导图替代 BuiltinMindMapGenerator
  4. 第四阶段:安全层、多模型、沙箱

6.8 修正后优先级

优先级 项目 说明
P0 学习预期闭环 创建 session 时必填 → 结束时对比”预期 vs 实际”
P0 权重配置 UI 五个维度滑块,即时影响排序
P1 滚动条交互增强 点击内容后弹出回忆卡片”你还记得多少?”→ 再展开原文
P1 滚动条智能排序 低频访问 + 低回忆覆盖率内容优先出现(类 spaced repetition
P1 搭建 LPT-AI 服务 TypeScript 独立项目,先做残片聚合报告
P1 回忆对比可视化 嵌入 mind-elixir,节点着色展示 MATCHED/MISSED/EXTRA
P2 内置生成器升级 接入 AI 后替代规则生成
P2 有效时间阈值 维持 10 分钟(经确认合理)
P2 多租户 保留不变

6.9 最终总结(修正版)

系统在基础设施层面(前后端分离、RESTful、Flyway、Sa-Token、MyBatis-Plus)相当规范。原评审中约 50% 的批评基于对设计意图和代码状态机的误解,经用户指正后已修正。

剩余真正有价值的问题:

  1. 学习预期无闭环:P0,需要实施
  2. 权重配置无 UIP0,需要实施
  3. 复习交互可深化:滚动条 + 点击触发回忆,而非纯被动浏览
  4. AI 聚合报告:需要独立服务

修正后的判断:系统设计的大部分决策是有意为之且有合理性的,不是”把功能完整当有用”。 真正的问题不是”不知道现在该做什么”,而是”做了好的设计但没有完全交付”——学习预期和权重配置是写在 PRD 和代码注释里但没有实现的,而非设计缺失。 下一步重点是:交付未完成的功能 + 引入 AI 服务作为独立项目 + 深化复习交互。