艾宾浩斯复习工具
2026/9/2 21:02:00 网站建设 项目流程

艾宾浩斯复习工具 Recall

写在前面

你有没有过这种经历:背了一上午的英语单词,第二天醒来全忘了?或者学了一个技术点,过两周再看跟第一次见一样?

这不是你记忆力差,是人脑的遗忘曲线决定的。德国心理学家艾宾浩斯早在 1885 年就通过实验发现:人类对无意义音节的记忆保持率在学习后 20 分钟、1 小时、1 天、6 天分别约为 58%、44%、33%、25%。

那有没有办法对抗遗忘?有——间隔重复(Spaced Repetition)。简单说就是"在你快要忘掉的时候刚好复习一下",每次复习之后间隔可以拉长,直到真正进入长期记忆。

市面上已经有 Anki、Quizlet 这类产品,但 Anki 配置太折腾、UI 不够友好,Quizlet 在线使用体验好但离线要翻墙。我想要一个轻量、好看、纯本地、数据完全自己掌控的复习工具——所以就搞了个Recall

GitHub 项目地址 👉 https://github.com/suger-cheng/memory-tool


一、先看成品长什么样

📊 今日概览

打开应用第一眼就能看到今天要复习多少张、留存率、总卡片数、连续打卡天数、XP 和等级进度。

🗂 卡片管理

三种卡片类型:记忆卡片、知识点笔记、语录收藏。支持按卡组分类,嵌套卡组也没问题。

📚 卡组管理

卡组树结构,默认卡组 + 自建卡组,每日新卡数和复习上限独立配置。

⚙️ 设置页

主题切换、每日限额、托盘提醒、JSON 导入导出、数据库备份、自定义数据目录(改完自动迁移)。

二、核心算法:9 阶段间隔 + 三级反馈 + 长期记忆毕业

2.1 艾宾浩斯遗忘曲线

艾宾浩斯的实验公式是R(t) = e^(-t/S),其中 R 是记忆保持率,t 是经过的时间,S 是记忆强度(和复习次数正相关)。我们的目标是在 R 降到某个阈值之前恰好复习一次,把 S 拉高,下次间隔可以更长。

2.2 九阶段间隔表

我把复习间隔设计成 9 个递进阶段,从第一次复习的 5 分钟到第 9 次的 30 天:

阶段123456789
基础间隔5 分钟30 分钟12 小时1 天2 天4 天7 天15 天30 天

但这不是死板的——每张卡还有一个ease(难度因子,1.3~3.0),实际间隔 =基础间隔 × (ease / 2.5)。容易的卡(ease 大)间隔自动拉长,难的卡(ease 小)间隔自动压缩。

2.3 三级反馈机制

每次复习完一张卡,用户只需要点三个按钮之一:

反馈quality阶段变化ease 变化熟练度变化获得 XP
🟢 记住了2+1(最高到第 9 阶段)+0.08+100/9 × (ease/2.5)+10
🟡 模糊1-1(最低到 0)-0.05-5+4
🔴 忘了0重置为 0-0.3×0.4+1

"忘了"惩罚最重:阶段清零 + ease 大减 0.3 + 熟练度砍到 40%——但还是能拿到 1 XP,哪怕只是打开应用标记"忘了"也是好的,鼓励用户保持习惯。

2.4 熟练度与毕业系统

熟练度范围 0~100,达到 100 时卡片毕业,从普通复习流程进入长期记忆池

  • 长期记忆卡片使用 60 天基础间隔,按 ease 增长,上限 180 天

  • 长期记忆卡片若再被标"忘了",退回普通流程,熟练度降至当前值的 40%

毕业就像通关——你不会再被一张已经记住的卡反复打扰。

2.5 复习队列优先级

一天到期的卡可能有几十上百张,按什么顺序复习?我的设计:

逾期普通卡 > 今日到期 > 即将到期 > 逾期长期卡

同优先级内:逾期天数降序 → ease 升序 → 熟练度升序

简单说就是越该复习的卡越靠前,让每张卡都在"最佳遗忘临界点"被复习。

2.6 核心算法代码

算法集中在review_engine.py,核心就一个函数:

defapply_feedback(card:dict,feedback:str)->dict:"""根据用户反馈更新卡片的阶段、ease、熟练度。"""q={"forgot":0,"fuzzy":1,"remembered":2}[feedback]# 三级反馈更新逻辑ifq==2:# 记住了card["stage"]=min(card["stage"]+1,9)card["ease"]=min(card["ease"]+0.08,3.0)card["mastery"]+=100/9*(card["ease"]/2.5)elifq==1:# 模糊card["stage"]=max(card["stage"]-1,0)card["ease"]=max(card["ease"]-0.05,1.3)card["mastery"]=max(card["mastery"]-5,0)else:# 忘了card["stage"]=0card["ease"]=max(card["ease"]-0.3,1.3)card["mastery"]*=0.4# 熟练度达标 → 毕业ifcard["mastery"]>=100andnotcard["is_long_term"]:card["is_long_term"]=1returncard

三、技术栈 & 架构设计

3.1 为什么选 PySide6?

框架优点缺点
PySide6(我选的)Qt 官方 Python 绑定、文档全、跨平台、QSS 样式能力强、社区成熟打包体积大(但 PyInstaller 可解决)
Tkinter自带、轻量样式丑、功能弱、图表支持差
PyQt5/6功能和 PySide6 类似GPL/商业双授权,商用要花钱
Electron/CEFUI 最好看体积大(动辄 100MB+)、内存占用高

PySide6 是目前 Python 桌面 GUI 的性价比之王——免费(LGPL 协议)、跨平台、样式系统灵活、图表渲染可以接 pyqtgraph。

3.2 整体架构

┌──────────────────────────────────────────────┐ │ PySide6 界面层 │ │ dashboard_view / review_view / card_manager │ │ deck_manager / stats_view / settings_view │ └──────────────────┬───────────────────────────┘ │ 调用 ┌──────────────────▼───────────────────────────┐ │ 业务逻辑层 │ │ review_engine.py 复习调度算法 │ │ gamification.py XP/等级/成就 │ │ scheduler.py 定时提醒 │ └──────────────────┬───────────────────────────┘ │ 读写 ┌──────────────────▼───────────────────────────┐ │ SQLite 数据层 │ │ database.py 连接管理 + 路径解析 │ │ utils/import_export.py JSON 导入导出 │ └──────────────────────────────────────────────┘

3.3 数据模型

全部 7 张表,职责清晰:

职责
cards卡片数据 + 复习调度状态(stage/ease/mastery/is_long_term)
decks卡组(支持嵌套,parent_id 自关联)
review_log每次复习的完整记录(含前后状态快照 + 反应时间)
daily_stats按天聚合的统计
settings键值对配置
user_progressXP 与等级
achievements成就定义与解锁状态

用 SQLite WAL 模式 + 单连接复用,性能和稳定性都够用。

3.4 数据路径的坑

这里有个我花了点心思的设计:数据目录可配置 + 自动迁移

问题:如果把路径硬编码成E:\data\xxx,别人 Windows 机器上 E 盘不存在就崩了。但如果放在安装目录,升级/卸载会丢数据。

方案

  1. 默认路径跨平台:Windows 用%APPDATA%、macOS 用~/Library/Application Support、Linux 用$XDG_DATA_HOME
  2. 引导配置独立:在~/.recall_config.jsondata_dir——放在用户 home 而不是 data_dir 里,否则改了 data_dir 后下次启动找不到自己在哪
  3. 一键迁移:设置里选新目录 → 自动关闭连接 → 迁recall.db+-wal+-shm→ 写引导配置。还做了目标目录可写校验、已存在数据库拒绝覆盖、迁移中途失败自动回滚
  4. 便携版支持:设环境变量RECALL_BOOT_CONFIG=./boot.json就能把引导配置也挪走,整个 Recall 可以跟着 U 盘走
# database.py —— 路径解析核心逻辑def_get_data_dir()->str:"""默认路径按系统选择。"""ifsys.platform=="win32":base=os.environ.get("APPDATA")oros.path.expanduser("~")elifsys.platform=="darwin":base=os.path.expanduser("~/Library/Application Support")else:base=os.environ.get("XDG_DATA_HOME")oros.path.expanduser("~/.local/share")returnos.path.join(base,"Recall")def_resolve_data_dir()->str:"""优先级:引导配置 > 系统默认。"""cfg=_load_boot_config()# 读 ~/.recall_config.jsoncustom=(cfg.get("data_dir")or"").strip()ifcustomandos.path.isabs(custom):returncustomreturn_default_data_dir()

四、游戏化:让坚持下去变得容易

纯工具很难坚持,加了一点游戏化元素:

  • XP 与等级:每次复习拿 XP(记住 +10、模糊 +4、忘了 +1),升级公式100 × (n-1) × n / 2

  • 8 种成就徽章:初次复习、勤奋学习者(10/100 张)、连续打卡(3/7 天)、完美一轮、长期记忆、小有所成(Lv.5)

  • 连续打卡天数:断一天就清零——但这也是动力

XP 系统其实是个副产品:算法本身已经很科学了,但加了数字反馈之后,用户会更愿意打开应用——这对坚持来说比算法精度更重要。


五、快速上手

方式一:源码运行

# 克隆仓库gitclone https://github.com/suger-cheng/memory-tool.gitcdmemory-tool# 安装依赖pipinstall-rrequirements.txt# 运行python main.py

方式二:打包 exe 分发

pipinstallpyinstaller# 单目录模式(推荐,启动快)pyinstaller--onedir--windowed--nameRecall main.py# 产物:dist/Recall/Recall.exe

分发时把dist/Recall/整个文件夹压缩给对方即可。对方双击就能用,数据目录自动按系统选择,无需配置。

依赖清单

PySide6 >= 6.5.0 pyqtgraph >= 0.13.0

Python 3.10+ 即可。


也可以直接安装exe文件,无需安装各种依赖,直接运行。

有任何问题或建议,欢迎在 GitHub 提 Issue / PR,也可以在评论区交流。


🔗项目地址:https://github.com/suger-cheng/memory-tool

⭐ 如果觉得有用,记得给项目点个 Star~


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询