第 3 课

出题、JSON 事件流与会话续聊

用 run deep_question --config num_questions 按知识库出题并看清小模型的局限,用 --format json 输出 NDJSON 并用 jq 取 result、sources 和 session_id,用 --session 跨进程续聊,用 session list、session show 回看记录,最后照官方文档了解用 SKILL.md 交给 Claude Code、Code

图文25 分钟

课程目录第 3 / 3 课

学习位置仅保存在当前浏览器,有效期 180 天。

01 / 图文教材

图文教材

本课对照的官方页面:命令参考、代理交接、故障排查。第 1~4 步为实测(DeepTutor 1.7.0,本地 gemma-4-e2b),第 5 步照官方文档整理、未实测。

前两课用的都是 chat。这一课先试 DeepTutor 的出题能力 deep_question,再学 --format json 事件流和 --session 续聊。掌握这两样,就能把 DeepTutor 写进脚本,或者交给 Claude Code、Codex 这类代理来调用。

第 1 步:根据知识库出题

deeptutor run 的第一个参数是能力名(capability)。deep_question 用来出题,题量、难度等参数通过 --config key=value 传入:

deeptutor run deep_question "根据笔记出 2 道导数选择题" \
  --kb calculus -l zh --config num_questions=2

实测(约 4 分钟,节选,公式两侧的 $ 已省略):

▶ exploring
  模型违反了动作标签协议;本轮重试。   (共出现 8 次)
  已达迭代上限。基于当前已有内容产出输出。
▶ planning
▶ quizzing
题目 1
函数 f(x) = x^2 在 x=1 处的导数值是多少?
 • A. 2   • B. 1   • C. 0   • D. 4
答案: A
解析: f'(x) = 2x,因此 f'(1) = 2。
题目 2
……下列哪一项最准确地描述了导数的几何意义?
答案: true

这次实测的结果并不理想,这里如实记录。deep_question 会先进入 exploring 阶段,让模型按智能体协议调用工具去查资料。2B 小模型反复违反协议,8 轮后触顶,最后只能凭模型自己的知识出题。第 1 题正确;第 2 题是选择题却没有选项,答案写成了 true。

结论:chat 和 kb 用小模型就够了,但 deep_question、deep_solve、deep_research 这类多阶段能力,应该在 setup.json 里换成更强的模型,具体写法见第 1 课第 4 步。官方的代理交接示例还演示了 --config difficulty=easy|medium|hard,可以分难度出题。

第 2 步:用 --format json 拿到结构化事件

加上 --format json 后,stdout 每行输出一个 JSON 事件(NDJSON)。日志走 stderr,可以用 2>/dev/null 屏蔽:

deeptutor run chat "用一句话说明 (x^3)' 等于多少" \
  --kb calculus -l zh --format json 2>/dev/null > turn1.ndjson

统计一下各类事件的数量:

jq -r '.type' turn1.ndjson | sort | uniq -c

实测对照结果:

     37 content
      1 done
     22 progress
      1 result
      1 session
      1 session_meta
      1 sources
      1 stage_end
      1 stage_start
    498 thinking

thinking 是模型的推理流,content 是逐段输出的正文。脚本最常用的是三类事件:result 里有完整回答,sources 是引用的资料,done 带着会话 ID。

jq -r 'select(.type=="result") | .metadata.response' turn1.ndjson
jq -r 'select(.type=="done") | .session_id' turn1.ndjson

对照结果:

$(x^3)'$ 等于 $3x^2$,这是根据幂法则 $(x^n)' = n x^{n-1}$ 推导得出的结果。
unified_1793290582368_cd7cb797

第 3 步:用 --session 接着上一轮聊

把会话 ID 存进变量,下一轮通过 --session 传回去,模型就能记得上下文:

SID=$(jq -r 'select(.type=="done") | .session_id' turn1.ndjson)
deeptutor run chat "那 (x^4)' 呢?只写结果" --session "$SID" \
  -l zh --format json 2>/dev/null \
  | jq -r 'select(.type=="result") | .metadata.response'

对照结果:

$(x^4)' = 4x^3$

第二轮只问了「那 (x^4)' 呢」,模型能接上,说明上下文确实续上了。这就是官方代理交接示例的做法:第一轮从 done 事件取出 session_id,后面每一轮都带上它。

第 4 步:回看会话记录

deeptutor session list
deeptutor session show "$SID"

对照结果:session list 列出所有会话,包括 ID、自动生成的标题、能力和消息数。这次实测的标题有「导数幂法则」「速度加速度辨析」「无法生成题目」等。session show 的节选(公式两侧的 $ 已省略):

导数幂法则 (unified_1793290582368_cd7cb797)
capability=chat status=completed messages=4
USER       用一句话说明 (x^3)' 等于多少
ASSISTANT  (x^3)' 等于 3x^2……
USER       那 (x^4)' 呢?只写结果
ASSISTANT  (x^4)' = 4x^3

会话数据都保存在运行目录的 data/ 下,换一个终端、换一个进程都能用 --session 续上。

第 5 步:交给 Claude Code / Codex 调用(照官方文档)

DeepTutor 仓库根目录附带一份 SKILL.md,按官方说明,内容包括使用场景、前置条件、全部命令、REPL 斜杠命令和典型工作流。官方给出的接入方式是把它链接到你的项目根目录:

cd /your-project
ln -s /path/to/DeepTutor/SKILL.md ./SKILL.md

之后就可以直接用自然语言下任务,例如官方示例:

Read SKILL.md before doing anything else. Then build study plans,
generate quizzes, ...

代理会把任务翻译成 kb create、run deep_question --format json、--session 这些前面练过的命令。这一步本课没有实测,具体以代理交接页面为准。

小结

  • deeptutor run <能力> "<消息>" 是统一入口,能力参数用 --config key=value 传入。
  • --format json 输出 NDJSON:result 取回答,sources 取引用,done 取 session_id。
  • --session 可以跨进程续聊,session list 和 session show 用来回看记录。
  • 多阶段能力(出题、解题、研究)对模型要求高,小模型实测会出现协议错误和题目格式错误。