OpenViking 深度技术解析:AI Agent 上下文数据库的设计哲学与实践
本文是一篇面向新手 / 初中级开发者的系统性教程,结合 OpenViking 官方文档(https://docs.openviking.ai/zh)与源码实现视角,从「概念直觉 → 核心概念 → 实现原理 → 动手实操 → 横向对比」四个层次,把 OpenViking 讲透。
阅读建议:如果你刚接触 AI Agent,请重点读第 1–5 章(概念);如果你已经会写 Agent 但想理解内部机制,请直接跳到第 6–11 章(原理);如果你想立刻跑起来,请跳到第 12 章(5 分钟上手)。
写在前面:用一句话建立直觉
传统 RAG(检索增强生成)把文档切碎、塞进向量数据库,Agent 提问时「按相似度翻找碎片」——这就像你把所有书撕成纸条扔进一个箱子,要用时只能靠关键词碰运气。
OpenViking 的做法完全不同:它把 Agent 需要的所有知识(记忆、文档、技能)组织成一个「虚拟硬盘」(viking:// 文件系统),让 Agent 像人浏览文件夹一样去定位、理解、按需读取上下文。 这个「虚拟硬盘」还会自动写摘要、自动从对话里学经验、并且把每次检索路径都记录下来供你审查。
一句话:OpenViking 是「专为 AI Agent 设计的上下文数据库(The Context Database for AI Agents)」,用文件系统范式统一管理三类上下文,用分层加载省 Token,用目录递归搞检索,用可视化轨迹消除黑箱,用会话自演化让 Agent 越用越聪明。
第一部分:概念直觉(新手必读)
第 1 章 OpenViking 是什么?为什么需要它?
1.1 一个真实的痛点场景
设想你做了一个「客服 Agent」。第一天用户告诉你「我姓张,公司用深色主题」。第二周用户再问问题,Agent 却说「您好,请问怎么称呼您?」——它失忆了。
你尝试用传统 RAG 把聊天记录存进向量库。但很快发现:
- 记录散落各处(用户偏好在 A 库、产品文档在 B 库、工具定义在 C 库),碎片化;
- 长对话越攒越多,全塞进上下文窗口会爆,所需上下文猛增;
- 向量检索只匹配「相似句子」,却不知道「张先生的偏好」其实在三个月前那条消息里,检索效果不佳;
- 为什么 Agent 这次答错了?你翻遍日志也找不到它「看了哪些资料」,上下文不可观测;
- 最致命的:传统 RAG 只会「记用户」,却不会「记自己怎么把事干成的」,记忆迭代有限。
这五大问题,正是官方文档明确定义的「构建 AI Agent 的五大挑战」,也是 OpenViking 所有设计的出发点。
1.2 五大挑战 ↔ 五大特性
| 官方定义的挑战 | OpenViking 的对应解法 |
|---|---|
| 上下文碎片化 | 文件系统范式,统一三类上下文 |
| 所需上下文猛增 | L0/L1/L2 分层加载,按需取用 |
| 检索效果不佳 | 目录递归检索(结构 + 语义) |
| 上下文不可观测 | 可视化检索轨迹 |
| 记忆迭代有限 | 会话自动管理与自演化记忆 |
1.3 OpenViking 的本质定位
- 开源:Apache-2.0 许可证,由字节跳动火山引擎 Viking 团队开源,背后有 VLDB 2026 论文 VikingMem 的理论支撑。
- 上下文数据库:它不是又一个向量库(那是它的底层之一),而是在存储之上构建了意图分析、层次化检索、记忆提取、会话管理的一套完整上下文操作系统。
- Agent 无关:通过 Python SDK、HTTP API、Rust CLI(
ov)、Go SDK、MCP 协议,可以接入任何 Agent 框架(LangChain、Claude Code、Cursor、TRAE 等)。
第二部分:四大核心概念
第 2 章 核心概念一:一切皆文件(Viking URI 与虚拟文件系统)
2.1 为什么用「文件系统范式」?
人类理解知识的方式天然是「分门别类」的:先看目录名,大概知道这块讲什么;再看 README,了解结构;最后才打开具体文件读细节。传统的向量 RAG 把这种结构彻底摧毁了——所有文档被切成等长片段,扁平地躺在向量空间里,上下文的「位置感」和「从属关系」全部丢失。
OpenViking 把这种「人类浏览知识」的直觉,映射成了一套虚拟文件系统:
- 每一段上下文(一个文档、一条记忆、一个技能)都有唯一地址:
viking://resources/docs/api.md - Agent 可以用标准文件操作去探索它:
ls(列目录)、tree(看树)、read(读内容)、write(写)、find(找)、grep(搜文本)、glob(按通配符匹配) - 每个目录自动附带隐藏的「元信息文件」:
.abstract.md(L0 摘要)、.overview.md(L1 概览)、.relations.json(关联),见第 4 章
新手理解:你可以把
viking://想象成电脑里的C:/或~/。只不过这个盘里装的不是你的电影和文档,而是「给 AI 看的知识」。
2.2 URI 语法
viking://{scope}/{path}
scheme:固定为vikingscope:顶级命名空间(官方公开支持resources、user、agent;temp、queue、upload为内部临时作用域)path:作用域内的路径
三大公开作用域说明:
| 作用域 | 存放什么 | 生命周期 | 可见性 |
|---|---|---|---|
resources |
客观知识(文档、代码、规范) | 长期 | account 全局 |
user |
用户级数据(记忆、私有资源、技能、会话) | 长期 / 会话生命周期 | 当前用户 |
agent |
Agent 能力与配置(技能、端点、工具、支付) | 长期 | account 全局 |
⚠️ 约束:
resources作用域只放客观知识,禁止存放工具配置、技能定义等非知识类数据(那些要放agent作用域)。这是新手常踩的坑。
📊 如图:一切皆文件 —— 三大公开作用域

2.3 目录树长什么样?
viking://
├── resources/ # 独立资源(客观知识)
│ └── {project}/
│ ├── .abstract.md # L0 摘要
│ ├── .overview.md # L1 概览
│ └── {files...}
│
├── user/{user_id}/ # 当前用户的数据
│ ├── profile.md # 用户画像
│ ├── memories/ # 记忆空间
│ │ ├── preferences/ # 按主题
│ │ ├── entities/ # 每条独立
│ │ └── events/ # 每条独立
│ ├── resources/ # 用户私有资源
│ ├── skills/ # 用户技能
│ ├── peers/{peer_id}/ # 关于某个交互对象的隔离空间
│ │ ├── memories/
│ │ └── resources/
│ └── sessions/{session_id}/ # 会话
│
└── agent/ # Agent 能力与配置(全局共享)
├── skills/
├── endpoints/ # 通信端点(规划中)
├── tools/ # 工具配置(规划中)
└── payments/ # 支付配置(规划中)
短路径约定(新手友好):你在代码里写 viking://user/memories/,服务端会按当前登录身份自动展开成 viking://user/{user_id}/memories/。{user_id}、{peer_id} 必须是安全的单段标识(如 alice、web-visitor-alice)。
2.4 变量路径:按时间自动归档
这是 OpenViking 一个很巧妙的设计。URI 支持路径变量,特别适合按时间序列组织数据(邮件、日志、日报):
{namespace:key}
calendar 命名空间提供了一整套日期变量:
| 变量 | 含义 | 示例(2026-05-07) |
|---|---|---|
{calendar:today} |
完整日期路径 | 2026/05/07 |
{calendar:yesterday} |
昨天 | 2026/05/06 |
{calendar:ym} |
年/月 | 2026/05 |
{calendar:quarter} |
季度 | Q2 |
{calendar:yw} |
年/ISO 周 | 2026/w18 |
# 写法(模板原样传,服务端渲染)
viking://resources/emails/{calendar:today}/inbox
# 渲染为:viking://resources/emails/2026/05/07/inbox
# CLI 中也一样(--parent-auto-create 可简写为 -p)
ov add-resource -p "viking://resources/emails/{calendar:today}/inbox" ./emails/*.eml
ov read "viking://resources/logs/{calendar:yesterday}/app.log"
第 3 章 核心概念二:三类上下文(Resource / Memory / Skill)
OpenViking 把 Agent 需要的所有信息抽象成三种基本类型,对应人类认知的三个侧面:外部知识、自身认知、行动能力。
| 类型 | 用途 | 生命周期 | 谁往里写 |
|---|---|---|---|
| Resource(资源) | 知识和规则 | 长期,相对静态 | 用户添加 |
| Memory(记忆) | Agent 的认知 | 长期,动态更新 | Agent 自动记录 |
| Skill(技能) | 可声明的能力配置 | 长期,静态 | 用户/系统添加 |
3.1 Resource:Agent 可以引用的外部知识
- 特点:用户主动添加(如产品手册、代码仓库);添加后内容很少变;按项目/主题以目录组织,并自动抽取多层信息(L0/L1)。
- 示例:API 文档、FAQ、代码仓库、研究论文、技术规范。
- URI:
viking://resources/{project}/... - 代码:
# 添加资源(支持 URL / 本地文件 / 目录)
client.add_resource("https://docs.example.com/api.pdf", reason="API 文档")
# 在资源范围内检索
results = client.find("认证方法", target_uri="viking://resources/")
3.2 Memory:Agent 从交互中「学」到的持久知识
- 特点:由 Agent 主动提取和记录;随交互持续更新;针对特定用户/Peer 个性化。
- 关键认知:Memory 不存在独立的
viking://agent/memories目录——它写在当前用户或 Peer 的命名空间下(viking://user/{user_id}/memories/...或viking://user/{user_id}/peers/{peer_id}/memories/...)。
官方内置的 11 种记忆类型(这是理解 OpenViking「记忆观」的关键):
| 类型 | 默认位置 | 说明 |
|---|---|---|
profile |
user/memories/profile.md | 用户基本信息 |
preferences |
user/memories/preferences/ | 按主题组织的用户偏好 |
entities |
user/memories/entities/ | 人物、项目、组织等实体知识 |
events |
user/memories/events/ | 决策、里程碑等事件记录 |
identity |
user/memories/identity.md | 助手的名称、形象、气质、自我介绍 |
soul |
user/memories/soul.md | 助手的核心原则、边界、风格、连续性 |
cases |
user/memories/cases/ | 用于训练和评估的任务案例 |
trajectories |
user/memories/trajectories/ | 可复用的任务执行轨迹 |
experiences |
user/memories/experiences/ | 从执行结果中提炼的可复用经验 |
tools |
user/memories/tools/ | 工具使用经验与最佳实践 |
skills |
user/memories/skills/ | 技能执行经验与工作流策略 |
新手理解三个维度:
- 「用户与环境」= 它知道用户是谁(
profile/preferences/entities/events)- 「助手身份」= 它知道自己是谁(
identity/soul)——这是很多框架缺失的- 「任务执行与学习」= 它知道自己怎么把事干成(
cases/trajectories/experiences/tools/skills)
记忆从会话中自动提取,开发者不需要手写:
session = client.session()
await session.add_message("user", [{"type": "text", "text": "我喜欢深色模式"}])
commit = await session.commit() # 启动后台记忆提取
task = await client.get_task(job_id) # 轮询直到 status == "completed"
# 搜索记忆
results = await client.find("用户界面偏好", target_uri="viking://user/memories/")
3.3 Skill:Agent 可以调用的能力
- 定义:Skill 是 Agent 可以调用的能力,属于
AgentDefinedContextType。包括传统工作流(如搜索、代码生成)、通信端点、工具配置、支付能力等。运行时定义相对静态,但「用得好不好」的经验会进 Memory。 - 存储位置:
- 用户私有的:
viking://user/skills/{skill-name}/ - 通过
--uri覆盖为全局共享的:viking://agent/skills/{skill-name}/
- 用户私有的:
- 目录结构(自身也遵循 L0/L1/L2):
viking://user/skills/search-web/
├── .abstract.md # L0: 简短描述
├── SKILL.md # L1: 详细概览
└── scripts # L2: 完整定义
- 代码:
await client.add_skill({
"name": "search-web",
"description": "搜索网络获取信息",
"content": "# search-web\n..."
})
# 全局共享:ov skills add search-web -p viking://agent/skills
3.4 统一检索:三类一起搜
Agent 常常需要同时找「用户偏好 + 相关文档 + 可用技能」,OpenViking 支持跨类型统一检索:
results = await client.find("用户认证") # 不指定 target_uri,全量搜
for ctx in results.memories: print(f"记忆: {ctx.uri}")
for ctx in results.resources: print(f"资源: {ctx.uri}")
for ctx in results.skills: print(f"技能: {ctx.uri}")
第 4 章 核心概念三:L0/L1/L2 三层信息模型(省 Token 的核心)
这是 OpenViking 最优雅、也最值得理解的设计。本质问题是:上下文窗口(Token 上限)有限,但知识无限,怎么办?
人类看书不会把整本书背下来——先看目录(L0),再看章节导言(L1),只有真要细读才翻到正文(L2)。OpenViking 把这套行为工程化了。
4.1 三层定义
| 层级 | 文件 | Token | 用途 |
|---|---|---|---|
| L0 摘要 | .abstract.md |
~100 tokens | 向量搜索、快速过滤 |
| L1 概览 | .overview.md |
~2k tokens | Rerank 精排、内容导航 |
| L2 详情 | 原始文件/子目录 | 无限制 | 完整内容、按需加载 |
L0 示例(超短,让 Agent 一眼感知主题):
API 认证指南,涵盖 OAuth 2.0、JWT 令牌和 API 密钥的安全访问方式。
L1 示例(适中,告诉 Agent 内容结构和「去哪读详细」):
# 认证指南概览
本指南涵盖 API 的三种认证方式:
## 章节
- **OAuth 2.0** (L2: oauth.md): 完整 OAuth 流程和代码示例
- **JWT 令牌** (L2: jwt.md): 令牌生成和验证
- **API 密钥** (L2: api-keys.md): 简单的密钥认证
## 要点
- OAuth 2.0 推荐用于面向用户的应用
- JWT 用于服务间通信
## 访问
使用 read("viking://resources/docs/auth/oauth.md") 获取完整文档。
L2:完整原文,只在确认需要时才 read() 加载。
📊 图示:L0/L1/L2 自底向上聚合
4.2 它们是怎么自动生成的?
- 何时生成:① 添加资源时,Parser 解析后由 SemanticQueue 异步生成;② 会话归档压缩旧消息时,生成历史片段的 L0/L1。
- 生成方向:叶子节点 → 父目录 → 根目录(自底向上)。子目录的 L0 会被聚合进父目录的 L1,形成层级导航。
- 由谁生成:
SemanticProcessor(资源/技能语义生成)、SessionCompressor(会话历史语义生成)。
统一目录结构:
viking://resources/docs/auth/
├── .abstract.md # L0: ~100 tokens
├── .overview.md # L1: ~1k tokens
├── .relations.json # 相关资源
├── oauth.md # L2: 完整内容
├── jwt.md # L2
└── api-keys.md # L2
4.3 多模态支持
- L0/L1 永远是文本(Markdown),方便检索和阅读;
- L2 可以是任何格式(文本、图片、视频、音频);
- 二进制内容的 L0/L1 用文本描述(如「一张工作室布局图,包含……」),让 Agent 即使不加载原图也能感知它。
4.4 怎么省 Token?——给新手的策略
# 先用 L1 概览判断,只在确实不够时才读 L2
overview = client.overview(uri)
if needs_more_detail(overview):
content = client.read(uri)
| 场景 | 推荐层级 |
|---|---|
| 快速相关性检查 | L0 |
| 理解内容范围 | L1 |
| 详细信息提取 | L2 |
| 为 LLM 构建上下文 | L1 通常就够 |
原理总结:L0 超短用于「粗筛」避免加载大文件;L1 提供导航,多数情况下替代完整 L2;L2 无限制但严格按需。通过「轻量筛选 → 中等导航 → 精准加载」的递进,在保住信息完整的同时最大化省 Token。官方在 LoCoMo 等基准上报告了 63%–91% 的 Token 消耗下降。
第 5 章 核心概念四:会话与记忆自演化
Session(会话)是 Agent 与用户一次完整交互的载体。OpenViking 的会话管理不止「存聊天记录」,而是构成记忆自演化闭环。
5.1 生命周期:创建 → 交互 → 提交
session = client.session(session_id="chat_001")
session.add_message("user", [TextPart("怎么配置 embedding?")])
session.commit()
小贴士:用
client.get_session(..., auto_create=True)可在会话不存在时自动创建。
消息结构(新手了解有四种 Part):
TextPart:文本ImagePart:图片 URL(记忆提取时可用 VLM 转成文字描述)ContextPart:引用某个上下文(URI + 摘要)ToolPart:工具调用(输入 + 输出)
📊 图示:会话生命周期与 commit 两阶段提交
5.2 使用追踪 used()
告诉系统「这次回答用了哪些上下文 / 技能」,这对后续记忆提取和重要性统计很重要:
session.used(contexts=["viking://user/memories/profile.md"])
session.used(skill={"uri": "viking://user/skills/code-search",
"input": "search config", "output": "found 3 files", "success": True})
5.3 commit() 两阶段提交(关键!)
commit() 分两阶段,同步立即返回,重活后台异步做:
Phase 1(同步,立即完成):
- 递增
compression_index - 把消息写入归档目录
messages.jsonl - 清空当前消息列表
- 返回
task_id
Phase 2(异步后台):
5. 生成结构化摘要(LLM)→ 写入 .abstract.md / .overview.md
6. 提取长期记忆
7. 写入 memory_diff.json(记忆变更审计日志)
8. 更新 active_count(使用次数)
9. 写入 .done 完成标记
result = session.commit()
# {"status": "accepted", "task_id": "uuid-xxx", "archive_uri": "...", "archived": True}
task = client.get_task(result["task_id"])
# task["status"]: pending | running | completed | failed
5.4 记忆提取与去重闭环
消息 → LLM 提取 → 候选记忆
→ 向量预过滤(找相似旧记忆)
→ LLM 去重决策(candidate: skip/create/none + item: merge/delete)
→ 写入 AGFS → 向量化
| 层级 | 决策 | 说明 |
|---|---|---|
| Candidate | skip | 候选重复,跳过 |
| Candidate | create | 创建;必要时先删冲突旧记忆 |
| Candidate | none | 不创建,只处理已有记忆 |
| Existing item | merge | 合并到已有记忆 |
| Existing item | delete | 删除冲突的已有记忆 |
memory_diff.json 审计日志(每次 commit 都会写,便于回溯):
{
"archive_uri": "viking://user/{user_id}/sessions/{sid}/history/archive_001",
"extracted_at": "2026-04-21T10:00:00Z",
"operations": {
"adds": [{"uri": ".../identity.md", "memory_type": "identity", "after": "..."}],
"updates": [{"uri": ".../project.md", "memory_type": "context", "before": "...", "after": "..."}],
"deletes": [{"uri": ".../old.md", "memory_type": "context", "deleted_content": "..."}]
},
"summary": {"total_adds": 1, "total_updates": 1, "total_deletes": 1}
}
即使这次没有记忆变动,也会写入一个全 0 的空结构,保证可审计。
5.5 Peer Memory:为多对象隔离记忆
当 Agent 同时服务多个交互对象(比如一个助手同时对接多个客户/子系统),可以为每个 Peer 维护独立记忆空间:
viking://user/{user_id}/peers/{peer_id}/memories/
viking://user/{user_id}/peers/{peer_id}/resources/
提交会话时,若对话涉及稳定的 Peer,相关记忆会落入对应 Peer 空间,实现记忆隔离 + 共享。
5.6 会话与记忆的存储结构(一图总览)
viking://user/{user_id}/sessions/{session_id}/
├── messages.jsonl # 当前消息
├── .abstract.md # 当前摘要
├── .overview.md # 当前概览
├── history/
│ └── archive_001/
│ ├── messages.jsonl
│ ├── .abstract.md
│ ├── .overview.md
│ ├── memory_diff.json # 记忆变更审计
│ └── .done
└── tools/{tool_id}/tool.json
viking://user/memories/ # 11 类记忆目录
├── profile.md identity.md soul.md
├── preferences/ entities/ events/
├── cases/ trajectories/ experiences/ tools/ skills/
第三部分:实现原理(深入引擎内部)
第 6 章 系统架构总览
6.1 四层架构
📊 图示:四层架构与数据流(彩色可视化)
┌──────────────────────────────────────────────────────────────┐
│ Client 层 │
│ AsyncOpenViking / SyncOpenViking / HTTPClient / ov CLI / Go │
└───────────────────────────────┬──────────────────────────────┘
│ 委托
┌───────────────────────────────▼──────────────────────────────┐
│ Service 层(业务逻辑) │
│ FSService / SearchService / SessionService / ResourceService │
│ RelationService / PackService / DebugService │
└───────────────────────────────┬──────────────────────────────┘
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Retrieve │ │ Session │ │ Parse │
│ (上下文检索) │ │ (会话管理) │ │ (上下文提取) │
│ search/find │ │ add/used │ │ 文档解析 │
│ 意图分析 │ │ commit │ │ L0/L1/L2 │
│ Rerank │ │ 压缩/去重 │ │ 树构建 │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ 记忆提取 │
│ ▼ │
│ ┌─────────────┐ │
│ │ Compressor │ │
│ │ 压缩/去重 │ │
│ └──────┬──────┘ │
└───────────────────┼────────────────────┘
▼
┌───────────────────────────┐
│ Storage 层 │
│ AGFS(内容) + 向量库(索引) │
└───────────────────────────┘
核心模块职责表:
| 模块 | 职责 | 关键能力 |
|---|---|---|
| Client | 统一入口 | 所有操作接口,委托 Service |
| Service | 业务逻辑 | 7 个 Service(见下) |
| Retrieve | 上下文检索 | 意图分析、层级检索、Rerank |
| Session | 会话管理 | 消息记录、使用追踪、压缩、记忆提交 |
| Parse | 上下文提取 | 文档解析、树构建、异步语义生成 |
| Compressor | 记忆压缩 | Schema 驱动提取、LLM 去重 |
| Storage | 存储 | VikingFS、向量索引、AGFS |
Service 层方法(解耦传输层,HTTP/CLI 复用):
| Service | 职责 | 主要方法 |
|---|---|---|
| FSService | 文件系统操作 | ls mkdir rm mv tree stat read abstract overview grep glob |
| SearchService | 语义搜索 | search find |
| SessionService | 会话管理 | session sessions commit delete |
| ResourceService | 资源导入 | add_resource add_skill wait_processed |
| RelationService | 关联管理 | relations link unlink |
| PackService | 导入导出 | export_ovpack import_ovpack backup restore |
| DebugService | 调试 | observer(观测检索轨迹) |
6.2 三条数据流
① 添加上下文(写路径):
输入 → Parser → TreeBuilder → AGFS → SemanticQueue → 向量库
- Parser:解析文档、建文件/目录结构(无 LLM 调用)
- TreeBuilder:把临时目录移入 AGFS,入队语义处理
- SemanticQueue:异步自底向上生成 L0/L1
- 向量库:建索引用于语义搜索
② 检索上下文(读路径):
查询 → 意图分析 → 层级检索 → Rerank → 结果
③ 会话提交(记忆路径):
消息 → 压缩 → 归档 → 记忆提取 → 存储
6.3 设计原则(官方提炼)
| 原则 | 说明 |
|---|---|
| 存储层纯粹 | 存储层只做 AGFS 操作和基础向量搜索,Rerank 在检索层 |
| 三层信息 | L0/L1/L2 渐进式加载,省 Token |
| 两阶段检索 | 向量召回候选 + Rerank 精排 |
| 单一数据源 | 内容只从 AGFS 读,向量库仅存引用和索引 |
第 7 章 双层存储:内容-索引分离
7.1 为什么要分离?
传统做法把「文件内容」和「向量索引」混在一起,导致:向量库内存被大文件撑爆、内容与索引耦合难扩展、改一份要两处同步。
OpenViking 用双层存储彻底解耦:
┌─────────────────────────────────────────┐
│ VikingFS (URI 抽象层) │
│ URI 映射 · 层级访问 · 关联管理 │
└────────────────┬────────────────────────┘
┌────────┴────────┐
│ │
┌───────▼────────┐ ┌─────▼───────────┐
│ 向量库索引 │ │ AGFS │
│ (语义搜索) │ │ (内容存储) │
└────────────────┘ └─────────────────┘
| 存储层 | 职责 | 存储内容 |
|---|---|---|
| AGFS | 内容存储 | L0/L1/L2 完整内容、多媒体、关联关系 |
| 向量库 | 索引存储 | URI、向量、元数据(不存文件内容) |
分离的好处:① 职责清晰;② 内存优化(向量库不存正文);③ 单一数据源(内容都从 AGFS 读);④ 可独立扩展(向量库和 AGFS 分别扩容)。
注:AGFS 已用 Rust 重写为 RAGFS,性能更强。
7.2 AGFS 内容存储
提供 POSIX 风格文件操作,支持多种后端:
| 后端 | 说明 | 配置 |
|---|---|---|
| localfs | 本地文件系统 | path |
| s3fs | S3 兼容存储 | bucket, endpoint |
| memory | 内存(测试用) | - |
多写模式:配置 storage.agfs.backups 后,顶层 backend 是 primary(权威写入),backups.items[] 是副本/迁移/读加速。用户接口不变,内部用 .redirect.json 和 .sync_log.json 维护映射(对用户不可见)。
7.3 向量库索引
向量库只存「索引」,Context 集合 Schema 如下:
| 字段 | 类型 | 说明 |
|---|---|---|
| id / uri / parent_uri | string | 主键、资源 URI、父目录 URI |
| context_type | string | resource/memory/skill |
| is_leaf | bool | 是否叶子(文件) |
| vector / sparse_vector | vector | 密集 / 稀疏向量(混合检索) |
| abstract | string | L0 摘要文本 |
| name / description | string | 名称 / 描述 |
| created_at / active_count | - | 创建时间 / 使用次数 |
索引策略:flat_hybrid 混合索引 + cosine 距离 + int8 量化。
后端支持:local(本地持久化)、http(远程)、volcengine(火山引擎 VikingDB)。
一致性由 VikingFS 自动维护(新手不用操心同步):
viking_fs.rm("viking://resources/docs/auth", recursive=True)
# 自动递归删除向量库中 uri 以此开头的所有记录
viking_fs.mv("viking://resources/docs/auth",
"viking://resources/docs/authentication")
# 自动更新向量库中的 uri 和 parent_uri
7.4 VikingFS 虚拟文件系统
VikingFS 是统一 URI 抽象层,屏蔽底层存储:
📊 图示:VikingFS → AGFS + 向量库 双层存储
viking://resources/docs/auth → /local/{account_id}/resources/docs/auth
viking://user/memories → /local/{account_id}/user/{user_id}/memories
核心 API:read write mkdir rm mv abstract overview relations find。
关联管理通过 .relations.json:
viking_fs.link(from_uri="viking://resources/docs/auth",
uris=["viking://resources/docs/security"], reason="相关安全文档")
relations = viking_fs.relations("viking://resources/docs/auth")
第 8 章 上下文提取流水线(Parser → TreeBuilder → SemanticQueue)
这是「往 OpenViking 里加一份文档」时,引擎内部发生的事。
8.1 总体流水线
输入文件 → Parser → TreeBuilder → SemanticQueue → 向量库
↓ ↓ ↓
解析转换 文件移动 L0/L1 生成
(无 LLM) 入队语义 (LLM 异步)
设计原则:解析与语义分离——Parser 不调 LLM(快、省),语义生成异步进行。
📊 图示:上下文提取流水线时序(Parser → TreeBuilder → SemanticQueue → 向量库)
8.2 Parser(解析器)
负责格式转换与结构化,在临时目录建文件结构。
支持格式:
| 格式 | 解析器 | 扩展名 | 状态 |
|---|---|---|---|
| Markdown | MarkdownParser | .md .markdown | 已支持 |
| 纯文本 | TextParser | .txt | 已支持 |
| PDFParser | 已支持 | ||
| HTML | HTMLParser | .html .htm | 已支持 |
| 代码 | CodeRepositoryParser | 遵循 .gitignore | 已支持 |
| 图片/视频/音频 | Image/Video/AudioParser | png/jpg/mp4/… | 规划/部分 |
智能分割:
if document_tokens <= 1024: → 保存为单文件
else:
→ 按标题分割
→ 小节 < 512 tokens 合并
→ 大节 > 1024 tokens 创建子目录
8.3 TreeBuilder(树构建器)
把临时目录移动到 AGFS,并入队语义处理。5 个阶段:① 找文档根目录;② 确定目标 URI(按 scope 映射);③ 递归移动目录树;④ 清理临时目录;⑤ 入队语义生成。
| scope | 基础 URI |
|---|---|
| resources | viking://resources |
| user | viking://user |
8.4 SemanticQueue(语义处理队列)
异步生成 L0/L1 并向量化。处理顺序:叶子 → 父 → 根(自底向上)。单目录步骤:
- 并发生成文件摘要(并发上限
max_concurrent_llm=10) - 收集子目录摘要
- 生成
.overview.md(L1) - 从 overview 提取
.abstract.md(L0) - 写入 AGFS
- 向量化,入队 EmbeddingQueue
代码文件的 AST 骨架提取(省钱妙招):
对 ≥100 行的代码文件,OpenViking 可用 tree-sitter 抽取结构骨架(模块 docstring、import、类继承与方法签名、顶层函数签名),跳过 LLM 调用。通过 ov.conf 的 code_summary_mode 控制:
"ast":只抽 AST 骨架(默认,最省)"llm":全走 LLM"ast_llm":先抽骨架再辅助 LLM
支持 Python/JS/TS/Java/C/C++/Rust/Go/C#/PHP/Lua,其余 fallback 到 LLM。
8.5 三类上下文的提取差异
| 环节 | Resource | Memory | Skill |
|---|---|---|---|
| 基础 URI | viking://resources | viking://user/memories | viking://user/skills |
| TreeBuilder scope | resources | user | user |
| SemanticMsg type | resource | memory | skill |
记忆提取走:SessionCompressorV2 → ExtractLoop → MemoryUpdater → SemanticQueue。
第 9 章 检索机制:目录递归检索
这是 OpenViking 取代「扁平向量 RAG」的核心算法,也是「检索效果不佳」挑战的解法。
9.1 两阶段检索总览
查询 → 意图分析 → 层级检索 → Rerank → 结果
↓ ↓ ↓
TypedQuery 目录递归 精排评分
📊 图示:检索机制流程(意图分析 → 层级检索 → Rerank)
9.2 find() vs search()
| 特性 | find() |
search() |
|---|---|---|
| 会话上下文 | 不需要 | 需要 |
| 意图分析 | 不使用 | 使用 LLM 分析 |
| 查询数量 | 单一查询 | 0–5 个 TypedQuery |
| 延迟 | 低 | 较高 |
| 适用 | 简单查询 | 复杂任务 |
# 简单查询
results = await client.find("OAuth 认证", target_uri="viking://resources/")
# 复杂任务(需要会话上下文)
results = await client.search("帮我创建一个 RFC 文档", session_info=session)
9.3 意图分析(IntentAnalyzer)
用 LLM 把用户查询「翻译」成结构化的检索计划,生成 0–5 个 TypedQuery:
@dataclass
class TypedQuery:
query: str # 重写后的查询
context_type: ContextType # MEMORY/RESOURCE/SKILL
intent: str # 查询目的
priority: int # 1-5 优先级
- 输入:会话压缩摘要 + 最近 5 条消息 + 当前查询
- 查询风格:skill 以动词开头(“创建 RFC 文档”)、resource 是名词短语(“RFC 模板”)、memory 是"用户XX"(“用户的代码规范偏好”)
- 特殊情况:0 个查询 = 闲聊/问候;多个查询 = 复杂任务需技能+资源+记忆
9.4 层级检索(HierarchicalRetriever)
用优先队列递归搜索目录结构,关键在「先定位好目录,再深度钻取」:
Step1: 按 context_type 确定根目录
Step2: 全局向量搜索定位起始目录
Step3: 合并起始点 + Rerank 评分
Step4: 递归搜索(优先队列)
Step5: 转为 MatchedContext
根目录映射:MEMORY→viking://user/memories、RESOURCE→viking://resources、SKILL→viking://user/skills。
递归算法(含分数传播 + 收敛检测):
while dir_queue:
current_uri, parent_score = heapq.heappop(dir_queue)
results = await search(parent_uri=current_uri)
for r in results:
# 分数传播:子节点分数 = α*自身 + (1-α)*父分数
final_score = alpha * embedding_score + (1-alpha) * parent_score
if final_score > threshold:
collected.append(r)
if not r.is_leaf: # 目录则继续递归
heapq.heappush(dir_queue, (r.uri, final_score))
if topk_unchanged_for_3_rounds: # 收敛检测,提前停止
break
| 参数 | 值 | 说明 |
|---|---|---|
score_propagation_alpha |
1.0 | 子节点自身分数权重;1.0 表示仅用子节点自身分数 |
MAX_CONVERGENCE_ROUNDS |
3 | 收敛检测轮数 |
GLOBAL_SEARCH_TOPK |
10 | 全局搜索候选数 |
MAX_RELATIONS |
5 | 每资源最大关联数 |
9.5 Rerank 精排
在 THINKING 模式(search 默认)下,对候选做精排:
- 触发:配置了 Rerank AK/SK 且使用 THINKING 模式
- 失败回退:Rerank 无效或 API 失败 → 回退向量分数
- 后端:火山引擎
doubao-seed-rerank - 使用位置:起始点评估 + 每层递归子节点评估
9.6 检索结果与可视化轨迹
返回结构:
@dataclass
class MatchedContext:
uri: str; context_type; is_leaf; abstract # L0 摘要
score: float; relations: List[RelatedContext]
@dataclass
class FindResult:
memories; resources; skills; query_plan; query_results; total
可视化检索轨迹:由于检索是确定性的「目录浏览 + 文件定位」过程,OpenViking 能完整记录「走过哪些目录、选中哪些片段、为何选中」,并通过 Web Studio(React + Vite 构建)可视化。这直接解决了「上下文不可观测」的挑战——调试不再是黑箱猜测。
第 10 章 会话提交与记忆闭环(原理视角)
把第 5 章的机制串起来看,OpenViking 的「自演化」本质是这条异步流水线:
对话消息
→ SessionCompressorV2 压缩(保留最近 N 轮,旧消息归档 + 生成 L0/L1)
→ ExtractLoop 用 LLM 抽取候选记忆
→ 向量预过滤找相似旧记忆
→ LLM 去重决策(skip/create/merge/delete)
→ MemoryUpdater 写 AGFS + 向量化
→ 写 memory_diff.json 审计
整个过程对开发者透明且异步——你只需 session.commit(),剩下的 OpenViking 在后台把 Agent「养」得越来越懂用户、越来越会干活。
第 11 章 部署模式
11.1 嵌入式模式(类似 SQLite)
client = OpenViking(path="./data")
自动启动 AGFS 子进程、用本地向量索引、单例模式。适合本地开发、单进程应用。
11.2 HTTP 模式(类似 PostgreSQL)
client = SyncHTTPClient(url="http://localhost:1933", api_key="xxx")
curl http://localhost:1933/api/v1/search/find \
-H "X-API-Key: xxx" -d '{"query": "how to use openviking"}'
Server 独立进程(openviking-server),支持任何能发 HTTP 的语言。适合团队共享、生产环境。
11.3 多语言架构(Polyglot)
| 语言 | 职责 |
|---|---|
| Python 3.10+ | 服务端、SDK、客户端、会话/检索/解析 |
| Rust | CLI(ov)、RAGFS 核心、高性能组件 |
| Go | AGFS 原始文件系统、Go SDK |
| TypeScript/React | Web Studio 前端 |
11.4 安全与加密
信封加密:主密钥 → 账户密钥 → 文件密钥,对上层透明;每账户独立密钥,多租户强隔离。
第四部分:动手实操 + 选型
第 12 章 5 分钟上手(新手逐行教程)
12.1 前置要求
- Python ≥ 3.10(Linux / macOS / Windows 均可)
- 稳定网络(下载依赖 + 访问模型服务)
12.2 安装
# 推荐 uv
uv tool install openviking --upgrade
# 或 pip
pip install openviking --upgrade --force-reinstall
# 或 pipx
pipx install openviking && pipx upgrade openviking
装完会有 ov(别名 openviking)命令和 openviking-server 服务。
12.3 准备模型
OpenViking 需要两类模型:
- VLM 模型:图像/内容理解(火山引擎豆包 / OpenAI GPT-4V / Codex 等)
- Embedding 模型:向量化与语义检索
12.4 配置环境
首次推荐用向导生成配置:
openviking-server init
openviking-server doctor
或手动写 ~/.openviking/ov.conf:
{
"embedding": {
"dense": {"api_base": "<endpoint>", "api_key": "<key>",
"provider": "<provider>", "dimension": 1024, "model": "<model>"}
},
"vlm": {
"api_base": "<endpoint>", "api_key": "<key>",
"provider": "<provider>", "model": "<model>"
}
}
配置在默认路径时自动加载;否则用 export OPENVIKING_CONFIG_FILE=/path/to/ov.conf。
12.5 运行第一个示例(逐行讲解)
创建 example.py:
import openviking as ov
client = ov.OpenViking(path="./data") # 1. 创建嵌入式客户端,数据存 ./data
try:
client.initialize() # 2. 初始化(启动 AGFS 子进程)
# 3. 添加资源:支持 URL / 文件 / 目录;本地目录默认遵循 .gitignore
# wait=True 会阻塞到语义处理(L0/L1 生成)完成
print("Wait for semantic processing...")
add_result = client.add_resource(
path="https://raw.githubusercontent.com/volcengine/OpenViking/refs/heads/main/README.md",
wait=True,
)
root_uri = add_result['root_uri']
# 4. 像用文件系统一样探索结构
ls_result = client.ls(root_uri)
print(f"Directory structure:\n{ls_result}\n")
# 5. glob 找所有 markdown 文件,read 读取第一个的前 200 字
glob_result = client.glob(pattern="**/*.md", uri=root_uri)
if glob_result['matches']:
content = client.read(glob_result['matches'][0])
print(f"Content preview: {content[:200]}...\n")
# 6. 获取 L0 摘要和 L1 概览(省 Token 的关键)
abstract = client.abstract(root_uri)
overview = client.overview(root_uri)
print(f"Abstract:\n{abstract}\n\nOverview:\n{overview}\n")
# 7. 语义检索
results = client.find("what is openviking", target_uri=root_uri)
print("Search results:")
for r in results.resources:
print(f" {r.uri} (score: {r.score:.4f})")
client.close() # 8. 关闭
except Exception as e:
print(f"Error: {e}")
运行 python example.py,预期看到目录结构、内容预览、摘要/概览、带分数的检索结果。🎉 你已跑通 OpenViking。
想跑服务端模式?用 Docker:
docker-compose up -d(镜像ghcr.io/volcengine/openviking:latest,默认 1933 端口 +/studioWeb 前端 + 内置 vikingbot)。
第 13 章 横向对比(选型参考)
📊 图示:扁平向量 RAG vs OpenViking 层级文件系统

为了看清 OpenViking 的定位,与主流开源方案对比:
| 维度 | OpenViking | Mem0 | Letta | Zep/Graphiti | LangMem |
|---|---|---|---|---|---|
| 架构范式 | 文件系统 + 层次化检索 | 向量 + 事实提取 | OS 式分层自编辑 | 时序知识图谱 | 模块化记忆原语 |
| 产品形态 | 可插拔基础设施 | 可插拔记忆层 | 完整 Agent 运行时 | 可插拔记忆层 | 框架组件 |
| 上下文范围 | 记忆+资源+技能 | 仅记忆 | 记忆+对话状态 | 仅记忆 | 仅记忆 |
| 结构化管理 | 虚拟文件系统(强) | 扁平向量(弱) | 分层(中) | 图谱(强) | 无 |
| Token 优化 | L0/L1/L2 三层 | 无 | 分页 | 无 | 无 |
| 时间推理 | 元数据级 | 元数据级 | 隐式 | 一等公民(强) | 情景记忆 |
| 自演化 | 多类记忆自动提取+去重 | 事实提取+去重 | Agent 自编辑 | 事实+过期 | 热/后台路径 |
| 可观测性 | 完整轨迹可视化 | 弱 | 弱 | 中 | 弱 |
| 集成复杂度 | 中等 | 极低 | 高 | 中(需图库) | 中(LangChain 绑定) |
结论性判断:
- 想要最简 API 上手 → Mem0;
- 想要完整 Agent 运行时 → Letta;
- 需要强时间推理(医疗/金融/合规) → Zep/Graphiti;
- 想要框架无关、统一治理三类上下文、强 Token 优化与可观测 → OpenViking。
第 14 章 核心优势与局限(客观总结)
优势:
- 统一治理:记忆/资源/技能一套 URI + API,天然可关联。
- 极致 Token 效率:L0/L1/L2 分层,不靠压缩/截断做减法,而是按需加载。
- 确定性可调试:文件系统范式让检索路径可追溯、可视化。
- 自演化记忆闭环:11 类记忆自动提取、去重、合并、审计。
- 灵活部署:嵌入式 ↔ HTTP,Python/Rust/Go/TS 多语言,MCP + VikingBot 多端。
局限:
- 时间推理较弱:相比 Zep 双时间线图谱,时间维度主要依赖元数据。
- 学习曲线偏陡:L0/L1/L2、目录分类、两阶段提交、Peer Memory 需一定投入。
- 生态早期:社区集成、教程、第三方贡献仍在成长中。
第 15 章 学习路线图(给新手的下一步)
建议顺序(与官方文档导航一致):
- 概念建立:本文第 1–5 章(或官方「简介」)。
- 动手跑通:官方「5 分钟上手」+ 本文第 12 章。
- 深入原理:官方「架构详解 / 上下文类型 / 上下文层级 / Viking URI / 存储架构 / 上下文提取 / 检索机制 / 会话管理」——即本文第 6–10 章。
- 进阶集成:MCP 接入、VikingBot(Telegram/飞书/钉钉/Slack/QQ)、Web Studio、
ovCLI、Pack 导入导出、多写存储、数据加密、多租户。
官方文档导航(权威、随版本更新):
- 快速开始:简介 / 5 分钟上手 / 服务端模式 / 安装 SOP / CLI 配置
- 核心概念:架构概述 / 上下文类型 / 上下文层级 / Viking URI / 存储架构 / 上下文提取 / 检索机制 / 会话管理
- Agent 集成:Claude Code / Codex / Cursor / TRAE / LangChain 等
- API 参考 / 常见问题 / 关于
本文概念、特性、API 与代码示例均以 OpenViking 官方文档(https://docs.openviking.ai/zh)为准,结合源码实现视角整理。官方文档持续更新,请以最新版本为权威来源。示例代码均为说明性片段,实际运行时请参照官方「配置指南」填入有效的模型服务地址与密钥。