wth2jhl.online

Back

OpenViking logo

“Data in, Context out.” —— openviking/__init__.py 第二行注释


一、为什么我会去翻这个项目#

最近一次刷 GitHub Trending,看到 volcengine/OpenViking ↗ 挂了快两周——30K+ stars,AGPLv3,主语言 Python,29.4K stars 配 7.9K forks 这种密度在 AI infra 赛道里太罕见了。

我去 README.md:1 ↗ 看了第一句话:

OpenViking is an open-source context database for AI agents.

主语是 “context database”,不是 “vector database”。这个用词让我警觉——他们是想和 Pinecone / Milvus / Qdrant 抢饭碗,还是在做一件完全不一样的事?

读完之后我确认:他们是在做完全不一样的事。

仓库是 100MB 重的 monorepo(53MB tarball),但分层清晰:

  • openviking/ Python 主包(FastAPI + Pydantic v2,约 2.2 万行 .py)
  • crates/ Rust 实现的 RAGFS(替代了历史上的 AGFS,相当于 OpenViking 的”ext4”)
  • openviking_cli/ Python 客户端 + Rust CLI(双实现的 ov 命令)
  • docs/en/ 15 个概念文档 + 29 个指南 + 完整的 API 参考
  • integrations/ LangChain / Claude Code / Cursor / OpenClaw / Hermes / OpenCode / Codex / pi / Trae 等 11 个 Agent 集成
  • benchmark/ 复现 LoCoMo + tau2-bench 的脚本

读完整个项目我的判断是:这不是又一个向量数据库,这是 AI Agent 时代的”文件系统”。


二、第一性原理:为什么 RAG 该被重写#

打开 docs/en/concepts/01-architecture.md ↗ 之前,先看 OpenViking 团队在 README 里写下的”RAG 五大痛点”(也写在了 docs/en/getting-started/01-introduction.md):

  1. Context Fragmentation — Memory 在代码里、Resource 在向量库里、Skill 散在各处,管不到一起
  2. Context Explosion — 长任务每执行一次就生成一堆上下文,简单截断 = 信息丢失
  3. Poor Retrieval Quality — 扁平 RAG 没有全局视角,理解不了完整上下文
  4. Context Opacity — 传统 RAG 的检索管道是黑盒,调试很难
  5. Limited Memory Iteration — 现在所谓”memory”只记用户偏好,不记 Agent 自己的任务经验

5 条都戳到我了。我过去一年搭 RAG 的时候,最痛的不是”召回率上不去”,而是第 4 条——结果错了,我都不知道错在哪一环。

OpenViking 的解法是:别把 context 当数据库条目,把 context 当文件。

没错,就是 Unix file tree。每个 context 一个 viking:// URI,Agent 用 ls / tree / find 操作自己的上下文。所有 context 类型(resource / memory / skill)共用一套语义、一套 API、一套存储。


三、三层渐进加载:L0 / L1 / L2#

这是 OpenViking 的第一个工程创新,写在 docs/en/concepts/03-context-layers.md。

所有 ingest 进来的内容会被预生成三层:

层名字默认长度用途
L0Abstract256 字符向量检索 + 快速过滤
L1Overview4000 字符Rerank + 内容导航
L2Detail无上限原始内容,按需加载

L0 和 L1 不是每个文件都生成,而是目录级别的 sidecar(.abstract.md / .overview.md):

viking://resources/my_project/
├── .abstract               # L0: ~100 tokens - quick relevance check
├── .overview               # L1: ~2k tokens - structure and key points
└── docs/
    ├── .abstract
    ├── .overview
    └── api/
        ├── auth.md         # L2: full content, loaded on demand
        └── endpoints.md
text

注意关键词:“directory sidecar”。L0/L1 描述一个目录,不是描述一个文件。这是和传统 RAG 最大的区别。

传统 RAG 是”扁平的 chunk 列表 + 向量”,LLM 每次都得从一堆 chunk 里拼出全貌。
OpenViking 把”目录语义”显式索引——viking://resources/my_project/docs/api/ 的 L0 是”API 认证指南”,L1 列出 auth.md / jwt.md / api-keys.md 三个文件。LLM 在拿到 L1 之后就可以决定要不要跳到 L2。

这个设计带来的可量化收益,README 里有现成的数字(README.md:109-115):

LoCoMo(长对话用户记忆)准确率:
  OpenClaw native 24.20% → 接入 OpenViking 82.08%(+57.88pp)
  Hermes    native 33.38% → 接入 OpenViking 82.86%(+49.48pp)
  Claude Code native 57.21% → 接入 OpenViking 80.32%(+23.11pp)
  输入 token 下降 34.3–91.0%,查询延迟下降 58.45–66.10%
text

换句话说:三层渐进加载不是花架子,是真的能让 LLM 在更少 token 里拿到更高的准确率。


四、目录递归检索:RAG 的”ls -R + grep”#

第二个创新写在 docs/en/concepts/07-retrieval.md 和 openviking/retrieve/hierarchical_retriever.py:84(648 行的核心检索器)。

传统 RAG 检索:

query → embed → 向量检索 top_k → 重排 → 拼接 chunks → 给 LLM
text

OpenViking 的 HierarchicalRetriever:

Step 1: 确定根目录(按 context_type:memory / resource / skill)
Step 2: 全局向量检索定位高分级目录(粗排,level=[0,1])
Step 3: Rerank 打分,决定候选起点
Step 4: 递归搜索(priority queue,max 3 轮收敛)
Step 5: 转成 MatchedContext 返回
text

我用大白话翻译:先 ls -R 找到最像的几个目录,再 cd 进去二级检索,再 cd 进去三级…… 直到找到满意的文件。

这种”先定位目录,再细搜内容”的策略,在项目里叫 directory recursive retrieval。它的好处写在 README 里:

“Vector search first locates the highest-scoring directory, then drills down layer by layer, so results arrive with their surrounding context intact.”

也就是说:不仅返回 fragment,还返回 fragment 的目录背景。这解决了传统 RAG 调不动的”orphan chunk”问题——传统 RAG 拿到 5 个 chunk,但不知道这 5 个 chunk 在文档树里是什么关系。

_recursive_search 内部用 heapq(小顶堆)维护候选,源码 openviking/retrieve/hierarchical_retriever.py:400-500。DIRECTORY_DOMINANCE_RATIO = 1.2 这个常量很关键——目录分必须比子节点分高 20% 才停止下钻,避免误判。

还配备了 transparent trajectory(透明回溯)——每次检索保存完整的目录浏览路径。错的不是”结果”,是”路径”。这正是 README 里说的 “Observable retrieval”。


五、意图分析:一次查询可能拆成 5 个子查询#

OpenViking 有两套检索入口:find() 和 search()(区别在 docs/en/concepts/07-retrieval.md:11):

find()search()
Session context不需要需要
意图分析不调用LLM 分析
子查询数10-5
延迟低较高
用途简单查询复杂任务

search() 入口会调 openviking/retrieve/intent_analyzer.py(180 行),用 LLM 把用户的复杂 query 拆成 0-5 个 TypedQuery:

@dataclass
class TypedQuery:
    query: str              # 改写后的查询
    context_type: ContextType  # MEMORY / RESOURCE / SKILL
    intent: str             # 查询意图
    priority: int           # 1-5 优先级
python

查询风格有讲究(01-introduction.md 写了三大范式):

  • skill 类查询:动词开头(“Create RFC document”)
  • resource 类查询:名词短语(“API usage guide”)
  • memory 类查询:“User’s XX”(“User’s code style preferences”)

5 个子查询可以并行触发各自的 HierarchicalRetriever,最后聚合。这等于一次性把”memory + resource + skill + 多个时间切片”全部召回,对复杂任务友好。


六、双层存储:VikingFS + 向量索引#

写在 docs/en/concepts/05-storage.md,OpenViking 把存储拆成两层:

┌─────────────────────────────────────────┐
│          VikingFS (URI Abstraction)      │
│    URI Mapping · Hierarchical Access     │
│           · Relation Management          │
└────────────────┬────────────────────────┘
        ┌────────┴────────┐
        ▼                 ▼
┌──────────────┐  ┌──────────────────┐
│ Vector Index │  │  AGFS / RAGFS    │
│ (Semantic    │  │  (Content        │
│  Search)     │  │   Storage)       │
└──────────────┘  └──────────────────┘
text
  • Vector Index:只存 URI + 向量 + 元数据,不存文件内容(省内存)
  • AGFS / RAGFS:POSIX 风格文件系统,存 L0/L1/L2 全部内容 + 关联关系

AGFS 已经用 Rust 重写成 RAGFS(crates/ragfs/,1.0+ 版本),通过 PyO3 暴露给 Python。性能更强、可选 backend 也更多(localfs / s3fs / memory)。

这个设计的好处是数据一致性——所有内容读写都走 RAGFS,向量索引只是”索引”。删除一个文件,AGFS 删一个,向量索引同步删一个,不会出现”向量库里有 ID 但文件系统里没文件”的鬼影。

URI 映射是用户态的,写在 openviking/core/namespace.py:

viking://resources/docs/auth  →  /local/{account_id}/resources/docs/auth
viking://user/memories        →  /local/{account_id}/user/{user_id}/memories
python

多租户隔离也在这里完成——{account_id} 和 {user_id} 是 namespace 的一部分。


七、Session → Memory:会话结束后才真正开始学习#

第三个关键创新在 openviking/session/memory/(9.1K 行 Python),是 OpenViking 比所有竞品都”重”的部分。

docs/en/concepts/08-session.md 描述了完整流程:

  1. Session 期间:所有 message + tool call + resource 使用都会记录
  2. Session commit:用户主动触发(或定时任务)
  3. 异步抽取:extract_loop 跑起来,用 LLM 从 session 里抽:
    • 用户偏好(写作风格、代码习惯)→ viking://user/{user_id}/memories/preferences/
    • Agent 经验(这次任务学到了什么)→ viking://user/{user_id}/memories/agent_experience/
  4. Compressor V3:去重 + 合并相似记忆,避免 memory 爆炸

openviking/session/memory/streaming_memory_updater.py 单文件 2004 行,是 OpenViking 最大的 Python 文件。注释里写:

“Memory is the only thing that survives across sessions.”

这点至关重要——传统 RAG 是”静态知识库”,每次 session 都从零开始;OpenViking 是”自进化上下文数据库”(README subtitle),session 结束才是它学习的开始。

tau2-bench 的 benchmark 数字验证了 Agent Experience memory 的价值(README:117):

tau2-bench 任务成功率:
  Retail  70.94% → 77.81%(+6.87pp)
  Airline 54.38% → 66.25%(+11.87pp)
text

这是 OpenViking 0.3.22 的实测数字。这不是 RAG 的胜利,是 “Agent 经验可累积” 的胜利。


八、ovpack:可移植的”上下文包”#

OpenViking 不只是一个运行时,它还是一种可移植格式。

openviking/storage/ovpack/ 定义了 .ovpack 格式(一种 ZIP 容器),包含:

  • manifest.json — 元数据
  • tree.json — 目录结构
  • vectors/*.json — 预计算向量
  • content/ — 原始内容

可以用 ov export-ovpack / ov import-ovpack 把整棵上下文树打包带走,或者 backup-ovpack / restore-ovpack 做带时间戳的备份。

这意味着:OpenViking 是少数支持”上下文迁移”的 RAG 系统。团队 A 的私有 viking://resources/ 可以打包发给团队 B,团队 B 一键导入,开箱即用。


九、30K star 的社区真实使用形态#

我去翻 integrations/ 目录的时候意识到 OpenViking 不是”一个 demo 项目”,它已经接入了当下主流的所有 Agent 框架:

集成位置形态
Claude Codeexamples/claude-code-memory-plugin/Memory plugin
Codexexamples/codex-memory-plugin/Hooks
OpenClawexamples/openclaw-plugin/Plugin
Hermes(文档)Provider
Cursorexamples/cursor-memory-plugin/Memory plugin
Trae / Trae-CLIexamples/trae-*Hooks + plugin
OpenCodeexamples/opencode-plugin/Plugin
piexamples/pi-coding-agent-extension/Extension
zcodeexamples/zcode-memory-plugin/Memory plugin
DSHexamples/dsh-memory-plugin/Memory plugin
LangChain / LangGraphintegrations/langchain/Python SDK
OpenWebUIexamples/openwebui-plugin/Plugin

加上 Rust CLI(crates/ov_cli/,基于 clap + ratatui 的 TUI)和 npm 包(npm/),OpenViking 在 2026 年初已经实质上成了Agent 上下文层的事实标准之一。

agent-plugins/ 还有一个 plugin.json + mcp.json(MCP server),等于把 OpenViking 自己也暴露成了 MCP server。任何支持 MCP 的 host(Claude Desktop / Cursor / Cline)都能直接用。


十、OpenViking Helper:桌面端调试器#

最有意思的是 docs/en/README.md:127-141 提到的 OpenViking Helper(Beta)——一个 macOS + Windows 的桌面控制台:

Visual local agent setup: detects OpenViking CLI, Claude Code, Codex, Cursor, Trae, and OpenCode, then configures supported plugin, MCP, Hook, and CLI integrations.

Session trace inspection: parses Claude Code, Codex, and Trae sessions to show OpenViking recall, prompt injection, MCP calls, capture, and commit events.

Local memory and skill management: views local memory / rule files and SKILL.md skills, then syncs them to OpenViking.

这玩意解决的痛点是 “我用的是 Claude Code,但我怎么知道它是哪条 prompt 触发了 OpenViking 召回?” —— 通过把 session trace 解析成可视化的 timeline,可以直接看到 recall / prompt injection / MCP call / capture / commit 五个事件分别在哪个位置发生。

这个 debug 工具的存在再次印证了 OpenViking 的核心哲学:context 必须是可观测的(observable)。


十一、代码组织里一些值得偷的小细节#

读源码的时候捡了一些”小但很关键”的设计:

1. 双实现客户端:Python + Rust#

openviking_cli/ 是 Python,crates/ov_cli/ 是 Rust,两边共用同一个 HTTP API。Client 只负责发请求,逻辑都在 server 端。
→ 这意味着以后想加 Go / Node 客户端,零成本。

2. Sparse + Dense 双向量#

openviking/retrieve/hierarchical_retriever.py:147-161 里 embedder 同时返回 dense_vector 和 sparse_vector,对 remote vendor 友好(很多云厂商只支持 dense)。

3. Hotness scoring#

openviking/retrieve/memory_lifecycle.py 维护 memory 的”热度分”,最近被 recall 过的 memory 权重更高。
→ 这就是 beta 衰减 + 召回频次的混合模型。

4. VLM 优先的图片 / 视频#

openviking/parse/vlm.py 用 VLM 处理图片(32 行壳),整条 async pipeline 复用同一个 VLM client。
→ 多模态不是单独模块,是所有 parser 都能调的能力。

5. asyncio.to_thread 包装同步 Rerank#

hierarchical_retriever.py:353-358 把同步的 Rerank client 包装成 async,避免阻塞 event loop。
→ 这种”同步 SDK 异步化”的写法在 RAG 项目里很常见但容易踩坑。

6. 完整的 observer 抽象#

openviking/storage/observers/ 实现了 observer pattern(类似 Linux 的 inotify),文件系统变更会触发 observer,可以挂 resume / backup / notify hook。
→ 这让 OpenViking 能做”watch”功能(ov watch 监控 viking:// 改变)。

7. .redirect.json + .sync_log.json 实现多写#

docs/en/concepts/14-multi-write-storage.md 描述了多写模式:主 backend 写 + 多个 backup backend 写。同步状态用两个隐藏文件追踪。
→ 这是”数据库风格的灾难恢复”被搬到了文件系统层。

8. AGFS / RAGFS 多 backend#

storage.agfs.backend 字段支持 localfs / s3fs / memory,生产用 S3、测试用内存。
→ 和 vector store 完全独立的 scaling 路径。


十二、不足与注意事项#

我必须诚实地说几点:

  1. 复杂度极高:100MB monorepo,2.2 万行 Python + 4000+ 行 Rust,部署要求不低(FastAPI 服务 + 向量库 + 对象存储)。个人开发者用 pip install openviking 简单,但自己改源码并部署到生产是另一回事。
  2. AGPLv3 商用保护:开源协议是 AGPLv3,“服务化”部署必须开源你的服务源码。如果你要做 SaaS,要么开协议、要么用官方 SaaS 版(README 提到 Managed SaaS on Volcano Engine)。
  3. 依赖锁定 LLM provider:默认是 Volcengine 的 doubao,需要换 OpenAI / Claude / Ollama 的话 openviking-server init 引导一步步配置。
  4. observability 还在早期:metrics 接口(docs/en/concepts/12-metrics.md)有但默认关闭;想做 Grafana 看板需要手动装 exporter(examples/grafana/)。
  5. VikingFS 的多 backend 在 vector 端不统一:vector index 现在强依赖 VikingDB(Volcengine 自家向量数据库),虽然可以替换但成本高。
  6. commit / extract 是异步的:session commit 后立刻 fetch 可能看不到刚生成的 memory——需要 wait_processed 或者轮询。

十三、读完之后我换了一种思路#

我之前做 RAG 默认思路是:

拆文档 → embed → 存向量库 → 检索 → 拼接 chunks → 给 LLM
text

OpenViking 让我看到另一种思路:

拆文档 → 目录化 → L0/L1/L2 渐进 → 递归检索 → 上下文带目录 → 给 LLM
text

第二种思路的最大差别是给 LLM 的不是一堆 unrelated chunks,而是”目录 + 路径 + 关联”。这其实更接近人脑回忆一件事的方式——你不会只想到一个句子的截断,你会想到”那是 XX 那本书的第 3 章讲过……”。

我下一篇博客应该会写怎么用 OpenViking 改造一个自己的项目。如果你想先动手,5 分钟跑起来的最短路径:

pip install openviking --upgrade
openviking-server init      # 引导配置 provider
openviking-server doctor    # 校验
openviking-server           # 启动
ov add-resource https://github.com/volcengine/OpenViking --wait
ov tree viking://resources/volcengine -L 2
ov find "what is openviking"
bash

或者直接打开 OpenViking Studio ↗ 试在线 demo,零安装。


附录:关键源码定位速查#

模块路径
三层模型定义openviking/core/context.py:60-72
VikingFS URI 映射openviking/core/namespace.py
解析器总入口openviking/parse/parser_router.py
树构建openviking/parse/tree_builder.py
L0/L1 生成openviking/parse/understanding_api.py
检索核心openviking/retrieve/hierarchical_retriever.py:84
意图分析openviking/retrieve/intent_analyzer.py
Memory 生命周期openviking/retrieve/memory_lifecycle.py
双层存储openviking/storage/viking_fs/_ops.py
VikingFS 语义层openviking/storage/viking_fs/_semantic.py
关系管理openviking/storage/viking_fs/_base.py
ovpack 格式openviking/storage/ovpack/manifest.py
Session 管理openviking/session/session.py
自动 commit 策略openviking/session/auto_commit_policy.py
Memory 抽取openviking/session/memory/extract_loop.py
流式 memory 更新openviking/session/memory/streaming_memory_updater.py
Compressor V3openviking/session/compressor_v3.py
Rust RAGFScrates/ragfs/src/lib.rs
Rust CLIcrates/ov_cli/src/main.rs
FastAPI appopenviking/server/app.py
Quickstart 脚本examples/quick_start.py
架构文档docs/en/concepts/01-architecture.md
三层文档docs/en/concepts/03-context-layers.md
检索文档docs/en/concepts/07-retrieval.md
存储文档docs/en/concepts/05-storage.md
Session 文档docs/en/concepts/08-session.md

📘 项目信息

把 Agent 上下文当文件系统:拆 OpenViking 这张 30K star 牌
https://wth2jhl.online/blog/openviking-context-database/
Author 小吴同学
Published at August 19, 2026