OpenViking:LLM Wiki 理念的工程级实践 — L0/L1/L2 分层 + 目录递归检索
原文链接:https://mp.weixin.qq.com/s/JPUdQDXC8oV9erCJasDIVw
作者:青红皂白
火山引擎开源的 OpenViking 项目,把 Karpathy 的 LLM Wiki 理念做成了一套有文件系统、有分层索引、有递归检索、有自我进化的完整工程系统。我从源码层面拆解了它的两个核心创新:L0/L1/L2 上下文分层和目录递归检索。
从理念到工程的鸿沟
LLM Wiki 理念的核心洞察:RAG 每次查询从零推导,什么都不积累。LLM Wiki 预编译、持续维护,知识随时间复利。
但从「用 LLM 维护一个 wiki」到「让 Agent 真正用上这个 wiki」,中间有一道工程鸿沟:
- 规模问题 — wiki 膨胀到数百页后,index.md 本身就撑爆 context window
- 精度问题 — grep + 正则只认字面命中,语义检索能力不足
- 效率问题 — Agent 每次都要读全量内容,Token 消耗失控
- 进化问题 — 知识不会自动更新、不会自动发现关联
个人用的 wiki-vault 可以用 index.md + wikilink 解决前 100 页的问题。但当你有几千份文档、几十个 Agent 并发查询时,需要一套完全不同的基础设施。OpenViking 就是这套基础设施的一个工程回答。
OpenViking 是什么
OpenViking 是火山引擎(字节跳动)开源的 Agent 知识操作系统。核心命题:用文件系统的范式替代扁平的向量存储,让 Agent 的上下文像操作文件一样被分层加载、按需检索、持续迭代。
技术栈:Python(服务端 + AI 管线)+ Rust(底层文件系统 AGFS)+ C++(向量索引引擎),提供 FastAPI HTTP 服务。
它在 LLM Wiki 范式的基础上做了四件事:
- 虚拟文件系统 — 所有知识通过
viking://URI 寻址,有目录、有权限、有 ACL - L0/L1/L2 三级上下文 — 每个目录自动生成 100 token 摘要和 2k token 概览,Agent 按需逐层展开
- 目录递归检索 — 从目录级定位到文件级精确定位,兼顾全局和局部
- 自我进化 — 会话结束后自动提取记忆、更新知识库、重新生成摘要
一、L0/L1/L2:知识的三级分层
当 wiki 有 500 个页面时,Agent 不可能全部读完。它需要一个机制——像 CPU 缓存一样,先看 L1 Cache(小而快),miss 了再看 L2 Cache(中而准),最后才访问 Main Memory(大而全)。
| 层级 | 载体 | 大小 | 作用 | 类比 |
|---|---|---|---|---|
| L0 Abstract | .abstract.md | ~100 tokens | 一句话说明这个目录/文件”是什么” | CPU L1 Cache |
| L1 Overview | .overview.md | ~2k tokens | 核心信息 + 导航树 + 文件关系 | CPU L2 Cache |
| L2 Detail | 原始文件 | 不限 | 完整内容 | Main Memory |
Agent 的工作流变成:搜索 L0 → 读 L1 → 只在确认需要时才读 L2。Token 消耗从全量降到按需。
生成方式:自底向上的 DAG
L0/L1 不是手写的,而是 LLM 自动生成,关键在自底向上——先处理叶子文件,再逐层汇总到根目录。
OpenViking 用 SemanticDagExecutor(DAG 调度器)编排:文件先按类型用不同 prompt 模板生成摘要(代码文件 >100 行先 AST 提取骨架),子节点完成后触发父目录 overview 生成。L0 是从 L1 输出中自动提取的——一次 LLM 调用产出两层结果。
增量更新
DAG 调度器内置增量检测:文件内容未变则复用已有摘要,目录无变更则复用已有 overview,只有真正变化的路径才触发重新向量化。
二、目录递归检索:从「一袋子 chunk」到「一棵树」
传统 RAG 是扁平的——所有 chunk 平等地躺在向量库里,丢失层级信息,全局与局部矛盾。OpenViking 的解法是目录递归检索,利用 L0/L1 的层级结构先定位再精确搜索。
五步法
- 意图分析(可选)
- 全局定位 — L0/L1 向量中搜索 top-10 目录
- 选择递归入口 — 高分目录 + 预设根目录
- 递归搜索 — 优先队列驱动,并行展开子目录
- 结果聚合 — 去重、分数融合、热度加权、排序
核心算法:优先队列驱动的并行递归
用最大堆驱动目录展开顺序,每轮取最高分 4 个目录并行展开。不是 BFS(平等对待浪费算力)也不是 DFS(可能钻太深错过全局更优),而是 best-first search 的变体——保证每一轮都展开当前全局最高分的目录。
分数传播公式
final_score = α × child_score + (1-α) × parent_score
一个子节点的最终得分不仅取决于自身的相似度,还受到它所在目录相关性的加权——父目录的信誉为子节点背书。
收敛检测
三重机制:top-k 连续 3 轮不变停止 / 结果池连续 3 轮无新结果停止 / visited set 去重。实测大多数查询在 2-4 轮内收敛。
热度加权
借鉴 Hacker News 排序算法,融合语义相似度和热度分。被频繁访问且最近更新的知识排在前面,7 天半衰期——最近的经验优先被召回。
三、自迭代:知识库自己更新自己
每次会话提交时,系统自动执行知识沉淀管线:
1 | 会话消息 → 归档摘要 → ExtractLoop(ReAct 循环)→ MemoryUpdater → 目录 L0/L1 重建 |
ExtractLoop 不是简单的 “LLM 提取 → 写入”,而是有工具调用能力的 ReAct 循环——LLM 可以用 read 工具主动查阅现有知识,避免重复或矛盾的记忆写入。支持 upsert+patch(增量合并)、upsert+replace(整体替换)、delete、link 等操作。
写入后触发目录 L0/L1 重新生成,下次查询时新知识已经”编译”好了——这就是 LLM Wiki 理念的工程闭环。
四、回到 LLM Wiki 五范式
| 维度 | LLM Wiki 原版 | OpenViking |
|---|---|---|
| 知识表示 | Markdown + wikilink | viking:// URI + L0/L1/L2 三层 |
| 检索方式 | index.md + grep | 目录递归检索 + rerank |
| 规模承载 | ~100 页 | 数千页(向量索引 + 分层过滤) |
| 知识更新 | 手动 ingest | 会话后自动提取 + 增量 DAG |
| 权限控制 | 无 | 多租户 + ACL + 路径级权限 |
| 可观测性 | 无 | OpenTelemetry + Prometheus + 事件总线 |
| 自进化 | 无 | ReAct 记忆提取 + RL 训练管线 |
OpenViking 本质上是 LLM Wiki(范式二)+ GraphRAG(范式四的检索能力)+ 企业级基础设施 的工程融合,核心哲学仍然是 Karpathy 的:知识要被编译、沉淀下来,而不是每次从零检索。L0/L1 就是”编译后的知识”——不是原始文档的 chunk,而是 LLM 理解了整棵目录树后产出的结构化摘要。
五、局限与思考
| 代价 | 具体表现 |
|---|---|
| LLM 调用成本高 | 每个文件都要 LLM 生成摘要,每个目录都要生成 overview |
| 延迟 | 递归检索需要多轮向量搜索 + 可能的 rerank |
| 系统复杂度 | Python + Rust + C++ 三语言栈,部署运维门槛高 |
| 摘要质量依赖 LLM | L0/L1 质量取决于 LLM 总结能力,弱模型会导致摘要失真 |
核心判断: OpenViking 证明了 LLM Wiki 理念可以在工程上做到大规模、分层、自进化。但它的价值更多是方向性的验证而非直接可用的产品——它告诉你”上下文分层供给”这条路是走得通的,具体实现可以根据自己的规模选择合适的复杂度。
本文转载自微信公众号,如有侵权请联系删除。
- 标题: OpenViking:LLM Wiki 理念的工程级实践 — L0/L1/L2 分层 + 目录递归检索
- 作者: lxiol
- 创建于 : 2026-07-27 10:00:00
- 更新于 : 2026-07-27 08:59:38
- 链接: https://blog.lxiol.cn/2026/07/27/OpenViking-LLM-Wiki工程级实践-L0L1L2分层检索/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。