StudyLoop:本地优先的学习系统,以及 AI 失败时的退路
用 IndexedDB、三个学习模块和可替换的 QuestionProvider,把学习计划、每日巩固与间隔复习串成一个闭环。
本文目录
StudyLoop 是一个本地优先的个人学习系统。它没有把“学习”简化成一个番茄钟,而是拆成三个互相连接、但边界清楚的模块:
- 学习计划:接下来学什么,每天做什么。
- 每日巩固:今天学的内容是否真的理解了。
- 复习计划:已学过的内容,之后怎样记牢。
这三个模块共享知识库,但不混用任务。学习任务只记录完成情况;巩固题和复习题才影响掌握度。这个边界是整套设计里最重要的部分。
为什么本地优先
应用默认单用户、免登录。学习任务、笔记、题目、计划和答题记录都保存在浏览器 IndexedDB;关闭页面、重启设备后仍然存在。
联网只用于可选的 AI 出题服务。没有配置 AI 或断网时,系统仍可使用本地模板题与已缓存的题目。复习计划创建时会预生成并缓存基础题目,因此已建立的计划不会因为网络中断而失效。
这带来两个实际问题:
- 导出/导入不是附属功能:浏览器存储可能被清理,数据必须能完整导出。
- AI 不是主存储:模型失败不能把用户输入一起清空。
三个模块如何连接
学习计划(安排新内容)
↓ 完成今日学习任务
每日巩固(记录实际所学并即时出题)
↓ 用户确认纳入长期记忆
复习计划(按目标天数间隔复习)
↓ 暴露薄弱点
每日巩固
流转必须由用户确认。勾选“已学习”不会自动生成大量题目,也不会自动修改复习计划。这个约束看起来保守,但能避免 AI 把一次误操作放大成几十道题。
| 概念 | 所属模块 | 是否影响掌握度 |
|---|---|---|
| 学习任务 | 学习计划 | 否,只记录完成 |
| 当日巩固会话 | 每日巩固 | 是,形成初始掌握度 |
| 长期复习会话 | 复习计划 | 是,更新间隔与下次日期 |
| 笔记与知识点 | 共享知识库 | 被答题记录间接更新 |
AI 的边界
后端是一个本地 Fastify 代理,读取 .env.local 里的 DeepSeek 配置。API Key 不会进入前端代码或 IndexedDB;日志和导出文件也不应包含密钥。
出题层用统一的 QuestionProvider 接口隔离:
- 本地模板提供器:无需联网,从定义句、列表、步骤、对比和代码块生成基础题。
- DeepSeek 提供器:负责知识点提取、题型选择、干扰项和解析。
- 未来本地模型:可以接 WebLLM,但不进入 MVP。
DeepSeek 返回 JSON,经过 Zod schema 二次校验。空内容、截断或校验失败时只重试一次;仍失败就切到本地模板,并明确告诉用户。这里的原则是:AI 可以失败,但学习流程不能卡死。
复习计划不是“每天随机出题”
复习计划创建时,用户先确认知识点,再选择 3–60 天的目标、开始日期和轻量/标准/强化三档强度。系统预生成阶段日程和基础题目,首次打开当天时恢复“今日到期复习”,不需要网页一直运行。
答题后更新掌握度和下次复习日期;错题会在后续日期重新出现。主观题先展示参考答案,再由用户选择“不会 / 模糊 / 掌握 / 轻松”。
这也解释了为什么不能把学习任务和复习任务合成一个“待办数字”:学习任务是新内容,复习任务是旧内容,它们的逾期处理方式不同。
值得复用的设计
- 数据先于 AI:用户输入、计划、答题记录都在本地;AI 只是可替换的题目来源。
- Provider 隔离:本地规则和云端模型实现同一个接口,失败可切换。
- Schema 二次校验:模型输出不是“看起来像 JSON”就直接用。
- 用户确认边界:模块之间不自动流转,避免错误扩散。
- 可解释的复习:用户能看到“为什么今天复习这些内容”,而不是只看到一个日期。
小结
StudyLoop 的工程价值不在“接了 DeepSeek”,而在于它把 AI 放在一个可失败、可替换、可审计的位置。对个人学习工具来说,这比多一个模型名称重要得多。
项目仍在迭代;上面的模块边界和数据流来自公开的 README 与设计文档,具体实现以仓库为准。
讨论
评论由 GitHub Discussions 提供,点击后加载。未加载前不会产生第三方请求。