目录

HKUDS/DeepTutor 拆解:一个 agent-native 的终身个性化辅导工作台是怎么搭起来的

一句话判断

DeepTutor(HKUDS/DeepTutor)是港大数据智能实验室(HKUDS)维护的 agent-native 终身个性化辅导工作台,截至 2026-07 在 GitHub 上 26.7k stars / 3.6k forks,Apache-2.0。 它不是又一款 RAG chatbot,而是把"辅导"这件事拆成 9 个共享同一 agent loop 的能力面(Chat / Quiz / Research / Visualize / Solve / Mastery Path / Co-Writer / Book / Partners),并把这 9 个面下需要的知识库、技能、人格、记忆、IM 渠道、子代理全部接进了同一套状态机。读它的关键不是 feature list,而是"为什么 Chat、Partners、Co-Writer、Book、Knowledge Center 之间能共享上下文,以及这套上下文用三层 Memory + 5 套 RAG 引擎是如何被组织起来的"。

如果你正在评估"自己造一个 AI 辅导产品 / 内部知识助手",或者在选 RAG 引擎和 agent loop 编排方式,这篇文章值得完整读完。


系统地图

DeepTutor 的真实架构不是 README 顶部那张"能力面截图",而是 v1.4 重写之后沉淀出来的 Tools + Capabilities 插件模型。下面这张图把"用户感知的入口"、“能力面”、“共享工具层”、“可插拔底座"四层拆开:

┌──────────────────────────────────────────────────────────────────────┐
│  入口层 (User-facing surfaces)                                         │
│    Web  /  CLI (deeptutor)  /  IM 渠道 (15+)  /  REST + WebSocket API  │
└─────────────────────────────────┬────────────────────────────────────┘
                                  │
┌─────────────────────────────────▼────────────────────────────────────┐
│  能力面层 (Capabilities, all share one agent loop)                    │
│   Chat · Quiz · Research · Visualize · Solve · Mastery Path ·          │
│   Co-Writer · Book · Partner (per-channel long-running companion)    │
└─────────────────────────────────┬────────────────────────────────────┘
                                  │
┌─────────────────────────────────▼────────────────────────────────────┐
│  共享工具层 (Capability-scoped Tools, mount automatically)             │
│   brainstorm · web_search · paper_search · rag · read_source ·       │
│   read_memory · write_memory · read_skill · load_tools · exec ·      │
│   web_fetch · ask_user · list_notebook · write_note · github ·       │
│   consult_subagent · imagegen · videogen · geogebra_analysis · …     │
└─────────────────────────────────┬────────────────────────────────────┘
                                  │
┌─────────────────────────────────▼────────────────────────────────────┐
│  底座层 (Pluggable substrate)                                          │
│  ┌─────────────────────┐  ┌─────────────────────┐  ┌──────────────┐  │
│  │  Knowledge Center   │  │  Learning Space     │  │  My Agents   │  │
│  │  5 retrieval engines│  │  notebook / skills  │  │  Claude Code │  │
│  │  + 5 parser engines │  │  / persona / qbank  │  │  Codex · 等  │  │
│  └─────────────────────┘  └─────────────────────┘  └──────────────┘  │
│  ┌─────────────────────┐  ┌──────────────────────────────────────┐  │
│  │  Memory (L1/L2/L3)  │  │  Channel Adapter (Feishu/Telegram/  │  │
│  │  trace + cur + synth│  │  Slack/Discord/DingTalk/QQ/WeCom/    │  │
│  │  file-backed        │  │  WhatsApp/Zulip/Mattermost/Matrix/   │  │
│  │                     │  │  Mochat/Teams)                       │  │
│  └─────────────────────┘  └──────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────────────┘
                                  │
┌─────────────────────────────────▼────────────────────────────────────┐
│  LLM Provider + Embedding Provider (configurable, multi-provider)     │
└──────────────────────────────────────────────────────────────────────┘

这张图最重要的一条路径:“入口 → 能力面 → 自动挂载的工具 → 可插拔底座”,每一层都可以单独替换或扩展;这就是 README 自己反复强调的"agent-native”——把 agent loop 作为内核,而不是把每个能力面写成独立的微服务。


边界与角色划分

把 DeepTutor 拆成 4 组"不变项",可以一次性回答"它和别的 RAG 工具到底差在哪":

维度不变项工程含义
能力组织9 个能力面共享同一个 agent loop切换目标不切换引擎;上下文随学习者流转
知识接入5 套 RAG 引擎 + 5 套文档解析引擎,可单库绑定LlamaIndex(默认,向量+BM25)/ PageIndex / GraphRAG / LightRAG / LightRAG Server / linked Obsidian;Text-only / MinerU / Docling / markitdown / PyMuPDF4LLM
上下文三层文件可审计 Memory + 可选子代理L1 trace / L2 表面事实 / L3 跨面综合,每一条都能回溯证据
部署形态4 路安装路径共享同一 workspacePyPI / Docker / 源码 / remote-Docker;所有配置都落在 data/user/settings/$DEEPTUTOR_HOME

要注意的几个边界:DeepTutor 不是一个 LMS(学习管理系统)——它没有课程编排、没有班级、没有成绩册;它的定位是"个人学习工作台 + 可挂载子代理的辅导引擎"。它也不是一个 RAG 框架——LlamaIndex / PageIndex / GraphRAG / LightRAG / LightRAG Server 都只是 Knowledge Center 下的可选后端,你换掉它不会影响上层能力面。


关键机制

1. 同一个 agent loop,9 个能力面

DeepTutor v1.4 的核心抽象是 “agent loop as the single engine"。Chat、Quiz、Research、Visualize、Solve、Mastery Path 全部跑在 ChatOrchestrator 这一个回路上;能力面的差异不是引擎差异,而是:

  • 不同的 system prompt + 不同的工具挂载集合
  • 不同的入口 UI / 输出卡片(quiz 题卡 / 引用报告 / 图表 / 动画)
  • 不同的会话上下文(Mastery Path 会自动记录每题的对错并累积到 Question Bank)

这条回路有个值得专门记下的机制:ask_user 是一个"挂起而非猜"的工具——模型不是盲目继续推理,而是在不确定时主动暂停一个 turn,向用户发一个结构化澄清问题,等用户回答后从中断点恢复。这把"agent 的不确定性"显式化了,而不是把它藏在重试里。

工具挂载分两类:

  • 用户可切换brainstormweb_searchpaper_searchreasongeogebra_analysis,外加配置了生成模型后的 imagegen/videogen
  • 上下文自动挂载ragread_sourceread_memorywrite_memoryread_skillload_toolsexecweb_fetchask_userlist_notebookwrite_notegithubconsult_subagent

“自动挂载"这一类决定了 DeepTutor 的"工作台"气质——你把一个知识库钉在 composer 工具栏,工具链就会自动接上,不需要在每次提问里手动选。

2. 5 套 RAG 引擎,单库单绑

Knowledge Center 是 DeepTutor 最容易被低估的一部分。表面上它就是一个"上传文档 → 问 → 答"的工作流,但它的设计里有几个少见的工程决定:

  • 每个 KB 只能绑一个 retrieval 引擎。一个 KB 要么是 LlamaIndex,要么是 PageIndex,要么是 GraphRAG/LightRAG,要么是一个链接到本地 Obsidian vault 的"linked KB”。这避免了"同一库多套索引一致性"的灾难,但代价是切换引擎必须重建索引。
  • Document parsing 与 retrieval 解耦。你可以选 LlamaIndex 引擎,但解析时换 MinerU;这让"重解析"和"重检索"变成两个独立操作。
  • Re-index 不会毁掉工作索引。每次重建都会写一个新的 version-N 目录,旧版本保留;这样中途失败可以立即回退,而不是把 KB 留在一半状态。
  • 单文档级删除(v1.5.1)。即便是处在 error 状态的单文档,也可以从 KB 中移除而不用删整个 KB——这是对"用户上传了一张坏 PDF 不能用怎么办"的具体回应。
  • LightRAG Server 把检索外置。如果团队已经有一个 LightRAG 实例,可以让 DeepTutor 用 HTTP 调它而不是本地跑,知识库的所有权留在外部系统。

3. 三层 Memory:可审计的个性化

DeepTutor 的 Memory 不是 vector DB,是一个文件化、可读、可改的三层系统

L1  trace/<surface>/<date>.jsonl    追加式事件流(每次 tool call / 每回合输出)
L2  L2/<surface>.md                 每个表面的精选事实(curated facts)
L3  L3/<profile|recent|scope|preferences>.md   跨表面综合

关键不变量:L2 必须能引用到 L1 的事件,L3 必须能引用到 L2 的事实。这意味着模型声称"记得你上周写过一篇笔记"这件事,你能从 L3 追到 L2 再追到 L1 的原始 trace,整条链是 openable 的。这和"黑盒向量记忆"最大的差别在于:你可以编辑、删除、修正自己的画像,而不是被动等系统"学会”。

注意这条不对称的访问控制:Partner 读主人的 memory,但只写自己的 memory。这是 Partner 的"它记得我,但它不会把对我的印象写进我的 L3"。

4. Partner:复用 ChatOrchestrator 的"长连接人格"

Partner 是一个看起来独立、实际上没有自己引擎的子系统。每一条来自 IM 渠道的消息,最终都变成一个普通的 ChatOrchestrator turn,跑在 partner-scoped workspace 里。

这意味着:

  • Partner 不是一个新的 agent runtime,它和 Chat 共用同一条回路、同样的 RAG、同样的 Memory API
  • Partner 的"个性"由 SOUL.md、model policy、channels、tool policy、assigned library 这五个文件决定
  • 同一个 Partner 可以同时挂在 Feishu、Telegram、Slack 等 15+ 渠道上,对话上下文共享
  • Knowledge bases、skills、notebooks 会被复制到 data/partners/<id>/workspace/,所以 Partner 用的工具不需要特殊实现

这种设计的代价是:Partner 不能跑 Chat 没有的能力(比如它跑不了 Visualize 的图表生成),但收益是把"多渠道一致性"几乎免费拿到——只要一个 Chat 能回答,挂了 IM 的 Partner 也能回答。

5. My Agents:把外部 agent 当成上下文

“Subagent"在 DeepTutor 里不是另一种 worker,而是一种上下文类型consult_subagent 工具让 Chat 在一个 turn 内真正运行你本地的 Claude Code / Codex CLI,或者运行你自己定义的 Partner,并把它的输出以流式方式呈现在 Activity 面板。

特别值得注意的是"导入历史对话"的能力——/agents 面板可以把你过去和 Claude Code / Codex 的历史对话作为第三方对话导入进来,而不是当作 DeepTutor 自己的回合:这些对话保持原来的语气、格式、工具调用痕迹,DeepTutor 只是在 Chat 里把它们当成可引用的 transcript。

6. CLI = Agent-native Interface

deeptutor CLI 不是"暴露 API 给脚本”,而是被设计成"CLI 也是 agent loop 的入口":

deeptutor init                                       # 工作区初始化(端口/provider/key)
deeptutor start                                      # 启动后端 + Next.js 前端
deeptutor skill install <name>                       # 从 EduHub 安装 skill(带安全门)
deeptutor kb list/info/create/add/search             # KB 全生命周期 CLI 镜像
deeptutor book health / book refresh-fingerprints    # 检测 source 与 compiled page 是否漂移

deeptutor 的 session 可以保留 id 跨多轮复用——这让"在脚本里驱动 DeepTutor 多轮对话"成为常态,而不是把 CLI 当作一次性 prompt 工具。


一个请求如何流过系统

下面以一个具体的"读论文 + 出 quiz + 加进 Mastery Path"任务走一遍:

用户在 Chat 里粘贴论文 PDF
        │
        ▼
Composer 工具栏: 选中 Knowledge Base = "papers-llm"  (LlamaIndex 引擎)
        │ 自动挂载: rag / read_source / write_memory / write_note /
        │           list_notebook / consult_subagent / ask_user / reason
        ▼
ChatOrchestrator 起一个 turn:
  Round 1: rag → 论文前 6 段摘要
  Round 2: ask_user → "你想出 5 题还是 10 题?偏推理还是偏概念?"
           (用户答: 5 题 + 偏推理)
  Round 3: reason + read_skill "quiz-gen" → 5 道 quiz + 答案解释
  Round 4: 写一条 L2 fact "用户偏好: 概念题多于推理题" → Memory
  Round 5: write_note "LLM 论文 5 题" → Notebook
        ▼
用户: "把这 5 题加到我的 Mastery Path 里"
        │
        ▼
Mastery Path 能力面复用同一 ChatOrchestrator,但挂载额外工具:
  - mastery_track_progress (记录每题对错)
  - qbank_add (把题存进 Question Bank)
        │
        ▼
Partner "研究助理" 在 Feishu 收到推送:
  因为 Partner 复用 ChatOrchestrator,message 进来变成 partner-scoped turn,
  同样的 RAG 同样 memory 同样 model policy,但 read 主人的 L3、写自己的 L3。

这个例子刻意覆盖了 4 个面(Chat / Mastery Path / Memory / Partner)+ 1 个外部 partner,目的是让你看到它们不是 4 套系统,而是同一个 agent loop 在不同入口的不同投影


采用顺序与适用边界

推荐采用顺序

  1. 从 Chat + 一个 LlamaIndex KB 开始——这是 80% 场景的最小可用单元,验证"个人知识助手"是否值得继续投入。
  2. 加 Memory(L2 精选事实)——这一步是把"工具"升级成"个性化助手"的关键跳转,且 L2 文件可读,调试成本几乎为零。
  3. 引入 Partner 把 Chat 挂到 IM 渠道——如果你已经在用 Feishu/Slack,这一步把"打开 Web"变成"在群里 @ 机器人"。
  4. 再考虑 Book / Co-Writer / Mastery Path——它们价值大但场景窄,等基础回路用熟之后再启用。
  5. 多用户部署(v1.3.8+)——只在确认要服务超过一个用户时再做,每个用户的 workspace 隔离 + admin grants + 范围化 runtime 访问需要单独运维。

适用边界

适合不适合
个人/小团队的私人学习与研究助手学校/企业的 LMS / 课程编排 / 班级管理
多源知识库(论文/笔记/笔记软件/对话历史)需要统一检索单文档偶尔查询(直接用 IDE Copilot 就够)
需要把 agent 接到飞书/Slack/微信等已有 IM 渠道纯离线、纯本地、零 LLM 依赖的场景
想用一套代码既跑 Web 也跑 CLI、还能被脚本驱动想要商业 LMS 的合规、审计、学情报告能力
愿意承担"agent-native"心智模型(理解 Tools + Capabilities 模型)只想找一个开箱即用的 ChatPDF

风险与未知项

  • 大依赖面:README 标注 Python 3.11+ 与 Node.js 20+,部署前需要确认目标机器的依赖;rootless Podman 在 v1.4.13 起支持,但仍要单独验证。
  • 第三方过期材料:OSSU 之类的关联项目会随时间漂移,仓库本身已警示——选第三方扩展时建议直接看仓库的 latest release。
  • arXiv 论文 ID 与日期:README 提到 arXiv:2604.26962 的 preprint,文章写作时该编号按仓库当时引用为准,建议读者在引用前自行验证。
  • 许可证:Apache-2.0,对二次分发相对友好,但 v1.4+ 的 Partner / IM 渠道抽象下,私有部署仍需逐项评估依赖子项目的许可证。

一处延伸阅读

如果想继续深入: