第九章:持久化与数据平面 本章目标 :帮助你理解 Session 生命周期、日志格式与版本管理、持久化后端、查询、Compaction 和 Python SDK 对接。阅读本章后,你应该能回答"会话数据是如何持久化的"以及"如何扩展持久化后端"。
9.1 Session 生命周期 9.1.1 概念Session 是一次 Agent 与用户的完整交互。它包含:
SessionHeader :元数据
SessionEventLog :仅追加的事件流
内存状态 :运行时投影
9.1.2 Session 创建
class Session {
constructor ( options: CreateSessionOptions) {
this . id = options. id ?? generateSessionId ( )
this . header = {
id: this . id,
createdAt: new Date ( ) ,
cwd: options. cwd,
}
this . log = new SessionEventLog ( )
}
}
interface SessionHeader {
id: SessionId
createdAt: Date
cwd? : string
parentSession? : SessionId
isSeeded? : boolean
origin? : 'subagent'
delegationDepth? : number
agentPreset? : string
}
9.2 日志格式 9.2.1 仅追加日志Session 日志是仅追加 的事件流。这是 dsh 的核心设计原则之一:
Model-visible ⟺ logged ——任何到达模型请求的内容都必须可从日志重建。
9.2.2 SessionEvent 类型
type SessionEvent =
| TurnStartEvent
| TurnEndEvent
| StepStartEvent
| StepEndEvent
| UserMessageEvent
| AssistantMessageEvent
| AssistantChunkEvent
| ToolCallEvent
| ToolResultEvent
| RequestHeaderEvent
9.2.3 事件示例
interface UserMessageEvent {
type: 'user/message'
seq: SessionSeq
data: {
content: string
}
}
interface AssistantMessageEvent {
type: 'assistant/message'
seq: SessionSeq
data: {
content: string
toolCalls? : ToolCall[ ]
}
}
interface ToolCallEvent {
type: 'tool/call'
seq: SessionSeq
data: {
name: string
parameters: Record< string , unknown >
}
}
9.2.4 SessionSeq
type SessionSeq = number & { __brand: 'SessionSeq' }
function SessionSeq ( value: number ) : SessionSeq {
return value as SessionSeq
}
每个事件都有一个单调递增的序列号(seq),用于排序和投影。
9.3 持久化后端 9.3.1 架构 9.3.2 SessionPersistence 接口
interface SessionPersistence {
create ( options: CreateSessionOptions) : Promise < SessionHandle>
open ( sessionId: SessionId) : Promise < SessionHandle>
stat ( sessionId: SessionId) : Promise < SessionStat | null >
list ( options? : ListOptions) : Promise < SessionHeader[ ] >
export ( sessionId: SessionId) : Promise < ExportedSession>
}
9.3.3 SessionHandle
interface SessionHandle {
readonly id: SessionId
read ( offset? : SessionLogOffset) : AsyncIterable< SessionEvent>
append ( events: SessionEvent[ ] ) : Promise < void >
header ( ) : SessionHeader
close ( ) : Promise < void >
}
9.3.4 JSONL 后端
class JsonlSessionHandle implements SessionHandle {
private logFile: string
constructor (
private sessionId: SessionId,
private dir: string
) {
this . logFile = join ( dir, ` ${ sessionId} .jsonl ` )
}
async append ( events: SessionEvent[ ] ) : Promise < void > {
const lines = events. map ( e => JSON . stringify ( e) ) . join ( '\n' ) + '\n'
await appendFile ( this . logFile, lines)
}
async * read ( offset? : SessionLogOffset) : AsyncIterable< SessionEvent> {
const content = await readFile ( this . logFile, 'utf-8' )
const lines = content. split ( '\n' ) . filter ( Boolean)
for ( const line of lines) {
const event = JSON . parse ( line) as SessionEvent
if ( offset === undefined || event. seq > offset) {
yield event
}
}
}
}
9.4 日志版本管理dsh 使用 SESSION_FORMAT_VERSION 来管理日志格式的兼容性:
const SESSION_FORMAT_VERSION = 0
当前版本为 0 ,表示没有兼容性承诺。每次格式变更都会递增版本号。
9.4.2 版本检查
function validateSessionLog ( log: SessionEventLog) : boolean {
if ( log. version !== SESSION_FORMAT_VERSION ) {
throw new Error ( ` Incompatible session log version: ${ log. version} ` )
}
return true
}
9.5 Session 投影 9.5.1 概念Session 投影从日志增量派生状态。这是 dsh 的数据平面 核心。
9.5.2 ProjectionDefinition
interface ProjectionDefinition< K extends string , S > {
key: K
stateVersion: number
stateSchema: ZodType< S >
init ( ) : S
apply ( state: S , event: SessionEvent) : S
}
9.5.3 turnBoundary 投影
const turnBoundaryProjectionDefinition = {
key: 'turnBoundary' ,
stateVersion: 2 ,
stateSchema: zod. object ( {
openTurnStartSeq: zod. number ( ) . nullable ( ) ,
lastStepStartSeq: zod. number ( ) . nullable ( ) ,
lastStepBoundary: zod. object ( {
kind: zod. union ( [ zod. literal ( 'start' ) , zod. literal ( 'end' ) ] ) ,
seq: zod. number ( )
} ) . nullable ( ) ,
lastTurn: zod. number ( )
} ) ,
init : ( ) => ( {
openTurnStartSeq: null ,
lastStepStartSeq: null ,
lastStepBoundary: null ,
lastTurn: 0
} ) ,
apply : ( state, event) => {
switch ( event. type) {
case 'turn/start' :
return { ... state, openTurnStartSeq: event. seq, lastTurn: event. data. turn }
case 'turn/end' :
return { ... state, openTurnStartSeq: null }
case 'step/start' :
return { ... state, lastStepStartSeq: event. seq, lastStepBoundary: { kind: 'start' , seq: event. seq } }
case 'step/end' :
return { ... state, lastStepBoundary: { kind: 'end' , seq: event. seq } }
default :
return state
}
}
}
9.5.4 使用投影
const state = stateOf ( 'turnBoundary' )
const snapshot = snapshot ( [ 'turnBoundary' , 'otherProjection' ] )
9.6 Compaction(压缩) 9.6.1 概念Compaction 机制在上下文窗口溢出时压缩历史消息:
9.6.2 CompactionEngine
class CompactionEngine {
constructor ( private ctx: Context) { }
async needsCompaction ( session: Session) : Promise < boolean > {
const contextSize = this . calculateContextSize ( session)
const maxSize = this . getMaxContextSize ( )
return contextSize > maxSize
}
async compact ( session: Session) : Promise < CompactionResult> {
const messagesToCompact = this . selectMessages ( session)
const summary = await this . generateSummary ( messagesToCompact)
const compactedSession = this . replaceMessages ( session, messagesToCompact, summary)
return { session: compactedSession, summary }
}
}
9.6.3 Compaction 策略
interface CompactionStrategy {
selectMessages ( session: Session) : SessionEvent[ ]
generateSummary ( messages: SessionEvent[ ] ) : Promise < string >
replaceMessages (
session: Session,
original: SessionEvent[ ] ,
summary: string
) : Session
}
9.7 Session 查询 9.7.1 架构 9.7.2 查询接口
interface SessionQueryService {
list ( options? : ListOptions) : Promise < SessionHeader[ ] >
inspect ( sessionId: SessionId) : Promise < SessionSnapshot>
search ( query: string ) : Promise < SessionSearchResult[ ] >
readLog ( sessionId: SessionId, options? : ReadOptions) : Promise < SessionEvent[ ] >
}
9.7.3 语义搜索
class SessionCorpus {
async semanticSearch ( query: string ) : Promise < SearchResult[ ] > {
const queryEmbedding = await this . embed ( query)
const results = await this . vectorStore. search ( queryEmbedding, {
limit: 10 ,
threshold: 0.7
} )
return results
}
}
9.8 Python SDK 对接 9.8.1 架构 9.8.2 Python SDK 使用
from deepseek_harness import HarnessClient
client = HarnessClient( profile= 'sdk' )
session = client. create_session( )
response = client. send_message( session. id , 'Hello, world!' )
print ( response. content)
sessions = client. list_sessions( )
9.8.3 SDK 服务器
class HarnessSdkJsonRpcServer {
constructor ( private ctx: Context) { }
async initialize ( ) : Promise < void > {
this . registerMethods ( )
await this . startServer ( )
}
private registerMethods ( ) : void {
this . server. method ( 'session.create' , this . createSession . bind ( this ) )
this . server. method ( 'session.list' , this . listSessions . bind ( this ) )
this . server. method ( 'session.send' , this . sendMessage . bind ( this ) )
}
}
9.9 遥测 9.9.1 架构 9.9.2 遥测事件
class OpenTelemetryTelemetryProvider {
recordEvent ( event: SessionEvent) : void {
const span = this . tracer. startSpan ( 'session.event' , {
attributes: {
'session.id' : event. sessionId,
'event.type' : event. type,
'event.seq' : event. seq
}
} )
span. end ( )
}
recordLlmCall ( call: LlmCall) : void {
const span = this . tracer. startSpan ( 'llm.call' , {
attributes: {
'llm.model' : call. model,
'llm.tokens.input' : call. inputTokens,
'llm.tokens.output' : call. outputTokens,
'llm.duration' : call. duration
}
} )
span. end ( )
}
}
9.10 小结
概念 一句话解释 Session 一次 Agent 与用户的完整交互 SessionEventLog 仅追加的事件流 SessionHeader 会话元数据 SessionSeq 事件序列号 SessionPersistence 持久化接口 Projection 从日志增量派生状态 Compaction 上下文窗口溢出时压缩历史 SESSION_FORMAT_VERSION 日志格式版本管理
9.11 完整教程总结恭喜你完成了 DeepSeek Harness 教程的全部九章!让我们回顾一下你学到的内容:
核心概念总体架构 :dsh 是全插件化的 Agent 运行时
环境与运行 :Profile 系统、CLI 启动链、构建系统
Cordis 框架 :Plugin/Service/Context 模型、事件派发
Agent 循环 :Turn/Step 生命周期、Cancel 机制
LLM 能力 :适配器机制、流式调用、重试策略
工具能力 :三角色模式、执行管道、能力插件
Agent 编排 :Subagent、Worker Thread、Workflow
人类协作 :Approval、Questions、Guard、Plan
持久化 :Session、日志、投影、Compaction
下一步实践 :尝试修改一个插件或添加新功能
深入源码 :使用 GitNexus 探索更多细节
贡献 :参与 dsh 的开发和改进
参考资源本教程基于 DeepSeek Harness 源码编写,内容可能随项目更新而变化。