数据截至 (上游 commit 96d6df9eb1a3)
掌握式学习引擎(Mastery Path)
这章讲什么: DeepTutor 怎么逼你「真学会」。核心是一段没有 LLM、没有 I/O 的纯函数策略:它算「你掌握没掌握、下一步学什么」,模型只能照办,无权绕过门槛。这是教育产品里最有意思的设计。
1. 它要解决的小问题
普通 LLM 辅导是「你问它答」,你以为懂了就过了——没人拦你。掌握式学习(mastery-based learning)的理念相反:没到掌握线,就不许进阶。难点是怎么把这个「门」做成模型骗不过去的硬规则,而不是模型自己说「你掌握了」就算。
2. 思路 / 直觉:门就是游标
DeepTutor 把判定做成纯函数策略(deeptutor/learning/policy.py 顶部 docstring):
- 进阶不靠 stage 计数器,而是「从已掌握的内容算出来」。
next_objective一直返回同一个目标,直到它清过门为止(policy.py:163)。 - 已经证明掌握的目标直接跳过(「test out」/ 压缩路径)——因为门读的是「已证明的掌握」,不是固定的阶段序列(
policy.py:10-16docstring)。
直觉:门本身就是进度游标。 你没过的那个点会一直挡在你面前;你证明过的点自动让路。
3. 核心机制
3.1 分类型的门:定量 vs 定性
知识点分四种类型(deeptutor/learning/models.py,KnowledgeType:memory / concept / procedure / design),门也分两种:
| 类型 | 门的种类 | 怎么过 |
|---|---|---|
| MEMORY、PROCEDURE | 定量 | 近期加权准确率 ≥ 0.9(QUANTITATIVE_GATE,policy.py:35) |
| CONCEPT、DESIGN | 定性 | 一次费曼式讲解被导师判过(mastery_assess)(QUALITATIVE_TYPES,policy.py:43) |
为什么概念/设计型用定性?因为它们很少有唯一的标准答案可供字符串比对(policy.py:40-42 注释)。0.9 这个数字明说了是对标 Alpha School 的「90% before you advance」(policy.py:32-34 注释)。
判定入口是 is_mastered(policy.py:61):定量看 mastery_levels[kp.id] >= 阈值,定性看 qualitative_mastery[kp.id] 这个布尔。
3.2 掌握评分:近期加权 + 低置信封顶
定量分由 compute_mastery(deeptutor/learning/mastery.py:24)算——这是「教学法数学」唯一住的地方,docstring 明说要换成 IRT/BKT 只改这一个函数即可:
- 近期加权:最近的尝试权重更高(
_RECENCY_WEIGHTS = (0.5, 0.7, 0.85, 0.95, 1.0),mastery.py:17),所以早期错了之后追上来会被奖励。 - 低置信封顶:尝试次数太少时分数封顶——1 次封 0.5、2 次封 0.8(
_CONFIDENCE_CAP,mastery.py:21),所以一两次蒙对不算掌握。
# 示意,非源码:近期加权准确率,且证据不足时封顶
def compute_mastery(correctness): # 按时间顺序的对错列表
if not correctness:
return 0.0
recent = correctness[-5:] # 只看最近 5 次
weights = RECENCY_WEIGHTS[-len(recent):] # 越近权重越大
score = weighted_accuracy(recent, weights)
cap = CONFIDENCE_CAP.get(len(recent), 1.0) # 1次→0.5, 2次→0.8
return min(score, cap) # 蒙对一两次也到不了 0.9
重点看: 封顶让「运气」无法清过 0.9 的定量门——这正是「硬门」硬在哪。
3.3 下一步学什么:优先级决策
next_objective(policy.py:163)按固定优先级决定 NextStep:
- 有待答问题 →
answer_pending(先批改再继续)。 - 有到期复习 →
review(别让掌握过的内容衰退)。 - 第一个未掌握目标(按模块序 → 知识点序)→ 据状态给
probe(没碰过,先让你 test out)/practice(定量未达标)/assess(定性待费曼判定)。 - 否则 →
complete。
NextStep.action 对模型只是建议性的教学动作;绑定事实是「目标 + 掌握没掌握」(policy.py:99-112 docstring)。模型拿到这个结构后据此组织教学,但能不能进阶由策略说了算。
3.4 间隔重复
掌握过的点会进复习队列,按知识点类型用不同的间隔序列(deeptutor/learning/scheduler.py:13,INTERVAL_SEQUENCES):memory [0,1,3,7,14,30,60]、concept [3,7,14,30]、procedure [3,7,14]、design [14,28]——记忆型复习最密、设计型最疏。到期项由 due_reviews(policy.py:90)按优先级捞出来。
4. 它怎么接进 agent 循环
掌握式学习不是另起一套循环——它复用聊天的整个工具面 + 同一个 agent 循环,只是额外挂上 mastery 引擎工具(deeptutor/capabilities/mastery/loop.py,MasteryLoopCapability,docstring 原话:「Reuses the full chat tool surface … and adds the mastery engine tools on top」)。模型每轮通过 mastery_status / mastery_grade / mastery_assess 这些工具(deeptutor/tools/mastery_tool.py)去查策略、提交评分,策略函数返回「下一步」,模型据此辅导——但门挡在策略里,模型绕不过。
5. 巧妙之处
- 策略是纯函数,完全可测、可换。 没有 LLM、没有 I/O(
policy.py:2-3docstring),所以「90% 门」「近期加权」这些教学法决定是确定性的、能单测的,不随模型漂移。 - 门即游标,自带「test out」。 已掌握的点跳过,等于免费支持「我已经会了就别教我」(
policy.py:13-16)。 - 定量/定性分治。 用字符串能判的(记忆/程序)走准确率门;判不了的(概念/设计)走导师定性判定,显示时映射成满分让地图颜色一致(
_QUALITATIVE_PASS_DISPLAY,policy.py:50)。
6. 边界与局限
- 定性门(概念/设计)依赖导师 LLM 的
mastery_assess判定,质量取决于模型;策略本身只记录布尔结果。 - 评分模型当前是简单的近期加权,作者明说这是「intentionally simple and swappable」(
mastery.pydocstring),不是 IRT/BKT 那种统计学习模型。 - 阈值(0.9)、权重、封顶都是硬编码常量,没有按学科/学习者自适应。
7. 代码地图
| 主题 | 文件 | 符号 |
|---|---|---|
| 硬门策略(纯函数) | deeptutor/learning/policy.py | is_mastered、next_objective、QUANTITATIVE_GATE、gate_threshold、NextStep |
| 掌握评分 | deeptutor/learning/mastery.py | compute_mastery、_RECENCY_WEIGHTS、_CONFIDENCE_CAP |
| 间隔重复调度 | deeptutor/learning/scheduler.py | INTERVAL_SEQUENCES |
| 数据模型 | deeptutor/learning/models.py | KnowledgeType、LearningProgress、KnowledgePoint |
| 答案评分 | deeptutor/learning/grading.py | grade_answer |
| 接入 agent 循环 | deeptutor/capabilities/mastery/loop.py | MasteryLoopCapability |
| 掌握工具 | deeptutor/tools/mastery_tool.py | mastery 工具 |