`session` / `notebook` / `book` / `memory`:DeepTutor CLI 这四组命令各管什么

2026-08-10

读一个 CLI 项目,最容易犯的错是把命令组名当成功能地图——看到有 book 组就默认能在终端里把一本书做出来,看到有 memory 组就默认能在终端里改记忆。DeepTutor 这四组恰好是反例:它们名字对仗工整,实际完整度差着好几个档次。

以下行号与数字都对应我们采集的仓库快照:HEAD 456f9c2,采集日 2026-08-10,deeptutor/__version__.py 里的版本号是 1.5.11。你自己 clone 之后行号会漂,但文件名、命令名和选项名是稳的。

一、四组在整棵命令树里的位置

deeptutor_cli/ 这个目录一共 20 个文件(19 个 .py 加 1 个 README.md),wc -l 合计 5421 行。全仓 @app.command( 装饰器共 43 处,本文这四组占其中 16 个:notebook 6、session 5、book 3、memory 2。其余各组的分布另有一篇专门讲整棵命令树的文章在数,这里只用得上作分母的这四项。

对应的四个文件是:

命令组文件行数子命令数main.py:36-46 里给的 help 文案
sessiondeeptutor_cli/session_cmd.py1015Manage shared sessions.
notebookdeeptutor_cli/notebook.py1216Manage notebooks and imported markdown records.
memorydeeptutor_cli/memory.py992View and manage lightweight memory.
bookdeeptutor_cli/book.py613Manage interactive Books (BookEngine).

四个文件加起来 382 行,在 5421 行里是很小的一块。help 文案都在 deeptutor_cli/main.py:36-46,注册动作在 main.py:48-59。这张表的读法是:行数和子命令数一起看——book 组用 61 行挂了 3 个命令,notebook 用 121 行挂了 6 个,两者的”每个命令干多少事”是同一量级;真正的差别不在这张表里,在下面。

二、session:它不是会话管理器,是 chat 的第二个入口

session 组的 5 个子命令是 listshowopendeleterenamesession_cmd.py:16-48)。参数很简单:list --limit 默认 20,show <id> --format 默认 richrename <id> --title 是必填选项。

反直觉的是 open。你会预期它是个只读查看器,但 session_cmd.py:31-35 直接调的是 _chat_repl(ChatState(session_id=...)),这个函数是从 .chat import 进来的(session_cmd.py:6)。也就是说,deeptutor session open <id>deeptutor chat --session <id> 走的是同一个 REPL 实现,不是两套代码。

这件事的实际含义有两条:

其一,你在 session open 里能用的斜杠命令,就是 chat REPL 的那一整套。REPL 欢迎面板列出来的是 /quit /session /status /new /clear/regenerate(别名 /retry)、/tool on|off <name>/cap <name>/kb <name>|none/history add <id> | /history clear/notebook add <ref> | /notebook clear/show last|<n>/refs/config show|set|clearchat.py:109-124)。查 session open 的用法时别只翻 session_cmd.py,那里没有,得去 chat.py

其二,恢复已有 session 时状态是回填的chat.py:92-107 会把 capability、tools、kb、language、notebook_refshistory_refs 从 session 的 preferences 里读回来。所以同一个 session 第二次打开时的默认能力和工具集,未必等于你这次在命令行上敲的那些——具体的覆盖顺序我们没有逐行核实,只陈述”有这么一段回填”。

另外 session list 打出来的表格列是 ID / Title / Capability / Status / Messages(common.py:865-896)。Capability 这一列出现在会话列表里,本身说明 session 在这个项目里是绑定能力的,而不是一条纯粹的消息流。

三、notebook:一半的命令是在搬 markdown 文件

notebook 组 6 个子命令:listcreate <name> --descriptionshow <id> --formatremove-record <id> <record_id>add-md <id> <file> --title --typereplace-md <id> <record_id> <file>notebook.py:16/22/32/55/68/102)。

注意后三个:add-mdreplace-mdremove-record 全是围绕”记录”这个粒度转的,其中两个直接以本地 markdown 文件为输入。命令组的 help 文案里 imported markdown records 这个词组不是随口写的,它就是这一半命令的全部内容。

两个默认值要记住:

  • add-md --type 默认 "chat",help 写的是 Record type: chat, question, research, solve.notebook.py:73-77)。也就是说你导入一份研究笔记时如果不显式给 --type research,它会被标成 chat
  • add-md --title 缺省取文件名 stem(notebook.py:86)。文件叫 第三章-草稿.md,记录标题就是 第三章-草稿

这里要说清一件事:chat / question / research / solve 这套记录类型划分、以及记录在整个学习流程里承担什么角色,都是这个项目的实现选择,不是经过验证的教学结论。本文只讲这些枚举值写在哪一行、缺省会取哪个,不评价这种分类在学习效果上的作用,也不承诺任何效果。

notebook list 的表格列是 ID / Name / Records / Description(common.py:865-896)。

还有一处跨命令的连接点值得单独记:chat REPL 里的 /notebook add <ref>,它的引用格式是 <notebook_id>:<record_id,record_id>notebook_id 为空会抛 typer.BadParameterchat.py:354-363)。冒号左边是 notebook,右边是逗号分隔的 record 列表。你在 notebook show 里看到的那一列 record id,就是拿来往这个引用串里填的。

四、memory:只有两个命令,其中一个会删本机文件

memory 组只有 showclear 两个子命令(memory.py:21-27:63-70),是四组里最小的一个。

show [target] 的 target 默认 "L3"。它的 help 自述 L3 是「四个 global docs」、L2 是「七个 surface docs」;代码侧对得上:L3Slot = Literal["recent","profile","scope","preferences"] 是 4 个,Surface 是 7 个 chat / notebook / quiz / kb / book / partner / cowriter(memory.py:25deeptutor/services/memory/paths.py:47-56)。这两处是一致的,值得说一句——本批里我们遇到的对不上的地方不少,这里没有。

clear [target] 的 target 默认 "all",带 --force/-f这个命令会删你本机磁盘上的文件,删除范围是 memory root 目录下的文件,以及 traceL2L3 三个子目录里的文件(memory.py:81-90)。写这类命令的注意事项照实说:默认值就是 all,不带参数敲下去等于全清;--force 会跳过确认。这是本机数据,删掉之后能不能恢复取决于你自己的备份,项目没有为此提供任何保证,我们也没有运行过这条命令去验证它的实际删除结果。

同样要划一条线:三层记忆的切分方式、每层放什么,是这个项目的工程设计。它怎么落盘、常量定义在哪个文件,本文可以指路(三层记忆的完整分层另有一篇专门讲);它对学习本身有没有效果,本文不作任何判断。

五、book:本文最反直觉的一处

book 组的 help 文案在 main.py:36-46 一段里给的是 Manage interactive Books (BookEngine).。单看这一行,很容易以为终端里能做书。

打开 deeptutor_cli/book.py,模块 docstring(book.py:1-5)写的是:Currently exposes maintenance commands. (Authoring/reading still goes through the API + web frontend.)。原样记录,不加解释:创作和阅读仍然走 API 加 web 前端,CLI 这一侧目前只有维护命令。

三个命令分别是(book.py:17/37/49):

子命令干什么
list列出 book
health <book_id>输出 kb_driftlog_health 两段 JSON
refresh-fingerprints <book_id>重拍 KB 指纹,并清空 stale 页列表

这三个命令的共同点很清楚:它们都是围绕”书和它依赖的知识库之间是否还对得上”这件事的。health 是查,refresh-fingerprints 是重新对齐。至于 BookEngine 内部怎么把一个知识库变成一本书、指纹是怎么算的,不在这个文件里,也不在本文范围内(book 模块的流程我们另有一篇专门讲)。

为什么这一处值得单拎出来? 因为它推翻了一条很常见的默认假设:命令组的存在意味着这条路在 CLI 上是通的。这里恰好相反——组注册了、help 写得像个完整功能、book.py:17/37/49 也确实挂了三个子命令,但主流程根本不在这条路上。你如果照着命令树排期,把”CLI 里跑通做书流程”写进计划,会在这里卡住,而卡住的原因不是你用错了参数,是这条路当前就没铺。

判断这类情况的通用动作只有一个:别停在 --help 上,去打开那个命令组的模块 docstring。这个仓库里,book.py 把话说在了 book.py:1-5 的模块 docstring 里。

六、README 与代码对不上的一处

按纪律,只陈述差异、标明两处位置,不推断原因、不评价质量。

deeptutor_cli/README.md 的「资源管理命令」一节(README.md:168-229)列出的命令组是 kb、session、notebook、memory、plugin、config、provider,其中没有 book,也没有 partner 组;而 bookpartner 均已在 main.py:48-59 的注册段里注册,book 含 3 个子命令(book.py:17/37/49)。

以我们实读的仓库状态为准。说完就停。

对你的实际影响只有一条操作建议:查这四组命令时,README 能覆盖 session / notebook / memory,book 得直接看源码。

七、你可以照着核的五步

  1. 打开 deeptutor_cli/session_cmd.py:31-35,确认 open 调的是 _chat_repl,再回到 session_cmd.py:6 看这个函数是从 .chat import 的。
  2. 打开 deeptutor_cli/chat.py:109-124,把 REPL 欢迎面板列的那一串斜杠命令抄下来——这就是 session open 之后你能用的全集。
  3. 打开 deeptutor_cli/notebook.py:73-77,确认 --type 的默认值是 "chat" 而不是根据文件内容推断的。
  4. 打开 deeptutor_cli/memory.py:81-90,确认 clear all 的删除范围,再决定要不要给 memory 目录做备份。
  5. 打开 deeptutor_cli/book.py:1-5,把那句 Authoring/reading still goes through the API + web frontend. 读一遍,再去 README.md:168-229 确认这一节里没有 book

需要说明的边界:本文只读了这四个命令文件的注册段与参数默认值,以及 common.py 里两张表格的列定义;common.pyTurnStreamRenderer(约 380 行的事件流状态机)我们没有逐行核实,deeptutor.book 下的 BookEngine 实现、deeptutor/services/memory/ 的存储实现也都没有读。凡是”命令跑起来之后会怎样”、退出码在真实终端下的表现,本文一律不下结论——我们只读了源码文本,没有安装或运行过 DeepTutor。文中出现的默认值都是源码里的默认配置,不构成对实际运行结果的保证。

另外提醒一处:这个项目的 CLI 会在本机做真实的读写与进程动作——memory clear 会直接删除本机 memory 目录下的文件,chat REPL 启动时会尝试 get_cron_service().start() 并在退出时 stop(chat.py:83-90:177-180),serve 在 Windows 上专门切到 WindowsProactorEventLoopPolicy,注释写明原因是 uvicorn 默认的 SelectorEventLoop 不支持 asyncio.create_subprocess_execmain.py:148-152)——最后这一条本身就说明运行期会起子进程。是否在你的机器上跑,请结合自身环境评估。


本文依据 DeepTutor 官方仓库(github.com/HKUDS/DeepTutor)的 README、AGENTS.mdpyproject.tomldeeptutor/ 下的源码整理,核对日 2026-08-10,对应仓库快照 456f9c2(版本 1.5.11)。 本文内容为仓库源码与文档口径,我们没有安装、部署或运行过该项目,也没有调用过其中任何一个模型 API, 因此不涉及生成质量、响应速度与教学效果的任何描述。 参数与默认值随版本变动,请以仓库最新代码与 --help 的实际输出为准。 安全相关做法请结合自身环境评估,本文不构成安全方案建议。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。