首页 / DeepSeek Harness 入门教程 / 会话与消息模型

DeepSeek Harness 入门教程

会话与消息模型

本教程共 32 篇 · 第 10 篇 · 更新于 2026-08-15 · 约 6 分钟阅读

Session事件日志turnstep消息模型

本节目标:理解会话(Session)是「仅追加事件日志 + 内存存储」,学会 turn/step 边界与消息词汇,知道模型历史是怎么从日志派生的。

你有没有想过:模型看到的那段对话历史,到底存在哪里?dsh 的答案很特别:没有专门的地方存。历史从一份仅追加的会话事件日志里派生出来。这就是本节要讲的核心模型。

会话:一份仅追加的事件日志

会话是一份由类型化 SessionEvent 组成的仅追加日志,由 core/session 包提供,通过 ctx.sessions 访问(内存存储)。它是 Agent 完整交互历史的唯一真源。LLM 消息历史从日志派生,从不单独存储;回放就是重新从同一组事件派生历史。可以想成监控录像:画面不是另存的截图,而是每次从录像带重新剪出来的。

日志里的每个事件都有单调递增的 seqseq = log.length)和毫秒级 time。所有事件数据都必须能无损序列化为 JSON,Session.append 在源头强制这一点。

为什么用仅追加设计?因为派生性:恢复、fork(分叉)、transcript(文字记录)、遥测、持久化全部从这条事件流派生。日志是账本,谁也不能改账——只能往后记。会话日志里混进脏数据,比代码 bug 难查得多,所以 dsh 把「只能追加」做成了硬约束。

事件词汇:日志里记什么

SessionEventMap 是合并可扩展的事件词汇表。最常用的一批:

事件携带数据含义
turn/start / turn/end{ turn } / { turn, reason }轮次开闭,reason 如 completed / aborted / max-tokens
step/start / step/end{ turn, step }步骤开闭
user/messageUserMessage用户消息:直接提示、注入上下文、steering
assistant/chunk{ turn, step, chunk }原始流式分片,token 级回放保真
assistant/message{ turn, step, message, usage? }组装后的 assistant 消息(派生历史用它)
tool/call{ turn, step, callId, name, arguments }模型请求的一次工具调用
tool/result{ turn, step, message, error?, meta? }工具调用的模型可见结果

插件可以扩展这个词汇表:通过 TypeScript 声明合并声明新事件类型。例如 compaction seam 添加了 compaction/startcompaction/summarycompaction/end

turn 与 step:执行边界

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

turn/start
  claim next-step input
  assemble prompt sections + tool schemas
  step/start
  user/message → agent/request → llm/stream → assistant/chunk* → assistant/message
  tool/call* → tools/pre-execute → tools/execute → tools/post-execute → tool/result*
  step/end
turn/end

注意:轮次包围一次模型循环执行,不是整个会话。一个「帮我看代码 → 读文件 → 改文件 → 再跑测试」的完整任务,可能是多轮、多 step 的组合。

模型历史:从日志派生

Session.deriveMessages() 把事件日志投影成模型看到的 Message[]。投影规则很直接:

事件投影为
user/message一条 user 消息
assistant/message一条 assistant 消息
tool/result一条带 tool-result 块的 user 角色消息
assistant/chunk跳过(属于回放/UI 数据)
turn/*step/*跳过(结构信息)

由此得到 dsh 最重要的一条运行时不变量:

模型可见即已记录。 抵达模型请求的一切都必须能从日志重建。因此,新增一项模型可见输入,就需要新增一个会话事件——扩展 SessionEventMap 并从日志渲染。

人话版:模型看到什么,完全由投影规则决定。想给模型加一种新输入,就要先在日志里给它一个位置。

这条不变量由运行时不变量服务断言。它的推论很实用:你没法悄悄塞给模型一段不出现在日志里的上下文。凡是声称影响后续模型的数据,都必须能由持久日志重建。

消息词汇:Message 与内容块

模型请求与持久历史共用同一套消息表示。一条 Message 带稳定 id、角色(system / user / assistant)和一个内容块数组。内容块类型可合并扩展:

text(文本) | reasoning(思考) | image(图片附件)
| tool-call(工具调用) | tool-result(工具结果)

assistant 消息还携带来源信息(AssistantProvenance):产生它的 provider 与 model,以及可选的适配器私有回放数据。也就是说,一条 assistant 消息自带「身世」,回放时知道找谁还原。

inbox:输入怎么到达驱动器

所有输入通过同一个 inbox 到达 agent loop 驱动器。有些消息会立即唤醒它。注入的上下文(文件变更通知、AGENTS.md、skill 内容、定时提醒)会留在 inbox 里,等另一条消息来唤醒。agent/pre-step 决定模型看到什么:监听器可以改写已领取的消息,也可以直接拒绝。首次领取被拒绝或被改写为空时,仍会关闭一个不含 step 的持久轮次——日志会记录这次尝试。

会话事件如何广播

会话事件追加进日志后,还会通过 Cordis 事件 session/event 广播。需要实时反应的消费方(UI 渲染、持久化、遥测、标题生成)监听这个事件;需要回放 transcript 的 SDK 用户也消费这条事件流。持久化到 JSONL / SQLite 是另一个 seam(ctx.sessionPersistence),细节在第 18 章展开。

Tip

初学者常问「模型看到的历史和 Trajectory 视图怎么不一样」。原因就在投影规则:模型只看 user/messageassistant/messagetool/result 三类 surface 事件;assistant/chunk、边界事件、请求上下文是观测与回放数据,不进模型历史。被记录 ≠ 模型可见。

Warning

版本基线 @deepseek-ai/dsh 0.1.0-rc.6 处于 Developer Preview,事件词汇会随版本增减。完整 SessionEventMap 以官方 session 子系统文档为准。

小结

  • 会话是仅追加的类型化事件日志,是交互历史的唯一真源。
  • 模型历史由 deriveMessages() 从日志投影,从不单独存储。
  • 常用事件词汇:turn/*step/*user/messageassistant/*tool/calltool/result
  • 「模型可见即已记录」:新增模型可见输入,就要新增会话事件。
  • 日志通过 session/event 广播;持久化是另一个 seam(第 18 章展开)。