02 基准、快照与纪元三件套


文档摘要

02 基准、快照与纪元三件套 本节摘要:上一节讲了上下文源怎么组合成 System Context,但组合完之后,怎么让它「稳定」——稳定到可以作为模型缓存的前缀、稳定到变化能被检测?OpenCode 的答案是三件套:基准(Baseline)、快照(Snapshot)、纪元(Epoch)。基准是精确文本(作为模型缓存前缀,所以必须稳定),快照是模型不可见的 JSON(用来 diff 出「什么变了」),纪元是一段不可变的有效期(压缩或会话移动时结束)。本节讲清这三件套各自的角色,以及它们如何协作让 System Context「既稳定又可演化」。 一、稳定性问题:为什么需要三件套 先看问题。第 6 章讲过 Prompt Caching——模型会缓存稳定的前缀,重复读取成本极低(约 0.1×)。

02 基准、快照与纪元三件套

本节摘要:上一节讲了上下文源怎么组合成 System Context,但组合完之后,怎么让它「稳定」——稳定到可以作为模型缓存的前缀、稳定到变化能被检测?OpenCode 的答案是三件套:基准(Baseline)、快照(Snapshot)、纪元(Epoch)。基准是精确文本(作为模型缓存前缀,所以必须稳定),快照是模型不可见的 JSON(用来 diff 出「什么变了」),纪元是一段不可变的有效期(压缩或会话移动时结束)。本节讲清这三件套各自的角色,以及它们如何协作让 System Context「既稳定又可演化」。

一、稳定性问题:为什么需要三件套

先看问题。第 6 章讲过 Prompt Caching——模型会缓存稳定的前缀,重复读取成本极低(约 0.1×)。System Context 天然是「前缀」(每次回合都在最前面),所以让它稳定能省大量 token。

但 System Context 又必须能演化(对话进行中环境会变)。这就矛盾了:

  • 稳定(让缓存命中) → 不能老变
  • 演化(反映环境变化) → 必须能变

OpenCode 用三件套化解这个矛盾:在一段「纪元」内保持基准稳定(缓存命中),变化时通过 diff 检测并开新纪元(重建缓存)

二、基准(Baseline):精确的稳定文本

基准是 System Context 被渲染成的精确文本——它就是模型实际看到的初始指令文本。关键特性是:在一段纪元内,基准保持不变

纪元 N 开始 ──► 基准 = 某段精确文本 │ │ (整个纪元 N 期间,基准不变,模型缓存命中) │ 纪元 N 结束 / 纪元 N+1 开始 ──► 新基准(重新渲染)

为什么必须精确稳定?因为它直接作为模型缓存的前缀——差一个字符,缓存就失效。基准的存在,让「缓存命中」成为可能:只要还在同一纪元,模型反复读同一份基准,享受 0.1× 的低读取成本。

⚠️ 别把基准当「会变的字符串」:在纪元内它是冻结的。想变?得开新纪元(见后文)。这个「冻结」特性是缓存命中前提。

三、快照(Snapshot):模型不可见的 diff 工具

如果基准是冻结的,那怎么知道「环境变了」?靠快照。快照是 System Context 的模型不可见 JSON 表示——模型看不到它,但 OpenCode 用它来 diff:

上一回合的快照(JSON) │ ▼ 对比 这一回合的快照(JSON) │ ▼ diff 哪些上下文源变了?(key 级别)

快照和基准的分工:

基准 快照
形式 精确文本 JSON
模型可见? 是(模型看到的初始指令) 否(模型看不到)
作用 作为缓存前缀 用来 diff 检测变化
稳定性 纪元内冻结 每回合都更新(用于对比)

💡 为什么快照是 JSON 而基准是文本:JSON 适合结构化 diff(key 级别精确比较「哪个源变了」),文本适合喂给模型。各取所长。模型看不到快照,所以快照怎么变都不影响缓存(缓存只看基准文本)。

四、纪元(Epoch):不可变的有效期

纪元是三件套的「组织者」——它定义一段基准有效的不可变期。在一个纪元内:

  • 基准冻结不变(缓存命中)
  • 快照每回合更新(检测变化)
  • 如果某个源变了(快照 diff 发现),触发协调(第 04 节),决定是否开新纪元

纪元在以下情况结束,开启新纪元:

触发条件 说明
某个上下文源变化且需替换基准 环境变了,旧基准不再适用
上下文压缩(第 9 章) 压缩重写了历史,前缀变了
会话移动(换 Location,第 7 章) 新 Location 的环境信息不同
纪元 1(基准A) │ 某源变化 / 压缩 / 移动 ▼ 纪元 2(基准B) ← 新基准,模型重新建立缓存 │ ▼ ...

五、三件套如何协作

把三件套放一起看一次完整协作:

回合开始 │ ├─ 取当前各上下文源的最新事实 ├─ 生成新快照(JSON) ├─ 与上一回合快照 diff │ ├─ 无变化 ──► 继续用当前基准(缓存命中) │ └─ 有变化 ──► 触发协调(第 04 节) │ ├─ 可替换 ──► 新基准,开新纪元 │ └─ 需中途消息 ──► 第 03 节 │ ▼ 把(可能的新)基准作为前缀喂给模型 模型调用(缓存命中或重建)

这套协作实现了「既稳定又可演化」:稳定靠纪元内基准冻结,演化靠快照 diff + 协调 + 新纪元。

六、一个常见误解:纪元 ≠ 回合

新手容易把「纪元」和「回合」搞混。区别:

  • 回合(turn):一次模型调用 + 工具处理。一个会话有很多回合。
  • 纪元(epoch):一段基准有效期。一个纪元可能跨越多个回合(只要基准不变)。
会话时间轴: 回合1 回合2 回合3 │ 回合4 回合5 │ 回合6 ... │ │ 纪元1结束 纪元2结束 (基准A 跨回合1-3) (基准B 跨回合4-5)

一个纪元里多个回合共享同一基准——这正是缓存命中的来源:多个回合反复读同一份基准。

本节要点回顾

  1. 矛盾:System Context 要稳定(缓存命中)又要演化(反映环境变化)——三件套化解。
  2. 基准(Baseline):精确文本,纪元内冻结,作为模型缓存前缀。
  3. 快照(Snapshot):模型不可见的 JSON,每回合更新,用来 diff 检测变化。
  4. 纪元(Epoch):基准的不可变有效期;源变化、压缩、移动时结束,开新纪元。
  5. 协作:快照 diff → 无变化用旧基准(缓存命中)/ 有变化触发协调 → 可能开新纪元。
  6. 纪元 ≠ 回合:一个纪元跨多个回合,正是缓存命中的来源。

基准稳定能覆盖「缓慢变化」,但有个场景它处理不了——对话进行中某个源突然变化,模型必须马上知道。这就是下一节的「对话中途系统消息」。


发布者: 作者: 灏天文库 转发
评论区 (0)
U