Skip to content

CH 09 · 核心子系统与一条消息的流转

全文字数2731 字预估耗时约 14 分钟前置CH 08 插件树难度理解篇

本章目标

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-stoppingturn/end,这一轮结束,你看到最终回答。

一个关键区别记在脑子里:图里右侧标了两类事件——

  • 持久事件turn/*step/*user/messageassistant/*tool/*):会写进会话日志,重启了也在;
  • 实时扩展点agent/pre-stepagent/requestllm/streamtools/*):只在运行中生效,插件靠它们拦事情、改行为,但本身不落账。

这正好呼应 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 拦事情)
  • [ ] 能说出"模型可见即已记录"这条规则的含义

Open Source · MIT · Community Driven