第 2 卷
方法输入用途返回
一串 Se listSessions()不用传列出所有会话(只看 header,不读事件)
live/per
克隆 he readSession(id)一个会话 id读出这个会话的整份日志:header + 全部事件回)
轻量事件 listEvents(id)一个会话 id列出这个会话的每条事件,并标注它现在算哪一类 shadow
克隆 he readSurface(id)一个会话 id读出这个会话当前的表层(模型眼前那部分)
第几条
跑 npm run start:ch11:corpus,把这四个读方法依次走一遍:
3· sess-alive=truepersisted=false 4· sess-blive=truepersisted=false
5--- readSession:读完整日志 --- 6sess-a:共 8 条事件
| 7 | 类型序列:turn/start→user/message → assistant/message → turn/end→ turn/start→ |
|---|---|
| 8 | --- listEvents:列带归属的事件--- |
| 9 | seq0 turn/start surface=log-only |
| 10 | seq1 user/message surface=current |
| 11 | seq2 assistant/message surface=current |
| 12 | seq3 turn/end surface=log-only |
| 13 | seq4 turn/start surface=log-only |
| 14 | seq5 user/message surface=current |
| 15 | seq6 assistant/message surface=current |
| 16 | seq7 turn/end surface=log-only |
| 17 | --- readSurface:当前surface快照--- |
| 18 | 截到seq:7 |
| 19 | surface上还剩4条(只剩还在模型眼前的,结构事件不在内) |
四个读方法里只有 listSessions 是跨会话的(一次列出所有,不用给 id);对应的带过滤条件的方法是 filterSessions,那个属于“过滤”一类、不在上面四个之列,到第三节讲。
readSession 交出完整的 8 条,连 turn/start 这类结构事件都在内。
listEvents 返回的 surface 归属有三个取值:current(还在模型眼前)、shadowed (被替换掉了,比如第 10 讲压缩换掉的旧消息)、log-only(从没浮上来,比如上面示例
里的 turn/start、turn/end)。下面“搜”的两节会反复用到。
readSurface 只剩 4 条:比 readSession 少的,正是那些从没浮上 surface 的结构事件。同一份日志,问法不同,拿到的东⻄就不同。
全文搜索:搜什么、怎么搜、拿到什么
第二个问题:怎么搜出“聊过 X”的那个会话?
事项,以及 turn 的结束原因。
其中两项要多说一句:工具结果除了内容本身,还会把报错的 error 名和 code 一起收进去,因此按错误码也能搜到它;turn 的结束原因也算文本(error、aborted、max-tokens、
interrupted 都能搜),唯独正常结束(completed)不带任何文字。
反过来,这几类东⻄搜不到:结构事件(turn/start、step/start、step/end)、流式分片(assistant/chunk)、请求头、消息里的推理(reasoning)块,以及尚未定义语义
的新事件、新块。一句话:它搜的是“内容”,不是“⻣架”;内容里只有推理(reasoning)块例外,它虽是内容,却不进索引。
搜哪些会话?
能搜什么说完了,接着看范围。搜索的两个入口同样挂在 ctx.sessionQuery 上,区别是搜哪些会话。本讲的主角是跨会话的 searchSessions():一次搜遍所有会话,返回的是会
话(命中的事件按会话归拢,一个会话一条);作为对照的 searchEvents() 只在指定的那一个会话里搜,返回的是事件(一条命中一条)。
这里顺便聊一聊搜多深。上面那维决定的是“搜多宽”,这一维则是“深度”:第一节列 listEvents 时讲过的三种归属,全文搜索默认三种都搜,所以你搜得到已经被压缩掉的
历史(shadowed 的那些)。这是“搜”比只读 surface 看得更全的地方。只想搜当前上下文,就加一个 surface 过滤器收窄到 current。
怎么匹配?
searchSessions() 和 searchEvents() 用的都是全文检索(full-text search,下称 FTS),靠 SQLite 自带的 FTS5 模块建索引。
注意,它匹配的是 token,不是任意子串。下面我们马上用例子拆开看。