CH 09 · 核心子系统与一条消息的流转
本章目标
CH 08 讲了 dsh 是"一棵插件树",这一章把镜头拉近:树上的几个关键插件(子系统)各自管什么、怎么配合,然后跟着一条消息走完全程——从你敲回车,到它回话,中间发生了什么。这两件事看懂,你就知道 dsh 内部是怎么转起来的。
核心子系统:一家餐厅的后厨团队
延续 CH 08 那家小馆子:后厨不是一个人,是一队分工明确的员工,各管一摊、互相递活儿。dsh 的核心子系统就是这队员工:
| 子系统 | 对应员工 | 管什么 |
|---|---|---|
agent-loop | 主厨 | 默认的驱动器:决定"下一步做什么"——请求模型、叫工具、收结果,整个循环由它转 |
llm | 外卖接线员 | 通过适配器连接外部模型,把消息送出去、把回复接回来 |
tools | 厨具柜 + 把关人 | 工具注册表 + 受控执行管道;每个 agent 用自己那一套(scope 隔离) |
system-prompt | 备菜拼盘 | 把各个插件注册的提示词片段、工具 schema 拼成"这一盘给模型看什么" |
session | 记账本 | 追加式会话日志:你发的、模型回的、工具跑的,全部记录在案 |
scope | 工位隔离 | 让每个 agent 的注册只在自己那格子里生效,互不串台 |
它们怎么配合,看这张图:
一句话记法:主厨(agent-loop)发号施令,拼盘(system-prompt)备料,接线员(llm)叫外卖,厨具柜(tools)递工具,最后所有结果都记进记账本(session)。而记账本,是下一章的主角。
一个关键单位:step 与 turn
看流转之前,先分清两个词,它们是理解整条链路的地基:
- step(步骤)= 一次模型请求 + 它调用的工具。模型"想一下 + 动一下手"算一个 step。
- turn(轮次)= 零个或多个 step。从领到你的第一条输入开始,到不再欠任何工作为止。
为什么一个回答可能有好几个 step?因为模型经常"想一下 → 调个工具 → 看到结果再想一下 → 再调一个……"直到它觉得够了,才给出最终回答。这一整串是一个 turn,里面的每一次"想+动"是一个 step。官方原话是:轮次在领取首条输入之前打开,在不再欠下任何工作时关闭。
对应到生活:你点一单(turn),服务员可能来回好几趟(step)——先确认有没有这菜、再上菜、再问要不要加料——直到这单真正上齐才算完。
一条消息的流转:从你回车到它回话
现在把一条消息完整走一遍。跟着这张图从上往下看:
① turn/start:轮次打开。 你按下回车前,这一轮还没开始;按下后,轮次先打开,进入"领取输入"。
② 领取输入(inbox)。 所有输入都先进一个叫 inbox 的信箱。你发的消息会立即唤醒主厨开始干活;而"注入的上下文"(CH 04 见过的那种)会先留在信箱里,等另一条真正的消息把它叫醒——所以"注入资料"本身不会打断流程。
③ 组装:提示词 + 工具 schema。 system-prompt 把各个插件注册的片段拼成一盘,告诉模型"你是谁、有哪些工具可以用、工具长什么样"。
④ agent/pre-step:决定模型看到什么。 这是第一个"实时扩展点"——插件可以在这里改写要发出去的内容,或直接拒绝这一次。被拒绝或改写为空,这轮也会照常关闭并记录,日志里能看到"试过一次但没跑成"。
⑤ step/start:落账 + 取历史。 你发的消息作为 user/message 写进会话日志;同时模型这一轮的历史,从日志里投影出来(deriveMessages())。模型看到的一切都来自日志——这是后面要反复强调的一句。
⑥ 请求模型 → 收到回复。 agent/request 发请求(可被拦截)、llm/stream 流式返回、模型回复作为 assistant/message 写进日志。
⑦ 要调工具? 如果模型决定"我需要动手",就 tool/call → 执行 → 结果 tool/result 写回日志。执行前后各有拦截点(pre/post-execute)。如果不需要工具,直接跳到下一步。
⑧ step/end:还有活吗? 如果工具结果还需要模型再处理一轮(或又有新输入进来),就再开一个 step,回到"领取输入";直到不再欠任何工作,走 agent/turn-stopping → turn/end,这一轮结束,你看到最终回答。
一个关键区别记在脑子里:图里右侧标了两类事件——
- 持久事件(
turn/*、step/*、user/message、assistant/*、tool/*):会写进会话日志,重启了也在; - 实时扩展点(
agent/pre-step、agent/request、llm/stream、tools/*):只在运行中生效,插件靠它们拦事情、改行为,但本身不落账。
这正好呼应 CH 08 的"事件是扩展点":想观察或拦截正在跑的工作,盯实时事件;想让事实留下来,靠持久事件。
模型的记忆从哪来
一句话:会话日志就是模型看到的上下文。模型这一轮"记得什么",不是它自己记的,而是系统从日志里投影给它的历史——所以"模型可见即已记录"是 dsh 的一条硬规则:任何到达模型请求的东西,都必须能从日志重建,运行时会用不变式去检查。这条规则是整个设计的轴心,我们 CH 10 专门讲它。
顺手和前面对上号:CH 04 你看过的"轨迹视图"——那一排 ASSISTANT / TOOL 时间线——底层就是这个会话日志的可视化。模型说了什么、调了什么工具、结果是什么,都是从日志渲染出来的。所以你问"它为什么记得我前面说过的话",答案很朴素:不是模型记得,是日志记得——每次提问前,系统把日志里的历史投影出来喂给它。
这一章你学到了什么
- [ ] 能说出核心子系统的分工(agent-loop / llm / tools / system-prompt / session),并解释它们怎么配合
- [ ] 能说清 step 和 turn 的区别(step = 一次模型请求+工具;turn = 零个或多个 step)
- [ ] 能顺着图讲一条消息的完整流转:turn/start → 领取输入 → 组装 → pre-step → step/start → 请求模型 → 工具调用 → step/end → turn/end
- [ ] 能区分持久事件和实时扩展点,并说出各自用途(留证据 vs 拦事情)
- [ ] 能说出"模型可见即已记录"这条规则的含义
