上下文层级(L0/L1/L2)

August 24, 2026 · View on GitHub

OpenViking 使用三层信息模型,在检索效率、导航能力和原始内容完整性之间取得平衡。

概览

层级名称存储形式默认正文上限用途
L0摘要目录内的 .abstract.md256 字符向量检索、快速过滤
L1概览目录内的 .overview.md4000 字符Rerank、内容导航
L2详情原始文件和子目录无统一上限完整内容、按需加载

L0/L1 是目录级语义 sidecar。它们描述一个目录,不是为每个普通文件创建的同名伴生文件。文件摘要会作为输入,聚合到所在目录的 L1 中。

L0 和 L1 通常成对生成,但系统允许只存在其中一个。例如,mkdir() 会先创建 L0:未传入 description 时使用目录名作为默认正文,传入后使用该说明。因此只有 .abstract.md 的目录也是合法状态。读取和向量重建只处理实际存在的层级。

正文上限由 semantic.abstract_max_charssemantic.overview_max_chars 配置;上表是默认值。限制只作用于 Markdown 正文,不会截断 sidecar 元数据。

L0:摘要

L0 是目录内容的最精简表示,用于向量召回和快速相关性判断。

API 认证指南,涵盖 OAuth 2.0、JWT 令牌和 API 密钥的安全访问方式。

通过语义 accessor 读取时,只返回可见正文:

abstract = client.abstract(uri="viking://resources/docs/auth")

L1:概览

L1 提供更完整的目录摘要和导航信息,用于 Rerank 和决定是否继续加载 L2。

# 认证指南

本目录介绍 API 的主要认证方式。

## 快速导航

- `oauth.md`:OAuth 2.0 流程和代码示例
- `jwt.md`:令牌生成和验证
- `api-keys.md`:API Key 认证
overview = client.overview(uri="viking://resources/docs/auth")

L0 从 L1 正文中提取:取 H1 标题之后、第一个 ## 标题之前的 Brief Description 段落。YAML frontmatter 不参与提取。

L2:详情

L2 是原始文件或解析后的完整内容,只在需要时加载,并保留源格式和结构。

content = client.read(uri="viking://resources/docs/auth/oauth.md")

目录结构

一个已完成语义处理的目录通常如下:

viking://resources/docs/auth/
├── .abstract.md          # L0,隐藏的目录级 sidecar
├── .overview.md          # L1,隐藏的目录级 sidecar
├── oauth.md              # L2,完整内容
├── jwt.md                # L2,完整内容
└── api-keys.md           # L2,完整内容

普通 ls 默认隐藏 .abstract.md.overview.md。它们不一定同时存在;不要依赖“每个目录始终具有两个 sidecar”的假设。

OKF sidecar 格式

新生成的 L0/L1 使用最小 OKF Markdown:YAML frontmatter 加可见 Markdown 正文。

---
directory: viking://resources/docs/auth/
source:
  kind: http
  uri: https://example.com/auth.pdf
generated_by:
  component: SemanticProcessor
  trigger: resource_ingest
freshness:
  total_entries: 3
  sampled_entries: 3
  unsampled_entries: 0
  pending_child_changes: 0
---

API 认证指南,涵盖 OAuth 2.0、JWT 令牌和 API 密钥。

初始元数据字段如下:

字段含义
directorysidecar 所描述的目录 URI
source可选的导入来源;通常只记录在导入根目录
generated_by生成组件和粗粒度触发原因
freshness直接子项覆盖率和已知的待刷新变化

已知字段会进行 schema 校验。未知顶层字段或已知对象中的未知嵌套字段会被静默丢弃,不会进入 preview、embedding、canonical writeback 或 metadata 写保护比较。没有 frontmatter 的旧 sidecar 继续作为 legacy Markdown 读取;YAML 损坏、缺少必填 directory 或已知字段类型错误仍会显式失败。

不同读取表面的行为

同一个 sidecar 在不同表面返回不同视图:

访问方式返回内容
abstract() / overview()仅 Markdown 正文
find、search/rerank preview仅 Markdown 正文
ls output=agent、tree agent 输出仅 Markdown 正文
直接 read(".../.abstract.md")原始 frontmatter 和正文
普通 ls默认不列出隐藏 sidecar

语义生成父目录摘要时也只读取子目录 L0 的正文,sourcegenerated_byfreshness 不会进入总结 prompt。

Embedding 元数据白名单

L0/L1 的 embedding 输入由正文和显式白名单元数据组成。当前白名单只有 directory

---
directory: viking://resources/docs/auth/
---

API 认证指南,涵盖 OAuth 2.0、JWT 令牌和 API 密钥。

sourcegenerated_byfreshness 以及未知字段都不会进入 embedding。正常向量化和 admin vectors_only reindex 使用相同策略,避免重建索引后改变检索输入。L1 的 rerank scalar 仍然是纯 L1 正文。

Freshness 与稳定采样

freshness 统计当前目录的直接子项,而不是整个递归子树:

  • total_entries:参与目录语义的直接文件和直接子目录总数。
  • sampled_entries:本轮实际用于总结的直接子项数。
  • unsampled_entries:未采样的直接子项数,满足 sampled + unsampled = total
  • pending_child_changes:已知发生变化、但尚未反映到当前正文中的直接子项数。

当直接子项超过 semantic.overview_sample_limit(默认 32)时,系统使用确定性、保序的稳定采样。相同目录树重复刷新会选择相同样本,避免无意义的正文和 Git diff 抖动。

pending_child_changes > 0 表示正文仍然可读,但已知落后于下层变化。父目录刷新成功后,该值会随新的覆盖率元数据重置为 0。

当前 resource/skill 语义任务成功后会逐级安排父目录刷新,并在入队前将父目录标记为 pending,直到 namespace 根边界。

TODO:基于 freshness 控制冒泡频率

当前实现会在每次成功的 resource/skill 语义任务后尝试向父级冒泡,即使新生成的子目录摘要与旧值相同。这不是最终期望的调度策略。后续应利用 freshness 数据实现合并、阈值或时间窗口节流,例如综合 pending_child_changes、采样覆盖率、直接子项变化规模和最近刷新状态,降低热点目录的重复刷新与向上写放大,同时保证最终一致性。

写保护

L0/L1 正文可以通过公共 write / batch_write 更新,但 metadata 受保护:

  • 目标 sidecar 必须已存在;公共 API 不允许直接创建新的 .abstract.md / .overview.md
  • 只提交正文时,系统保留现有 metadata 并重新拼回 canonical OKF。
  • 提交完整 OKF 时,已知 metadata 必须与现有值一致;修改受保护字段会失败。
  • 未知 metadata 字段会静默丢弃。
  • append 只追加正文,不会把用户内容追加到 frontmatter。
  • 正文更新只重建该目录实际存在的 L0/L1 向量,不触发语义重新生成,避免刚写入的正文被覆盖。

生成机制

SemanticProcessor 自底向上处理目录:

文件摘要 → 叶子目录 L1 → 叶子目录 L0 → 父目录 → namespace 根边界

子目录 L0 被聚合到父目录 L1。Memory 目录也通过统一的 SemanticProcessor 入口处理,但当前父级冒泡逻辑只用于 resource/skill。多模态文件会先生成文本摘要,再作为普通文件摘要参与其所在目录的 L0/L1;不会为每个图片、音频或视频创建 per-file L0/L1 sidecar。

最佳实践

场景推荐层级
快速相关性检查L0
理解目录内容范围L1
详细信息提取L2
为 LLM 构建初步上下文L1,必要时再加载 L2
检查 sidecar 来源或 freshness直接读取 sidecar 原始内容

相关文档