1. 系统概览
OpenViking 是一个开源的、专为 AI Agent 设计的上下文数据库。
OpenViking 通过文件系统范式统一管理 Agent 所需要的上下文(记忆、资源和技能),
并实现上下文的分层供给与自我迭代,最终目标是降低 Agent 开发门槛,
让开发者更专注于业务创新而非底层上下文管理。
与其它记忆不同的是,他既有最开始的原文,也有高层级的语义理解。
数据召回的时候,数量以及准确性,都会有较大的效果和性能提升。
说明:
- 本地安装的时候,全部可以用类似 Sqlite 的方案,依赖三方包即可;
- 数据写入后,L1、L0 阶段需要 LLM 参与生成摘要、做语义理解;
- L2 如果原文超长,可以做逻辑语义拆分,符号提取 / 虚拟子目录 / 偏移分页;
1.1 系统架构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| +-------------------------------------------------------------------------+ | AI Agent Runtime | | (Find / LS / Read / Tree / Memory Extraction / Tool Invocation) | +------------------------------------+------------------------------------+ | +------------------------------------v------------------------------------+ | OpenViking Core Engine | | | | +---------------------------+ +-------------------------------+ | | | Virtual File System | | Hierarchical Context Store | | | | viking:// schema router | <---> | - L0: Abstract Sidecar | | | | (Resources/Memory/Skills)| | - L1: Overview Sidecar | | | +---------------------------+ | - L2: Raw Payload | | | | +-------------------------------+ | | v | | | +---------------------------+ v | | | Recursive Retrieval Router| +-------------------------------+ | | | (Intent Analysis -> | <---> | Vector Engine & Reranker | | | | Global Path Locate -> | | (Embedding / Dense Vector / | | | | Subtree Recursive Zoom) | | Lexical BM25 / Cross-Encoder)| | | +---------------------------+ +-------------------------------+ | +------------------------------------+------------------------------------+ | +------------------------------------v------------------------------------+ | Persistence / Storage Layer | | (Local Disk / Object Store / Key-Value / Vector Index) | +-------------------------------------------------------------------------+
|
1.2 文件结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| viking:// ├── resources/ # 资源:项目文档、代码库、网页等 │ └── my_project/ ├── user/ │ └── {user_id}/ # 当前用户的私有上下文 │ ├── memories/ # 用户记忆:用户个性化、实体状态、交互历史(动态演进)。 │ ├── resources/ # 用户私有资源:文档、代码库、规约(静态长期)。 │ ├── skills/ # 用户私有技能(默认) │ ├── peers/ │ │ └── {peer_id}/ │ │ ├── memories/ │ │ └── resources/ │ └── sessions/ └── agent/ └── skills/ # account 全局共享技能(可选)
|
1.3 上下文分层:
- L0(Abstract,~256 字符): 作为全局向量检索与剪枝路由的轻量索引。
- L1(Overview,~4000 字符): 提供该目录/模块的结构骨架与语义摘要,专用于Rerank 与上下文粗排。
- L2(Detail,无上限): 原始 Payload(代码段、文档正文、执行轨迹)。L0/L1 命中后按需加载。
2. 数据入库与检索
保留了向量检索、BM25检索等,和常规的检索方案很类似。
相比于单纯的 embedding,这种综合性的方式相对来说比较准确,能够互补。
虽然多路召回也能做到类似的效果,但是多路+重排序都需要应用侧开发,openviking 不用。
2.1 数据写入过程
同步的过程只有写 meta + L2 原文。
涉及到数据加工需要异步处理。
在异步处理完成之前,涉及到语义、向量等操作是不可用的,只能直接查 L2 的文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| +-------------------------------------------------------------------------------------------------------------+ | 1. 写入接入层 (API / SDK / MCP) | | Client 发起 POST /write (路径 + 正文) | +------------------------------------------------------+------------------------------------------------------+ | v +-------------------------------------------------------------------------------------------------------------+ | 2. 同步快速通道 (Sync Fast Path) | | +-------------------------------------+ +------------------------------------+ +--------------------+ | | | Metadata Store | | Object Storage | | Event Queue | | | | - 鉴权 & 创建 VFS Node (viking://) | | - 写入 L2 Raw Payload 原文 (S3) | | - 投递异步解析任务 | | | | - 状态置为 Processing, Dirty: True | | (代码/Markdown/PDF/Session) | | (Task Payload) | | | +-------------------------------------+ +------------------------------------+ +---------+----------+ | +-----------------------------------------------------------------------------------------------|-------------+ | (返回 200 OK 给 Client) | v (后台异步处理) v +-------------------------------------------------------------------------------------------------------------+ | 3. 异步语法与结构解析 (AST / Parsing) | | +-----------------------------------------------------+ +-----------------------------------------------+ | | | 代码类 (Tree-sitter AST) | | 文档类 (Markdown DOM / Layout) | | | | - 提取符号表 (Function/Struct/ErrorCode/Interface) | | - 提取 H1~H6 标题层级树与面包屑路径 | | | | - 按语义边界切分 AST 块 (非机械字数暴力截断) | | - 剔除页眉页脚,保留完整自然段落与表格结构 | | | +-----------------------------------------------------+ +-----------------------------------------------+ | +------------------------------------------------------+------------------------------------------------------+ | v +-------------------------------------------------------------------------------------------------------------+ | 4. 自底向上分层 Sidecar 生成 (LLM Synthesis) | | +-------------------------------------------------------------------------------------------------------+ | | | 目录级 L1 概览 (.overview.md, ~4000 字符) | | | | 聚合目录下所有文件的 AST 骨架 + 核心接口 + 模块职责 (用于 Cross-Encoder Rerank 精排) | | | +---------------------------------------------------+---------------------------------------------------+ | | | | v | +-------------------------------------------------------------------------------------------------------+ | | | 目录级 L0 摘要 (.abstract.md, ~256 字符) | | | | 基于 L1 提炼高密度领域关键词与路由锚点 (用于全局向量检索快速初筛) | | | +-------------------------------------------------------------------------------------------------------+ | +------------------------------------------------------+------------------------------------------------------+ | v +-------------------------------------------------------------------------------------------------------------+ | 5. 双轨索引并行构建 (Dual-Track Indexing) | | | +---------------------------------------------------+ +------------------------------------------------+ | | | 稠密向量通道 (Dense Vector) | | 稀疏倒排通道 (Sparse BM25) | | | | - 对 L0 摘要 / L1 概览调用 Embedding 计算向量 | | - 对 AST 提取的精确符号 (函数名/错误码) 分词 | | | | - 写入向量索引引擎 (HNSW / Milvus / Qdrant) | | - 写入轻量倒排引擎 (Tantivy / SQLite FTS) | | | | - 绑定 VFS 节点路径 (用于全局与子树语义路由) | | - 建立精准倒排链 (用于无视层级的直达穿透召回) | | | +---------------------------------------------------+ +------------------------------------------------+ | +------------------------------------------------------+------------------------------------------------------+ | v +-------------------------------------------------------------------------------------------------------------+ | 6. 原子提交与级联更新 (Atomic Commit) | | +-------------------------------------------------------------------------------------------------------+ | | | 1. Metadata Store 更新状态: Processing -> Ready | | | | 2. 沿目录树向上级联检查父节点: 若需要则增量微调父目录 L0,并清除 Dirty 标记 | | | | 3. 全链路就绪: 对 Agent 的 find / ls / read / recursive search 完全可见 | | | +-------------------------------------------------------------------------------------------------------+ | +-------------------------------------------------------------------------------------------------------------+
|
2.2 数据加工过程
从 L2 原始数据开始,逐步往上层处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [ L2: 原始叶子文件 (Code / Markdown / PDF) ] │ ├── 1. 基于 AST / DOM 的语义结构化解析与清洗 │ (保留函数签名、Markdown 标题树、调用关系,剔除样板代码) │ ▼ [ L1 Sidecar: 目录级概览 (.overview.md, ~4000 chars) ] │ ├── 2. 局部上下文提炼:综合该目录下所有叶子文件的导出符号、核心职责生成 │ ▼ [ L0 Sidecar: 目录级极简索引 (.abstract.md, ~256 chars) ] │ └── 3. 全局路由锚点:提取高密度的领域概念、核心关键字与路由元数据
|
2.3 检索过程
OpenViking 内置了多路召回(Hybrid Retrieval)与重排(Rerank)机制,但其设计并非传统搜索系统中对单一切片(Chunk)的扁平堆叠,而是与它的 VFS 虚拟文件树拓扑以及 L0/L1/L2 分层结构紧密绑定的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| [ User Query / Intent ] │ ▼ ┌─────────────────────────────────────────────────────────-─┐ │ 1. 意图分解与查询改写 (Intent Decomposition) │ │ - 提取语义 Query (Dense) │ │ - 提取结构化/关键词 Query (Sparse / Lexical / Path Filter)│ └──────────────────────────┬───────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────┐ │ 2. 多路召回阶段 (Multi-Channel Retrieval) │ │ ├── 路径 A: 稠密向量检索 (Dense Embedding on L0/L1) │ │ ├── 路径 B: 词法/关键词检索 (BM25 / Lexical on Sidecars) │ │ └── 路径 C: 确定性路径前缀过滤 (VFS Path Scoping) │ └──────────────────────────┬───────────────────────────────┘ │ 融合生成候选集 (Candidate Sets) ▼ ┌──────────────────────────────────────────────────────────┐ │ 3. 混合融合与粗排 (Fusion: RRF / Linear Combination) │ │ - 使用倒数排名融合 (RRF) 归一化多路得分 │ │ - 输出初步 Top-N 候选目录/节点 │ └──────────────────────────┬───────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────┐ │ 4. 交叉编码精排阶段 (Cross-Encoder Reranker on L1) │ │ - 将 Query 与 L1 (.overview.md,~4000字符) 拼接打分 │ │ - 评估完整语境相关度,裁决是否深入递归 │ └──────────────────────────┬───────────────────────────────┘ │ 命中高分目录 / 节点 ▼ ┌──────────────────────────────────────────────────────────┐ │ 5. 递归下探与 L2 按需加载 (Recursive Tree-Search & Payload) │ │ - 若为目录:递归进入子树重复 2~4 步 │ │ - 若为叶子:读取 L2 正文并附带 Trace Path 返回给 Agent │ └──────────────────────────────────────────────────────────┘
|
3. 存储架构
OpenViking 属于存算分离的架构
上层是属于无状态的计算节点,底层可以接入各类云存储(L2)、向量数据库(L0/L1);
Metadata Store 主要承载
- VFS 目录树拓扑与路径映射(Virtual File System Topology)
- 多租户沙箱与 ACL 权限元数据(Auth & Access Control)
- 存储寻址指针(Payload & Vector Address Index)
- 写入流水线状态机(Ingestion State Machine)
- 记忆与会话元数据(Memory & Session Metadata)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| +-----------------------------------------------------------------------------------+ | API Gateway / Ingress Router | | (鉴权、租户路由、Rate Limiting、Session Affinity) | +-----------------------------------------+-----------------------------------------+ | +---------------------------------+---------------------------------+ | | +-------v-------------------------------+ +-------------------------------v-------+ | OpenViking Stateless Server Node 1 | | OpenViking Stateless Server Node 2 | | - VFS URI 解析与鉴权沙箱 | | - VFS URI 解析与鉴权沙箱 | | - 递归检索状态机 (Recursive Search) | | - 递归检索状态机 (Recursive Search) | | - 运行时 Context Assembly | | - 运行时 Context Assembly | +-------+-------------------------------+ +-------------------------------+-------+ | | +---------------------------------+---------------------------------+ | +-----------------------------------------v-----------------------------------------+ | Asynchronous Ingestion & Memory Worker Cluster | | (分布式消息队列/任务调度:AST 解析、L0/L1 生成、Session 异步抽取) | +-----------------------------------------+-----------------------------------------+ | +-----------------------------------------v-----------------------------------------+ | Enterprise Distributed Storage Layer | | | | +---------------------------+ +---------------------------+ +---------------+ | | | Object Storage | | Distributed Vector DB | | Metadata Store| | | | (S3 / MinIO / TOS / OSS) | | (Milvus / VikingDB / Qdrant) | | (PostgreSQL / | | | -> 承载海量 L2 原始 Payload| | -> 承载分布式 L0/L1 向量索引 | | Distributed | | | | (代码/PDF/历史 Trajectory| | 与 ANN 稠密检索 | | KV / MySQL) | | | +---------------------------+ +---------------------------+ +---------------+ | +-----------------------------------------------------------------------------------+
|
4. 怎么使用?
4.1 直接调用 SDK
如果是在自建应用程序,可以在对应的 AOP / middleware / 回调函数里面进行数据写入。
或者通过 MQ 解耦,异步处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package main
import ( "context" "github.com/volcengine/OpenViking/sdk/go" )
func main() { client, err := openviking.NewClient(openviking.Config{ BaseURL: "http://localhost:1933", APIKey: "your-api-key", }) if err != nil { panic(err) } defer client.CloseIdleConnections()
err = client.AddResource(context.Background(), &openviking.AddResourceRequest{ URI: "viking://resources/internal_wiki/", SourceURL: "https://wiki.company.com/docs/api_v2.md", })
err = client.Write(context.Background(), &openviking.WriteRequest{ URI: "viking://user/10086/memories/preferences.md", Content: []byte("用户更倾向于使用 Golang 进行后端开发,关注高并发架构设计。"), }) }
|
4.2 通过 MCP
Agent 在运行过程中,根据 MCP 的描述,决定是否要触发相关记录。
4.2.1 记忆沉淀
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| { "name": "openviking_record_memory", "description": "用于向用户的长期记忆空间 (viking://user/{user_id}/memories/) 持久化沉淀高价值信息。仅在以下场景主动调用:1. 识别到用户的全局开发习惯、框架偏好或明确禁止的编码风格;2. 总结出经过验证的复杂 Bug 解决方案或架构避坑经验;3. 跨项目的通用工作流规则。禁止记录临时的对话闲聊、单次简单修改或未验证的推论。", "parameters": { "type": "object", "properties": { "category": { "type": "string", "enum": ["preferences", "experiences", "cases", "entities"], "description": "记忆的分类:preferences (用户长期偏好), experiences (通用排错/避坑经验), cases (经典可复用案例), entities (核心项目实体与术语)" }, "title": { "type": "string", "description": "记忆的简短标题,如 'Go 1.22+ 迭代器规范' 或 'MySQL 唯一索引并发死锁规避'" }, "content": { "type": "string", "description": "提取出的核心经验、规则或代码片段正文 (Markdown 格式)" } }, "required": ["category", "title", "content"] } }
|
4.2.2 资源沉淀
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| { "name": "openviking_write_resource", "description": "用于在 OpenViking 虚拟文件系统 (viking://resources/) 写入或更新持久化知识库。适用于用户明确指示保存设计文档、接口定义、技术选型方案或团队通用规章等具有长期重用价值的工程资产。", "parameters": { "type": "object", "properties": { "uri": { "type": "string", "description": "目标 VFS URI 路径,格式如 'viking://resources/architecture/payment_flow.md'" }, "content": { "type": "string", "description": "完整的内容 Payload" } }, "required": ["uri", "content"] } }
|
5. 记忆处理
5.1 冲突处理
对 Resource(知识库/代码): 保持客观中立,依赖确定性版本覆盖和 VFS 路径隔离,不做主观语义魔改。
对 Memory(记忆/偏好): 引入 Entity Matching -> 仲裁模型 (修正/合并/细化) -> 覆写与归档 的自动化流水线,
结合时序优先和人工可读可编辑,从根本上解决记忆互相打架的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| [ 新会话产生的新事实 / 新偏好 ] │ ▼ ┌──────────────────────────────────────────────────────────┐ │ 1. 语义相似度与实体对齐 (Entity & Semantic Matching) │ │ - 检索 memories/ 中是否存在同类实体或相近的主题规则 │ └──────────────────────────┬───────────────────────────────┘ │ 命中旧记忆: "语言偏好: Python 3.10" ▼ ┌──────────────────────────────────────────────────────────┐ │ 2. 认知一致性仲裁 (Cognitive Arbitration) │ │ - 调用仲裁 Prompt 判定关系类型: │ │ ├── [完全冲突 / 修正] ──> 触发直接覆盖与归档 (Overwrite) │ │ ├── [条件互补 / 细化] ──> 触发合并增补 (Merge / Append) │ │ └── [无关 / 新增分支] ──> 触发新建条目 (Create New) │ └──────────────────────────┬───────────────────────────────┘ │ 判定为"偏好修正" ▼ ┌──────────────────────────────────────────────────────────┐ │ 3. 原子更新与历史追溯 (Atomic Update & Invalidation) │ │ - 覆写 viking://user/1001/memories/preferences.md │ │ - 重新计算该 Memory 节点的 L0/L1 摘要及向量索引 │ │ - 将旧记录移入历史追踪版本库 (可审计/可回滚) │ └──────────────────────────────────────────────────────────┘
|
5.2 遗忘机制
通过目录隔离,在会话结束之后,把 session 目录下的内容抽取沉淀至长期记忆
短期工作记忆(Working Memory):
- 存储路径:viking://user/{id}/sessions/{session_id}/
- 生命周期:仅在当前 Agent 任务或对话生命周期内活跃
- 使用场景:记录单次任务的多步执行轨迹(Scratchpad)、临时变量、中间推理步骤
长期记忆(Long-term Memory & Knowledge):
- 存储路径
- resources/(知识)
- user/{id}/memories/(偏好与经验)
- 生命周期:跨会话永久持久化,供后续所有任务共享
- 使用场景:为整个后续提供记忆材料
6. 深挖细节
- 目录树并发写入与惊群效应(级联重算)
- 问题:如果短时间内多次变更,会触发 L1/L0 重复处理
- 解决:
- 递归检索的长尾等耗时
- 问题:可能会遇到多级”打分 -> 分支判断 -> 下探子目录 -> 再次打分”
- 解决:
- 多级数据独立存储一致性
- 问题:由于系统解耦了 meta、向量、对象存储三层,跨系统下分布式事务没法实现
- 解决:
- 软删除(数据还在,但是标记为无效) + 异步垃圾回收
- 一致性校验机制
- prompt 注入与记忆毒化
- 问题:session 场景可能有恶意 prompt 提权等;
- 解决:只能限制在 session 沙箱,而且需要做对抗性检查,保证加工数据的安全;
- 多租户场景下资源竞争
- 问题:如果没有物理隔离,怎么实现资源平衡?
- 解决:
- 基于账户的优先级队列
- 做读写分离,线上部分只做读取 + L2 数据写入,离线部分做 L0/L1 数据加工计算
- 面对长上下文的 LLM,记忆还有优势吗?
- 问题:现在很多模型上下文到了 1M
- 解决:
- 少量 token 直接全量读取,不用多级加载
- 合理布局拼接结果,最大可能实现 prompt cache
- 对数据做事实性提取,模型擅长检索,不擅长推理
- 主动挖掘数据之间隐含的关联关系,为用户提供更个性化、超预期的服务