第 9 章 架构全景:轮次流程、会话日志与能力 Seam

本章把视角拉高,梳理 dsh 的整体架构,对应官方 Architecture 页面的后半部分。

9.1 三个事件域

事件就是扩展点,选对事件域是大多数改动的第一个决定:

域特征适用场景
会话事件追加到日志并通过 session/event 广播的持久事实事实必须在重新加载后仍然存在时
Agent 事件(agent/*)携带活跃 Agent:inbox、步骤、状态、请求、验证、续跑观察或拦截进行中的工作
能力事件fs/*、tools/*、telemetry/* 等无需导入循环即可向某个 seam 附加策略和适配器

官方的事件映射文档(docs/event-producer-consumer.zh.md)列出每个事件的生产方与消费方。

9.2 轮次流程(Turn Flow)

一个步骤(step)= 一次模型请求 + 它调用的工具;一个轮次(turn)包含零或多个步骤——它在领取首条输入前打开,在不再欠下任何工作时关闭:

turn/start
  claim next-step input plus one queued message
  assemble prompt sections + tool schemas; project runtime context
  -> agent/pre-step                   reject | enter(messages, startsRequestSeries?)
     step/start
     agent/request -> prepareCall
     append entered messages as user/message; log request/header & request/context
     derive and freeze model history from the log
     stream the bound prepared call -> llm/stream -> agent/assistant-stream start
       agent/assistant-stream chunk*
       assistant/message | assistant/attempt -> agent/assistant-stream end
     tool/call* -> tools/pre-execute -> tools/execute -> tools/post-execute -> tool/result*
     step/end
     tools owe another request, or next-step input arrived -> claim -> next step
  -> agent/turn-stopping
turn/end

理解要点:

  • 持久 vs 实时:turn/*、step/*、system/message、user/message、assistant/message、assistant/attempt、tool/* 是持久会话事件;其余是三个事件域的实时扩展点。

  • waterfall 事件:agent/pre-step、agent/request、llm/stream 和三个 tools/* 是瀑布式事件,监听器必须调用 next() 才能委托下去;agent/turn-stopping 是 serial 事件,没有 next()。

  • 输入统一走 inbox:有些消息立即唤醒驱动器;注入的上下文留在 inbox,直到另一条消息将其唤醒。

  • agent/pre-step 决定接纳的输入,监听器可改写或拒绝;首次领取被拒绝或为空时,关闭不含步骤的持久轮次。

  • 取消语义:agent/request 与 prepareCall() 先解析实际路由,再提交系统提示词与已接纳的用户消息;在任一异步阶段取消,这两者都不会被提交。重试不重复组装或 agent/pre-step。

  • 循环发送不可变请求,同时保留实时取消能力;只有已由该循环完整冻结的消息对象身份才能复用冻结证明。

9.3 会话日志:"模型可见即已记录"

会话日志是模型所见上下文的来源——deriveMessages() 从中投影出模型历史。核心不变量:

抵达模型请求的一切,都必须能从日志重建,并由一项运行时不变量断言这一点。因此新增一项模型可见输入 = 新增一个会话事件(扩展 SessionEventMap 并从日志渲染)。

  • 每个 assistant/message 嵌入产生其组装内容的精确紧凑带时间 stream;

  • assistant/attempt 保留已到达 settlement 的失败、重试、取消与 stream error attempt,不添加模型历史;

  • fork、恢复、transcript、遥测与持久化都从持久 settlement 派生;实时 UI 增量来自 agent/assistant-stream;

  • 进程在 settlement 前硬中断则不会留下持久 attempt stream。

格式与迁移

  • JSONL v0 使用 session.jsonl[.zstd],v1 起使用 session.vN.jsonl[.zstd];

  • 已提交 generation 路径绝不重命名、替换或删除;

  • stat/list 重扫会话目录、选择数值最高的规范 generation;open 拒绝未来版本,或经构建时静态确定的相邻迁移链(每个迁移包只负责一个 vN → vN+1 步骤)转换到当前逻辑事件;

  • 写 open 会在未改变源旁边排他发布最终版本命名的后继。

投影 Seam

dsh-session-projection 提供 ctx.sessionProjections:已注册单元增量折叠已提交事件;消费方通过 stateOf() 读取单个类型化状态,载体通过 snapshot() 批量取得裁剪后的客户端视图。host 读取方要么在激活时要求该服务,要么在必需 key 缺席时明确失败——不能为缺失的 host 值静默提供默认值。agent loop 为读取方注册共享的 turnBoundary 状态。

9.4 能力 Seam:Service Definition Provider Consumer

一个 seam 是一项可替换能力,包含三种角色:

  1. Service Definition:声明接口;

  2. Service Provider:实现它;

  3. Consumer:使用它(通常是面向模型的工具)。

一个包可以合并承担多个角色,但单一角色本身不是 seam;添加一项能力意味着把三者一并设计。

Seam 正是"替换一个提供方就能改变整个产品"的原因:

  • 文件系统与进程提供方共享同一个执行世界——把它们指向远程沙箱,就把 Bash、PTY 和 LSP 一并搬了过去,无需提供方专用 fork;

  • subagent 提供方在同一接口之后千差万别:从新建一个子 agent,到把一个轮次委派给另一个产品;

  • 实验性 Agent Teams 是 ctx.agentTeams 上公开发布、显式启用的协作 seam,在可继续 subagent 之上提供持久 roster、任务板和 mailbox。

9.5 桌面应用补充

Electron 桌面应用持有保留的 $DSH_HOME/profiles/desktop npm 项目,每个签名发行版绑定确切 dsh 版本并携带离线 seed;RPC 经带版本的分帧字节管道传输,Node IPC 只保留生命周期控制;桌面组合不开放 Web server 或 loopback 端口。


依据官方 Architecture 整理;时序图、工具流水线与取消恢复的细节见官方 agent-lifecycle、tool-execution-pipeline 页面。

DeepSeek Harness / 第 9 章 架构全景:轮次流程、会话日志与能力 Seam 0 字 0 行 cosolar
2026-09-17T10:12:14.016585053Z 2026-09-17T10:39:04.086054066Z