DeepTutor v1.4.5 技术解析:基于可扩展 Chat Loop 重构的引导式学习与对话循环插件框架
本文档围绕仓库内 v1.4.5 版本发布说明(Release Date:2026.06.14)展开。该版本聚焦两件大事:把「引导式学习(Guided Learning)」从自研的固定阶段状态机整体重建到统一的 Chat Agent Loop 之上,并为此引入一套让对话循环可扩展的 loop-plugin 框架。学习 DeepTutor 如何在"同一套聊天循环上长出不同学习模式"是理解后续各版本能力插件(solve / obsidian / subagent / explore-context 等)的钥匙;读完本文你可以掌握其能力挂载机制、掌握度门控与判分、间隔复习的底层实现,以及本版本的升级与迁移要点。
一、版本定位:聚焦发布,原位替换,无需迁移
v1.4.5 是在 v1.4.4 之上的一个聚焦发布,官方发布说明给出的核心定位是:
A focused release on top of v1.4.4:Guided Learning is rebuilt on the same chat agent loop that powers everything else, on top of a new loop-plugin framework that makes the chat loop extensible.
翻译成项目事实即四个要点:
- 引导式学习改由对话驱动——学习路径不再走"诊断 → 讲解 → 测验 → Feynman"的专用阶段机,而是变成一场一对一的导师对话,由**硬性掌握度门控(hard mastery gate)**决定何时才能推进到下一个目标。
- 引入 loop-plugin 框架——让某个特性可以向一轮对话贡献自己的工具、系统提示词块与服务端注入的工具参数,而聊天流水线本身无需为其硬编码。
- 合作伙伴(Partner)会话能力补齐——Partner Chat 与 Archive 对话支持导出 Markdown 并保存到笔记本。
- 对话结束提速——每一轮对话在答案保存的瞬间即发出
done信号。
发布说明还特别强调兼容性承诺:旧学习进度原样加载,零迁移、零配置改动;唯一的运维变化是 Windows 启动脚本位置调整(详见本文末尾的升级说明)。仓库内后续版本(如 ver1-5-8 发布说明)沿用了同样的"drop-in、no migrations"发布口径,说明 v1.4.5 确立的这套结构与存储模型是稳定的演进基线。
二、核心重构一:引导式学习如何被重建到 Chat Loop 上
2.1 从"固定阶段机"到"门控驱动的导师对话"
v1.4.5 之前,引导式学习是一台自定义的状态机,把学习者按固定的 diagnostic → explain → quiz → Feynman 阶段推着走。这台"bespoke stage machine"已被彻底移除。取而代之的是:一条掌握路径(mastery path)就是一节一对一的导师聊天,聊天代理(tutor agent)每一轮都查询一个每类型独立的硬掌握门控,目标未达标就不放行、不推进。
当前仓库中,这套"门控即游标(the gate IS the cursor)"的决策逻辑被收敛在 deeptutor/learning/policy.py 中。该模块的模块级注释写得很直白:
The gate is the heart of mastery-based learning. An objective only counts as mastered when the evidence clears its threshold, and
next_objectivekeeps returning the same objective until it does — advancement is computed from what is mastered, never tracked by a stage counter.
也就是说,推进的依据是"哪些目标已被证明掌握",而不是一个阶段计数器。next_objective() 的裁决优先级为:
- 有待回答的已出题(先判分再继续);
- 到期的间隔复习任务(不让学生已掌握的知识衰减);
- 按模块、知识点顺序找到的第一个未掌握目标(已掌握目标自动跳过,即"测试通过直接压缩跳过"的通道);
- 全部完成则返回
complete。
2.2 分类型的门控:MEMORY/PROCEDURE 量化,CONCEPT/DESIGN 质化
发布说明把学习目标明确分成两类处理方式,源码里则对应 deeptutor/learning/policy.py 中的两类门控常量:
# Quantitative gate: the learner must reach this mastery before the objective unlocks.
QUANTITATIVE_GATE: dict[KnowledgeType, float] = {
KnowledgeType.MEMORY: 0.9,
KnowledgeType.PROCEDURE: 0.9,
}
QUALITATIVE_TYPES: frozenset[KnowledgeType] = frozenset(
{KnowledgeType.CONCEPT, KnowledgeType.DESIGN}
)
- MEMORY(记忆) / PROCEDURE(程序性技能):走量化门控。在交互卡片上被提问,由服务端确定性判分——预期答案(expected answer)随题目一起存进引擎(
PendingQuestion),绝不经过模型往返。掌握度达到阈值 0.9(注释注明这是对标 Alpha School "90% 才放行"的做法)后解锁;答对的题再进入**间隔复习(spaced repetition)**调度。 - CONCEPT(概念理解) / DESIGN(开放性设计判断):走质化门控。因为这类问题通常没有唯一标准答案可做字符串比对,所以改为费曼式自述——学习者用自己的话把想法讲清楚,由导师(tutor)依据
mastery_assess工具记录通过与否。
2.3 判分是确定性的、fail-closed 的
"预期答案永不经过模型"这一设计在代码里的落点是 deeptutor/learning/service.py 的 grade_and_record()。它是"学生作答之后发生什么"的唯一事实来源,被所有交互阶段共享。其 docstring 强调:
Grading is fail-closed: with no stored expected answer the attempt is recorded wrong, never right.
调用链为:记录作答 → 重算掌握度 → 推进间隔复习状态 → 重建复习队列 → 持久化。真正的字符串判分在 deeptutor/learning/grading.py 的 grade_answer() 中,按题型分流:
| question_type | 判分规则 |
|---|---|
choice |
去空格后精确相等 |
short |
精确相等;若期望答案 ≤ 30 字符,则用 difflib.SequenceMatcher 的相似度 ≥ 0.85 判定(≤30 字符以上一律不给模糊放行) |
open |
把期望答案按 [,;,;。\n] 切分成关键词,命中率 ≥ 60% 判对 |
答错时,grading.py 的 classify_error() 先做粗分类——空白作答判为"元认知缺失"(metacognitive),非空白一律视为"应用错误"(application error);更细的四分类错误类型(ErrorType)由后续 LLM 错误诊断阶段再分配,这一粗分类保证引擎层不依赖模型即可先行记账。
错误记录会进入 service.py 的 error_records,并抬高对应知识点在复习队列中的优先级——见 deeptutor/learning/scheduler.py 的 build_review_queue():处于 active/retrying 状态的错误知识点,其复习任务优先级固定为 1(最高),其余按类型取 MEMORY=2, CONCEPT=3, PROCEDURE=4, DESIGN=5。
2.4 间隔复习:按知识类型定制间隔序列
判分之后的"调度到间隔复习"由 deeptutor/learning/scheduler.py 完成。核心是 SpacedRepetitionScheduler,四种知识类型各有不同的复习间隔序列(单位为天):
INTERVAL_SEQUENCES: dict[KnowledgeType, list[int]] = {
KnowledgeType.MEMORY: [0, 1, 3, 7, 14, 30, 60],
KnowledgeType.CONCEPT: [3, 7, 14, 30],
KnowledgeType.PROCEDURE:[3, 7, 14],
KnowledgeType.DESIGN: [14, 28],
}
schedule_next() 的状态机规则:答对一次 interval_index 前进 1 档,连续答对 2 次前进 2 档;答错则回退 1 档,且连续答错 2 次会重置连续计数。索引被夹在 [0, len-1]。另外该调度器支持 LEARNING_DEBUG=1 环境变量把间隔单位从"天"变成"秒",便于测试快速推进时间线——这也是 tests 中大量针对调度器行为的验证依赖的机制。配套掌握度数值计算(近因加权准确率,recency-weighted accuracy)位于 deeptutor/learning/mastery.py,可通过 deeptutor/learning/service.py 的 calculate_mastery() 观测其输入——它取该知识点全部历史作答的正确/错误序列计算 0..1 的掌握度。
2.5 /learning 页面从"流程页"变成"仪表盘"
发布说明指出 /learning 页面不再承载固定阶段流程,而是变成学习仪表盘:上半部分是由门控决定的下一个步骤(gate-decided next step),下半部分是每个目标的实时状态地图,状态取三态:new(未开始) / learning(学习中) / mastered(已掌握)。
三态判定本身是纯函数,位于 deeptutor/learning/policy.py 的 objective_status():已过门控为 mastered;有作答历史(或有质化记录)为 learning;否则为 new。而 map_summary() 输出的 counts 与逐模块 knowledge_points 快照,正是"导师每轮读取状态图"和"仪表盘渲染"共用的同一份数据。它通过 deeptutor/capabilities/mastery/tools.py 中的 mastery_status 工具暴露给模型,同时被 REST 侧 deeptutor/api/routers/mastery_path.py 驱动页面。
2.6 五位一体:对话导师背后的五个 mastery 工具
从源码结构看,导师聊天能操作掌握路径,靠的是 deeptutor/capabilities/mastery/tools.py 中定义、仅在掌握路径激活当轮才自动挂载的五个工具(MASTERY_TOOL_NAMES):
| 工具 | 职责 | 关键参数 |
|---|---|---|
mastery_status |
每轮第一个调用:返回下一个目标、待答问题、到期复习与全图状态 | 无参 |
mastery_build |
由导师按学习材料设计模块与知识点(memory/procedure/concept/design),以 replace/append 模式建/扩路径 |
modules[]、mode |
mastery_quiz |
为 MEMORY/PROCEDURE 目标登记题目,把预期答案注册进引擎(服务端判分专用) | knowledge_point_id、question、expected_answer、question_type、options[] |
mastery_grade |
对登记过的题目做确定性判分,更新掌握度、推进间隔复习并回报门控是否清除 | answer |
mastery_assess |
记录 CONCEPT/DESIGN 目标的费曼式讲解是否通过(passed) |
knowledge_point_id、passed、feedback |
工具注释里有一个值得注意的分工哲学(tools.py 头部 docstring):
The chat agent loop IS the tutor; these tools let it read the gate and record outcomes, while the pedagogy — what to teach, how to question, when to explain — stays the model's job. The arithmetic (mastery, gate, spaced repetition) stays in the engine.
也就是说:"教什么、怎么问、何时讲"是模型(导师)的职责;"掌握度计算、门控判定、间隔复习"是引擎的职责。模型的自由度被硬门控约束,引擎的数字不被模型的表达所污染。此外,mastery_build 解析模块时知识点 ID 一律由服务端生成(格式 {path}_m{i}_kp{j}),模型永远不持有存储键的控制权;未知的知识类型会安全回退为 concept。
三、核心重构二:可扩展的对话循环(Loop-Plugin 框架)
3.1 一个特性如何"插"进一轮对话
v1.4.5 发布说明宣告了新的 loop-plugin 框架,最初的落点目录为 deeptutor/loop_plugins/。在当前仓库中,这套"循环能力"的抽象已经演进为 deeptutor/capabilities/ 包下的 loop capability 体系,但其能力模型与 v1.4.5 描述完全一致——一个特性要向一轮对话贡献三样东西,而无须改动聊天流水线的核心代码:
- 工具(tools):该特性私有、随特性激活才挂载的工具;
- 系统提示词块(system-prompt block):仅在特性激活时插入的系统指令片段;
- 服务端持有的工具参数(server-owned tool arguments):模型无法伪造、由流水线注入的关键上下文。
以引导式学习为例,其插件实现是 deeptutor/capabilities/mastery/loop.py 的 MasteryLoopCapability,它实现了标准协议(该协议定义在 deeptutor/capabilities/protocol.py,如 PromptBlock):
name = "mastery",owned_tools = MASTERY_TOOL_NAMES;is_active(context):检查context.metadata["mastery_mode"]是否为真,决定本轮回合是否进入导师模式;system_block(...):激活时返回PromptBlock("mastery_tutor", content),内容优先取配置prompts["mastery"]["system"]的覆盖值,否则读取打包在包内的 英文系统提示 或 中文系统提示(按会话语言选择);augment_kwargs(...):当模型调用其私有工具时,服务端自动注入_mastery_path_id、_session_id、_turn_id三个参数——路径 ID、会话与轮次 ID 全部取自服务端上下文,模型永远无法自行指定。这正是 tools.py 中_resolve_path_id()等函数读取参数的来源,也是"并发回合不会在共享对象上竞争"的隔离基础:每次调用都新建独立的 store + service(与 REST 路由保持一致)。
3.2 内置能力注册表:Guided Learning 只是第一个插件
v1.4.5 让引导式学习成为该框架的第一个插件;当前仓库的内置注册表 deeptutor/capabilities/registry.py 已经登记了五个循环能力,按稳定顺序为:
LOOP_CAPABILITIES: tuple[LoopCapability, ...] = (
MasteryLoopCapability(), # 引导式学习导师模式(v1.4.5 首个插件)
SolveLoopCapability(), # 解题模式
ObsidianCapability(),
SubagentCapability(),
ExploreContextCapability(),
)
active_loop_capabilities(context) 按"每个能力是否 is_active"过滤出当轮激活的能力集合;any_exclusive_capability_active() 用于驱动流水线的"独占工具分支"(当某能力完全替换工具面板时,会抑制 rag 脚手架)。这种注册表式设计让后续新增"模式"只需实现协议并登记,验证了发布说明中"这是未来各种模式接入的接缝"(the seam future modes plug into)的判断。运行时层面,能力与工具注册还可以参考 deeptutor/runtime/registry/capability_registry.py 与 [deeptutor/runtime/registry/tool_registry.py),它们把能力/工具的挂载策略与内置注册集中管理。
3.3 上下文检查点折叠(Context-Checkpoint Folding)
loop 框架的另一个隐性但重要的能力是上下文检查点折叠:在对话中途,某个工具可以把一段很长的"工作上下文"折叠回"检查点 + 摘要",避免无限增长的工作区撑爆上下文窗口。发布说明称其为"日常不可见、却是未来模式插入的接缝"。
该机制在 deeptutor/agents/chat/agent_loop.py 中实现:折叠基于 checkpoint_boundary 划分历史消息,_fold_context_checkpoint()(约在 342–373 行)在检查到工具结果携带 _context_checkpoint 摘要元数据时,将边界前缀替换为形如 [Context checkpoint]\n{summary} 的折叠块。实际消费者之一是解题能力: deeptutor/capabilities/solve/tools.py 在完成一个解题步骤后,通过 extra_meta={"_context_checkpoint": {"summary": ...}} 把该步骤结论落成摘要,让长流程的多轮解题既能跨轮保留状态,又不至于让上下文无限膨胀。
四、能力补齐:Partner 会话的导出与保存到笔记本
发布说明的第三个要点是:Partner 的 Chat 与 Archive 会话,现在都可以导出为 Markdown并保存到笔记本——这与产品端 Chat 早已具备的控件一致,且这次统一由**同一个共享序列化器(one shared serializer)**支撑。这消除了产品对话与合作伙伴会话之间的能力不对称:无论你是在 DeepTutor 主聊天里,还是在 Matrix / WeChat 等 Partner 渠道的对话与归档中,得到的都是同一条导出链路、同一份序列化规则。
该功能的相关实现与测试可分别在仓库的 deeptutor/partners/ 模块以及 deeptutor/co_writer/、deeptutor/api/routers/ 中继续追踪(例如渠道模式定义位于 deeptutor/partners/channels/base.py 与 deeptutor/partners/channels/registry.py)。从仓库结构可以推断,"保存到笔记本"复用了会话侧的笔记本条目存储机制——deeptutor/services/session 提供的会话存储中包含了 upsert_notebook_entries 这类笔记本条目写入接口(引导式学习的题目也会同步进会话的问题库,见 mastery tools 中的 _sync_mastery_attempt_to_question_bank)。
五、体验优化:每轮对话"更快结束"
v1.4.5 对回合收尾做了流水线级优化:每一轮对话都在"答案被保存"的瞬间发出 done 信号。其收益分两头:
- 输入框(composer)立即解锁,用户不用等后续的收尾步骤;
- 回合时长计时立刻停止,统计更贴近真实等待;
- 自动生成的会话标题延后一拍再产生,不再把回合保持打开、拖延整个
done。
也就是说,标题生成这类"锦上添花"的工作从关键路径上被挪走了。这个改动与 v1.4.5 的整体叙事一致:让用户在"该轮对话内容已完成"的时刻立刻拿到控制权。该行为在对话流水线的回合状态上报(streaming / turn 事件)链路中体现,相关实现可参考 deeptutor/core/stream.py 与 deeptutor/agents/chat/ 下的回合驱动代码。
六、升级说明
6.1 版本升级
- 从 v1.4.4 无缝升级:
pip install -U deeptutor; - Docker 用户:拉取
ghcr.io/hkuds/deeptutor:latest; - 无需任何数据迁移:旧的引导式学习进度以原样加载(从代码看,进度数据由 deeptutor/learning/storage.py 的
LearningStore按book_id持久化,旧字段在新读取路径中天然兼容,因此"现有学习进度原样加载、无需操作")。
6.2 引导式学习的行为变化
发布说明用粗体醒目地提示了行为差异:
Guided Learning works differently now, but your progress carries over.
- 旧的固定阶段流程 → 换成带硬掌握门控的导师聊天;
- 已有学习进度原样载入,无需迁移、无需任何手动操作。
需要说明的限制:这一变化意味着旧版本中"按固定阶段走完即完成"的体验已不存在;取而代之的是每个目标必须独立通过其类型对应的门控(MEMORY/PROCEDURE 达到 0.9 量化线,CONCEPT/DESIGN 通过费曼讲解质化评估)才会被视为掌握并继续推进。
6.3 Windows 启动脚本的新位置
唯一面向运维的改动是 Windows 启动脚本的存放位置:移入仓库根目录的 scripts/ 之下,请在终端中执行:
scripts\start_backend.bat
scripts\start_frontend.bat
对应脚本本体可在仓库的 scripts/start_backend.bat 与 scripts/start_frontend.bat 中直接查看。
七、源码脉络速查
| 关注点 | 建议阅读的仓库文件 |
|---|---|
| v1.4.5 版本说明原文 | assets/releases/past_releases/ver1-4-5.md |
| 门控与"下一目标"决策 | deeptutor/learning/policy.py |
| 确定性判分与错误粗分类 | deeptutor/learning/grading.py |
| 作答后的完整流水线与状态记账 | deeptutor/learning/service.py |
| 间隔复习调度器 | deeptutor/learning/scheduler.py |
| 掌握度数值计算 | deeptutor/learning/mastery.py |
| 导师聊天的五个 mastery 工具 | deeptutor/capabilities/mastery/tools.py |
| 循环能力插件的标准实现 | deeptutor/capabilities/mastery/loop.py、deeptutor/capabilities/registry.py |
| 上下文检查点折叠 | deeptutor/agents/chat/agent_loop.py |
八、小结
v1.4.5 对 DeepTutor 的意义不只是"改版了引导式学习",而是确立了一套能力插件协议 + 硬门控引擎的分层架构:聊天循环负责对话与工具分发,学习引擎负责纯算术(掌握度、门控、间隔复习),而模型只负责"教与问"的教学决策。这种"循环可插拔、数学不外流、判分不靠模型"的设计,让后续的 solve、obsidian、subagent 等模式能够沿着同一条接缝生长。理解了这个版本,就等于读懂了 DeepTutor 当前能力体系得以持续扩展的地基。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0632
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00