DeepTutor — 架构与原理
30 秒导读: DeepTutor 是香港大学数据智能实验室(HKUDS)做的「agent-native 个性化辅导」开源项目。它把聊天、解题、出题、深度研究、掌握式学习这些能力,全部建在同一个「标签驱动的 agent 循环」上——模型每一步先报一个标签(
THINK/TOOL/FINISH…),循环据此决定继续推理、调工具还是收尾。再配上三层记忆、可插拔的多引擎 RAG、和一个「不到 90% 不放你过」的硬掌握门,组成一个能边学边记、会用工具、还逼你真学会的 AI 老师。
1. 这是什么(零基础也能懂)
-
一句话定义: 一个开源的、跑在你自己机器/服务器上的 AI 学习伴侣——既能像 ChatGPT 那样聊天答疑,也能围着你的资料库做检索问答、带你做「掌握式」闯关学习、甚至连进 IM(飞书/Discord 等)当一个有记忆的导师 bot。
-
解决什么问题 / 给谁用: 给想用 LLM 认真学东西的人。
假设你在准备一门课:你把讲义、论文丢进它的知识库,问它问题时它会先去检索你的资料再回答(而不是瞎编);你想系统掌握一个章节,它会把章节拆成知识点,一个点一个点考你,你没到掌握线它就不让你往下走;你和它聊过的偏好、画像,它会沉淀成「记忆」,下次自动带上。
-
它能做什么(功能):
- 聊天问答(默认能力):带工具的多轮对话,能边聊边检索、执行代码、读笔记。
- 深度能力:Deep Solve( 分步解题)、Deep Question(出题)、Deep Research(多步研究报告)、Visualize / Math Animator(画图、Manim 动画)。
- 掌握式学习(Mastery Path):把材料拆成知识点闯关,带硬门和间隔重复复习。
- 三层记忆:自动从对话里抽取并整理出你的长期画像。
- 知识库 / RAG:四套检索引擎(LlamaIndex / GraphRAG / PageIndex / LightRAG)任选。
- Partners:把上面这套接到即时通讯渠道,变成有人设、有私有记忆的导师 bot。
-
用起来什么样: 它有一个 Typer 写的 CLI(也有 Next.js 网页端和 WebSocket API),最直观的入口是命令行:
# 跑默认的聊天能力
deeptutor run chat "用直觉解释一下傅里叶变换"
# 跑深度解题,挂上 rag 工具、指定知识库
deeptutor run deep_solve "解 x^2=4" -t rag --kb my-kb
# 进交互式 REPL
deeptutor chat
CLI、网页、SDK 三个入口最终都汇到同一个 ChatOrchestrator,由它把请求路由到某个「能力」去执行(deeptutor/runtime/orchestrator.py:36,ChatOrchestrator.handle)。
- 一句话直觉 / 类比: 把它想成一台「带标签纸条的传送带」。模型每说一段话,先在纸条上写个标签——
THINK(我在想)、TOOL(我要用工具)、FINISH(我说完了)。传送带(agent 循环)只认纸条:看到TOOL就去执行工具再传回来,看到FINISH就停。所有能力共用这一条传送带,只是各自带不同的标签纸和工具箱。
2. 顶层全景(它大概怎么转)
DeepTutor 的代码组织成一个两层插件模型(出自 AGENTS.md):
- Level 1 — Tools(工具):模型按需挑选的单功能工具(检索、搜网、执行代码、读写记忆/笔记…),由
ToolRegistry管理。 - Level 2 — Capabilities(能力):接管一整个回合的多阶段流水线(chat / deep_solve / mastery_path …),由
CapabilityRegistry管理。
三个入口(CLI / WebSocket / SDK)都把请求打包成一个 UnifiedContext,交给 ChatOrchestrator 路由到对应能力;能力运行时把所有进度事件发到一条共享的 StreamBus 上,编排器再把事件扇出给消费者。
怎么读下面这张图: 从上往下是「一个用户回合」的数据流;左边是控制路由,右边的两个 Registry 是能力/工具的查找表。
CLI (Typer) WebSocket /api/v1/ws Python SDK
│ │ │
└──────────┬─────────┴──────────┬───────────┘
▼ ▼
打包成 UnifiedContext (会话/用户/附件/激活能力)
│
▼
┌──────────────────────────────┐ 查
│ ChatOrchestrator │────────────► CapabilityRegistry
│ 按 active_capability 路由 │ (chat / solve / mastery…)
│ 默认 → chat 能力 │────────────► ToolRegistry
└───────────────┬──────────────┘ 查 (rag / exec / memory…)
│ 运行选中的能力
▼
┌──────────────────────────────────┐
│ 能力跑在「标签驱动 agent 循环」上 │ ← 全项目的真·核心
│ 每步: LLM 调用 → 看标签 → 调工具/收尾 │
└─ ──────────────┬──────────────────┘
│ 所有进度都发到
▼
StreamBus(统一事件流:thinking / tool_call / content / sources …)
│ 编排器扇出
▼
消费者(终端渲染 / 网页 WS / SDK 迭代器)
部件一句话职责:
| 部件 | 干什么 | 在哪个文件(符号) |
|---|---|---|
UnifiedContext | 一个回合的全部输入:会话 id、用户、消息、附件、激活的能力、元数据 | deeptutor/core/context.py(UnifiedContext) |
ChatOrchestrator | 按 active_capability 把回合路由到某个能力,管理 StreamBus 生命周期 | deeptutor/runtime/orchestrator.py:36(handle) |
CapabilityRegistry | 能力查找表(Level 2 多阶段流水线) | deeptutor/capabilities/registry.py |
ToolRegistry | 工具查找表 + OpenAI schema 生成 + 并行执行 | deeptutor/runtime/registry/tool_registry.py(ToolRegistry) |
| agent 循环 | 标签驱动的迭代调度器,所有能力共用 | deeptutor/core/agentic/loop.py:180(run_agentic_loop) |
run_labeled_step | 一次流式 LLM 调用 + 标签解析 + 把推理/正文分流到不同事件 | deeptutor/core/agentic/labeled_step.py:197(run_labeled_step) |
StreamBus | 统一的流式事件总线(thinking/content/tool_call/sources…) | deeptutor/core/stream_bus.py(StreamBus) |
MemoryStore | 三层记忆的统一门面(L1 事件 / L2 表面 / L3 长期) | deeptutor/services/memory/store.py:47(MemoryStore) |
RAGService | 把检索路由到某个知识库绑定的引擎 | deeptutor/services/rag/service.py(RAGService) |
| 掌握式策略 | 纯函数的「下一步学什么 / 掌握没有」判定 | deeptutor/learning/policy.py:158(next_objective) |
SandboxService | 沙箱化 shell/代码执行,三档隔离 | deeptutor/services/sandbox/service.py(SandboxService) |
主线走一遍(高层,不进代码):
- 用户在 CLI 输入
deeptutor run chat "..."→ 打包成UnifiedContext。 ChatOrchestrator.handle看active_capability(没指定就用chat),从CapabilityRegistry取出对应能力。- 能力组装系统提示 + 工具清单 + 知识库种子,起一个 agent 循环。
- 循环每一轮调一次 LLM:模型先报标签。报
TOOL/调了工具 → 并行执行工具、把结果塞回对话、继续;报FINISH/没调工具 → 这一轮的文字就是最终答案,循环结束。 - 全程的推理、工具调用、最终文字都作为事件发到
StreamBus,前端实时渲染成「思考卡片 / 工具卡片 / 答案气泡」。 - 回合结束时,对话痕迹作为 L1 事件落进记忆;之后(手动或自动)被整理进 L2/L3 长期记忆。
3. 阅读地图(建议顺序)
这是一个多子系统的大项目。核心精华在前两章——读完这两章你就抓住了「DeepTutor 为什么叫 agent-native」。
- 01-agentic-loop.md — ⭐ 真·核心。标签协议、单步 LLM 调用怎么把「推理」和「正文」分流、并行工具分发、协议违规怎么自我修复。先读这章。
- 02-chat-loop.md — 默认聊天能力的循环:它用 OpenAI 原生 tool-calling,用「这一轮有没有调工具」来区分「叙述」和「收尾」,无需第二遍 respond。
- 03-memory.md — 三层记忆:L1 append-only 事件 → L2 表面摘要 → L3 长期画像;脚注引用的 markdown 文档格式 + 基于 id 差集的增量整理。
- 04-knowledge-rag.md — 知识库与 RAG:四套可插拔引擎、按文件类型路由、多查询变体聚合检索。
- 05-learning-mastery.md — 掌握式学习:纯函数的硬门、分知识点类型(记忆/概念/程序/设计)的定量 vs 定性评分、间隔重复调度。
- 06-tools-sandbox.md — 工具协议、上下文门控的工具挂载、三档隔离(SYSTEM/APPLICATION/OFF)的沙箱执行。
4. 横向对比(同 shelf 兄弟)
DeepTutor 站在「agent 框架」和「学术/教育应用」交叉处。它和兄弟项目的取舍差异:
- vs 通用 agent 框架(如 LangGraph 风格的图编排): DeepTutor 不用显式的「状态图」编排,而是用一条标签驱动的线性循环 + 能力插钩子(
LoopHost)。控制流不是预先连好的图,而是「模型每步报标签 + 循环按协议路由」。换来的是:加一个新能力 = 声明一套标签词表(LabelProtocol)+ 实现一组 host 回调,循环核心一行不改(见 01 章)。 - vs 把记忆做成向量库的项目: DeepTutor 的长期记忆是人类可读的 markdown 文档 + 脚注引用,靠 LLM 增量整理,而不是 embedding 检索(见 03 章)。可审计、可在网页工作台手改。
- 教育独有的「硬门」: 多数 LLM 辅导是「问什么答什么」;DeepTutor 把 Alpha School 的「90% 才能进阶」编码成纯函数策略,模型无权绕过(见 05 章)。