第 6 章:Session Log 与派生上下文
本章解决的问题
普通聊天产品把消息数组当真相。DeepSeek Harness 把只追加事件日志当真相。这一章解释这种设计为什么适合 Agent。
交互图解:Session Log、Surface 与多种投影 · 查看图解导读
大白话理解
Session Log 就像 Git 历史:
- 每次发生的事都追加一条记录。
- 当前视图由历史推导出来。
- 可以回放、分叉和审计。
模型的上下文不是额外保存的一份聊天数组,而是从日志中派生的。
必须掌握的概念
1. Append-only Log
事件一旦写入就不修改。事件包括:
turn/startstep/startuser/messageassistant/chunkassistant/messagetool/calltool/resultstep/endturn/end
2. Surface Event
不是所有事件都会进入模型历史。
会进入模型历史的事件主要是:
user/messageassistant/messagetool/result
assistant/chunk 用于流式展示和回放,不直接作为下一条模型消息。
3. deriveMessages
deriveMessages() 从 surface 节点投影出模型历史。
4. Model-visible 等价于 Logged
任何送给模型的内容都必须能从日志重建。这个原则保证 UI、回放、审计和模型看到的内容一致。
DeepSeek Harness 对应实现
DeepSeek Harness 的 Session 是事件日志,SurfaceManager 维护模型可见 surface。
deriveMessages() 只处理 surface 节点。assistant/chunk 保留原始流,assistant/message 是组装后的模型消息。
这个设计的价值:
- 用户看到的聊天记录来自日志。
- 模型看到的历史来自 surface。
- 持久化保存原始事件。
- 回放、标题、遥测和投影都基于同一份日志。
进一步阅读:
packages/core/session/src/index.tspackages/core/session/src/surface.ts
代码示例
下面用简化 TypeScript 表达事件日志和派生历史。
ts
type SessionEvent =
| { type: 'user/message'; content: string }
| { type: 'assistant/chunk'; text: string }
| { type: 'assistant/message'; content: string }
| { type: 'tool/result'; name: string; content: string }
class SessionLog {
private events: SessionEvent[] = []
append(event: SessionEvent): void {
this.events.push(event)
}
deriveMessages(): Array<{ role: string; content: string }> {
const messages: Array<{ role: string; content: string }> = []
for (const event of this.events) {
if (event.type === 'user/message') {
messages.push({ role: 'user', content: event.content })
}
if (event.type === 'assistant/message') {
messages.push({ role: 'assistant', content: event.content })
}
if (event.type === 'tool/result') {
messages.push({
role: 'tool',
content: `${event.name}: ${event.content}`,
})
}
}
return messages
}
}注意,assistant/chunk 保留在日志中,但没有被 deriveMessages() 放进模型历史。
面试怎么问
问:会话记录和模型上下文有什么区别?
回答要点:
- 会话记录用于 UI、审计、回放。
- 模型上下文是真正发给模型的消息。
- 不是每条 UI 记录都要发给模型。
- 可以用日志派生模型上下文。
问:为什么模型可见内容必须可重建?
回答要点:
- 回放时要知道模型当时看到什么。
- 调试和审计需要完整输入。
- 恢复会话不能只靠 UI 文本。
- 前端展示和模型上下文不能漂移。
问:前端如何消费事件日志?
回答要点:
- 订阅
session/event。 - 把边界、消息、chunk 和工具结果映射成 UI 节点。
- 保持原始事件和 UI 节点的对应关系。
- 流式 token 高频时合批更新。
自测题
- 为什么
assistant/chunk不直接进入模型历史? deriveMessages()的作用是什么?- 只追加日志适合解决什么场景?
- 前端显示聊天记录时,为什么最好从事件日志投影?
本章小结
Agent 产品里,会话日志是“真相”,模型上下文和前端 UI 都是投影。这个设计让回放、恢复、审计和 UI 保持同源。
进一步阅读:
packages/core/session/src/types.tsdocs/subsystems/session.md