Skip to content

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

OpenViking 用摘要和概览定位内容,需要细节时再读取正文。这三个层级分别称为 L0、L1 和 L2。

概览 ​

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

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

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

资源目录摘要的生成预算按字符计算,由 semantic.abstract_max_chars 和 semantic.overview_max_chars 配置;上表是默认值。预算作用于生成的 Markdown 正文,不包含 sidecar 元数据。

截断优先保留完整句子。如果预算内没有完整句子,可能保留首个完整句子,即使它超过预算。因此,这些配置不是已存储 sidecar 文件的大小硬上限。

L0:摘要 ​

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

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

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

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

L1:概览 ​

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

markdown
# 认证指南

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

## 快速导航

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

资源目录生成语义摘要时,L0 从 L1 正文中提取:取 H1 标题之后、第一个 ## 标题之前的 Brief Description 段落。YAML frontmatter 不参与提取。

L2:详情 ​

L2 是原始文件或解析后的正文,按需加载。格式取决于导入方式,例如 PDF 可被解析为 Markdown,并不一定保留源文件格式。

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

目录结构 ​

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

text
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 正文。

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 的正文,source、generated_by 和 freshness 不会进入总结 prompt。

Embedding 元数据白名单 ​

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

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

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

source、generated_by、freshness 以及未知字段都不会进入 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)时,系统使用确定性、保序的稳定采样。相同目录树重复刷新会选择相同样本,减少采样变化带来的正文差异;模型重新生成的正文仍可能不同。

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

resource/skill 的父目录刷新已使用 freshness 决策。子目录 L0 正文不变时,不触发向上传播。正文变化后,若父目录没有 freshness 基线,或直接子项数不超过 semantic.overview_sample_limit,则立即安排刷新。更大的目录会累计 pending_child_changes,其与 total_entries 的比值达到 semantic.freshness_refresh_ratio(默认 0.10)时才刷新。手动刷新或导入仅对请求的根目录跳过阈值,不会强制刷新所有祖先。传播止于 namespace 根边界。未达阈值时父目录仍可读,但保留 pending 状态;阈值策略不承诺定时刷新。

写保护 ​

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

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

生成机制 ​

SemanticProcessor 自底向上处理目录:

text
文件摘要 → 叶子目录 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 原始内容

相关文档 ​

Open source under the AGPL-3.0 License. Font licenses