← 返回目录

第 1 卷

第 1 / 6 卷日期:

张嘉熙 · DeepSeek Harness 前沿工程实践

图 1-1
图 1-1
图 1-2
图 1-2
图 1-3
图 1-3

你好,我是张嘉熙。

上一讲把会话日志本身讲透了:只追加、进日志即冻结、消息历史是从它算出来的投影。但它留了两个口子,这本账记在什么纸上(怎么落盘),以及会话怎么续接。这一讲把两件一起接

上:先把纸铺好,再看能用它做些什么。

但要把这本账真正用起来,问题就一个接一个冒出来:

这本账自己的信息,又放哪儿?

进程退出后再起来,这本账还在吗?

能不能从历史中间岔出去另开一个会话,原来那个不受影响?

跑到一半进程死了,已经写进日志的那些还算吗?

关于环境:本讲新增两个包——@deepseek-ai/dsh-session-persistence(持久化 seam 的抽象定义)与 @deepseek-ai/dsh-session-persistence-jsonl(JSONL

后端实现),已加入本项目的 package.json,npm install --legacy-peer-deps 装上即可。

关于示例:npm run start:ch09:fork 跑 fork,npm run start:ch09:crash 跑崩溃与恢复。

SessionHeader:日志旁的元数据

第一个问题:这本账自己的信息,放哪儿?

一本账要能存下来、过后再打开,光有一串事件还不够:这本账自己还有一批信息要交代。

格式版本、工作目录(cwd)、从哪个会话分出来的、前多少条是继承来的,这些不是事件,所以不进上一讲那张事件类型表(SessionEventMap),也永远算不进消息历史

(deriveMessages())。它们跟事件流分开存,挂在 session.header 上:

复制代码 1interface SessionHeader {

2readonly version: number*// 落盘格式版本;本构建不认识就拒绝打开*readonly 3}

这些字段什么时候定下来?

建会话的那一刻,也就是下一节要讲到的“创建”(create(meta)),它的 meta 参数正是这份 header。所以是先后两步:建会话时先把“这本账是什么、从哪来、按什么格式记”写

定;此后 append 只管往事件流里加事件,一次都不会碰它。

“打不开”其实分两种:读不懂(SessionFormatUnsupportedError,数据好好的、只是

持久化:先把日志交到纸上

第二个问题:进程退出后再起来,这本账还在吗?

上一讲说过,dsh-session 只认那一串事件,落在哪里是另一层的事。这另一层是一个能力 seam:框架定义抽象服务,具体实现可换。整个契约只有六个动作——建、写、读、看、

续、起,本讲会挨个遇上:

复制代码 1abstract class SessionPersistence {

2//建:登记一个会话,但还不建文件——要等第一次写*abstract create(meta: SessionHeader):
3//写:返回成功,就代表事件已经真的写到磁盘了*abstract append(id: SessionId, events: r
4//读:读回来,顺带把没闭合的轮次配平——配平结果会写回磁盘*abstract load(id: SessionId):
5//看:同样配平,但只在内存里做,一个字节都不写*abstract inspect(id: SessionId): Promi
6//续:给投影续算用的——只读fromSeq之后那一段,不必翻整本*abstract readFrom(id: Sessio
7//起:resume的正规入口,直接给你一个Session对象*abstract prepare(id: SessionId):
8// ...
9}</sessionpreparation></sessioninspection></sessioninspection></void></void>

抽象得有人实现。官方给了两个,它们的名字上一讲在“介质可换”那里已经露过面,但只说了名字;这里我们补的是它们各自的磁盘布局:

后端磁盘布局

每个会话一份仅追加的日志文件。默认是压缩过的 .jsonl.zstd(Zstandard 格 JSONL 式,带校验和),也可配成不压缩的原始文本

每个事件一行,行字段 (session_id, seq, type, time, data, SQLite source_event_seqs, surface_op) 与事件 1:1 映射

JSONL 默认是压缩的,这一点你先在这里记一下:它决定了崩溃时磁盘上留下的是什么,一

全站分卷索引 · 6 卷
  1. 1第 1 卷
  2. 2第 2 卷
  3. 3第 3 卷
  4. 4第 4 卷
  5. 5第 5 卷
  6. 6第 6 卷