Skip to content

1.5 会话日志:事件溯源与"模型可见即已记录"

本章概览:DSH 的会话模型是事件溯源(event sourcing)——一次对话的全部历史是一条只追加的事件日志。本章讲清会话日志的数据结构、模型历史如何派生、以及"模型可见即已记录"这一贯穿全项目的不变式。

会话 = 只追加的事件日志

Session 是 Agent 整个交互历史的只追加(append-only)事实源。模型消息历史(LLM message history)是从日志派生的,而不是独立保存的副本。

text
Session
  ├── session.events   # 只追加的 SessionEvent[](深冻结的持久事实)
  ├── session.surface  # 有序的"消息产生事件"投影层(用于高效派生与压缩)
  └── deriveMessages() # 从 surface 增量投影出完整模型历史

出处:packages/core/session/README.mddeepseek-harness-src/packages/core/session/README.md

关键数据形态

概念说明
SessionEvent持久事件:user/messageassistant/messageassistant/chunktool/calltool/resultturn/*step/* 等(SessionEventMap 声明)
SessionSurface消息产生事件的有序投影;压缩(compaction)会用它做"整段替换"
session.header脱离(detached)的创建元数据:versionidcreatedAt、可选 cwd / parentSession / seedLength / delegationDepth
SessionStorectx.sessions创建并持有 Session 实例;持久化不在本包实现——插件订阅 session/event,在 session/flush 时落盘

为什么 surface 与 raw log 分开

  • 模型面向的消费者读 session.surface(已应用压缩替换后的投影);
  • 人类 transcript(文本记录)读追加来源事件而非 surface——因为"落地的替换会遮蔽读者已经看过的历史";
  • 原始 assistant/chunk 事件保证回放与 UI 保真

不变式:模型可见即已记录

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

出处:docs/architecture.mddeepseek-harness-src/docs/architecture.md

这条不变式的工程后果:

  • 新增模型可见输入(如 plan 状态、preset 切换、目标状态)必须新增会话事件并在日志中渲染;
  • 仓库级约定把其提升为强制项:"Model-visible ⟺ logged: anything that reaches a model request must be reconstructable from the session log"(AGENTS.md);
  • 例证:plan 模式切换追加 plan/mode 事件;agent preset 切换追加 agent-preset/selected 事件;goal 每次变更追加 goal/change 事件。

从日志派生的下游

事件日志是"一处写入、多处派生"的枢纽:

下游派生方式
模型历史deriveMessages() 增量投影
恢复(resume)从持久化日志重建会话,轮次编号与派生历史延续
forkctx.sessions.fork(source, boundary?, childSessionId?) 以 boundary 之前缀建子会话(要求边界外不在开着的轮次内),携带 lineage 元数据
transcript / 遥测订阅 session/event 消费
会话标题ctx.sessionTitle 从日志折叠
投影(projection)dsh-session-projection 注册折叠单元(fold unit),如 plan、todo 状态
压缩(compaction)把一段 surface 节点总结为单个替换节点(见 3.9

出处:packages/core/session/README.mdpackages/session/session-projection/README.md

持久化:seam 而非内置

会话存储故意不实现持久化——它通过 session/event 发布事件,插件(持久化后端)在 session/flush 时落盘:

  • 后端:dsh-session-persistence-jsonl(JSONL)与 dsh-session-persistence-sqlite(SQLite),共享同一 SessionEvent 词汇;
  • 应用在组合时选择后端;
  • 恢复要求持久化后端存在(非硬注入——无持久化的演示仍可运行,resume 在无持久化时给出明确报错)。

出处:packages/session/session-persistence/README.mddeepseek-harness-src/packages/session/session-persistence/README.md

不变式伴侣:dsh-invariants

DSH 把关键关系断言注册到 ctx.invariantsruntime-diagnostics/invariants),由各包的 ./invariant 伴生子路径贡献:

  • dsh-session/invariant:单调序列号、轮次/步骤包裹、同步骤工具调用/结果配对;
  • dsh-agent/invariantdsh-agent-loop/invariant:agent 状态转换、请求重建检查;
  • dsh-goal/invariant:goal 变更的 revision 连续、生命周期合法迁移、时间戳不倒退。

出处:packages/runtime-diagnostics/invariants/README.mddocs/subsystems/invariants.md

小结

会话日志是 DSH 的"真相中枢":模型历史、持久化、fork、压缩、标题、投影全部从它派生;"模型可见即已记录"则保证日志的完整性。下一部分 2.5 会话持久化 将深入持久化、恢复与投影的机制。

参考资料

本文档为学习用途的原创讲解,基于 MIT 许可的开源项目 deepseek-ai/deepseek-harness 编写;所有引用均注明出处。