
“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):
- Context Fragmentation — Memory 在代码里、Resource 在向量库里、Skill 散在各处,管不到一起
- Context Explosion — 长任务每执行一次就生成一堆上下文,简单截断 = 信息丢失
- Poor Retrieval Quality — 扁平 RAG 没有全局视角,理解不了完整上下文
- Context Opacity — 传统 RAG 的检索管道是黑盒,调试很难
- Limited Memory Iteration — 现在所谓”memory”只记用户偏好,不记 Agent 自己的任务经验
5 条都戳到我了。我过去一年搭 RAG 的时候,最痛的不是”召回率上不去”,而是第 4 条——结果错了,我都不知道错在哪一环。
OpenViking 的解法是:别把 context 当数据库条目,把 context 当文件。
viking://
├── resources/ # Resources: project docs, repos, web pages, etc.
│ └── my_project/
│ ├── docs/
│ │ ├── api/
│ │ └── tutorials/
│ └── src/
└── user/
└── {user_id}/
├── memories/
│ └── preferences/
│ ├── writing_style
│ └── coding_habits
├── resources/
│ └── private_project/
├── skills/
│ ├── search_code
│ └── analyze_data
└── peers/
└── web-visitor-alice/text没错,就是 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 进来的内容会被预生成三层:
| 层 | 名字 | 默认长度 | 用途 |
|---|---|---|---|
| L0 | Abstract | 256 字符 | 向量检索 + 快速过滤 |
| L1 | Overview | 4000 字符 | Rerank + 内容导航 |
| L2 | Detail | 无上限 | 原始内容,按需加载 |
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.mdtext注意关键词:“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 → 给 LLMtextOpenViking 的 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 分析 |
| 子查询数 | 1 | 0-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}/memoriespython多租户隔离也在这里完成——{account_id} 和 {user_id} 是 namespace 的一部分。
七、Session → Memory:会话结束后才真正开始学习#
第三个关键创新在 openviking/session/memory/(9.1K 行 Python),是 OpenViking 比所有竞品都”重”的部分。
docs/en/concepts/08-session.md 描述了完整流程:
- Session 期间:所有 message + tool call + resource 使用都会记录
- Session commit:用户主动触发(或定时任务)
- 异步抽取:extract_loop 跑起来,用 LLM 从 session 里抽:
- 用户偏好(写作风格、代码习惯)→
viking://user/{user_id}/memories/preferences/ - Agent 经验(这次任务学到了什么)→
viking://user/{user_id}/memories/agent_experience/
- 用户偏好(写作风格、代码习惯)→
- 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 Code | examples/claude-code-memory-plugin/ | Memory plugin |
| Codex | examples/codex-memory-plugin/ | Hooks |
| OpenClaw | examples/openclaw-plugin/ | Plugin |
| Hermes | (文档) | Provider |
| Cursor | examples/cursor-memory-plugin/ | Memory plugin |
| Trae / Trae-CLI | examples/trae-* | Hooks + plugin |
| OpenCode | examples/opencode-plugin/ | Plugin |
| pi | examples/pi-coding-agent-extension/ | Extension |
| zcode | examples/zcode-memory-plugin/ | Memory plugin |
| DSH | examples/dsh-memory-plugin/ | Memory plugin |
| LangChain / LangGraph | integrations/langchain/ | Python SDK |
| OpenWebUI | examples/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.mdskills, 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 路径。
十二、不足与注意事项#
我必须诚实地说几点:
- 复杂度极高:100MB monorepo,2.2 万行 Python + 4000+ 行 Rust,部署要求不低(FastAPI 服务 + 向量库 + 对象存储)。个人开发者用
pip install openviking简单,但自己改源码并部署到生产是另一回事。 - AGPLv3 商用保护:开源协议是 AGPLv3,“服务化”部署必须开源你的服务源码。如果你要做 SaaS,要么开协议、要么用官方 SaaS 版(README 提到
Managed SaaS on Volcano Engine)。 - 依赖锁定 LLM provider:默认是 Volcengine 的 doubao,需要换 OpenAI / Claude / Ollama 的话
openviking-server init引导一步步配置。 - observability 还在早期:metrics 接口(
docs/en/concepts/12-metrics.md)有但默认关闭;想做 Grafana 看板需要手动装 exporter(examples/grafana/)。 - VikingFS 的多 backend 在 vector 端不统一:vector index 现在强依赖 VikingDB(Volcengine 自家向量数据库),虽然可以替换但成本高。
- commit / extract 是异步的:session commit 后立刻 fetch 可能看不到刚生成的 memory——需要
wait_processed或者轮询。
十三、读完之后我换了一种思路#
我之前做 RAG 默认思路是:
拆文档 → embed → 存向量库 → 检索 → 拼接 chunks → 给 LLMtextOpenViking 让我看到另一种思路:
拆文档 → 目录化 → L0/L1/L2 渐进 → 递归检索 → 上下文带目录 → 给 LLMtext第二种思路的最大差别是给 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 V3 | openviking/session/compressor_v3.py |
| Rust RAGFS | crates/ragfs/src/lib.rs |
| Rust CLI | crates/ov_cli/src/main.rs |
| FastAPI app | openviking/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 |
📘 项目信息
- 仓库:volcengine/OpenViking ↗
- 作者:ByteDance / Volcano Engine
- License:AGPLv3
- 版本:0.3.22
- Star 趋势:https://trendshift.io/repositories/19668 ↗
- Live Demo:OpenViking Studio ↗
- 官方文档:https://docs.openviking.ai ↗
- 博客:blog.openviking.ai ↗