AI Agent(人工智能代理)要长期工作,不能只依赖一次对话里的上下文窗口。它需要记住用户偏好,能读取项目资料,能复用过去的任务经验,还要知道自己有哪些技能和指令。
传统做法通常是把文档切块后塞进向量数据库,再通过 RAG(Retrieval-Augmented Generation,检索增强生成)把相关片段召回给模型。这种方案适合文档问答,但用在长期运行的 Agent 上会遇到几个问题:
- 上下文太分散:用户记忆、项目文档、工具说明、技能模板可能分别存在代码、配置文件、向量库和数据库里。
- 检索缺少结构:向量库通常按 chunk 平铺存储,能找相似片段,但很难表达“这个片段属于哪个项目、哪个目录、哪个任务案例”。
- 长任务成本高:任务越长,历史消息和中间资料越多,直接塞进上下文会消耗大量 Token(模型处理文本的基本计量单位)。
- 链路不透明:模型拿到了哪些资料、资料从哪里来、为什么召回,很难定位。
- 记忆不会沉淀:很多系统只保存对话记录,不会把“用户偏好”“解决方案”“可复用模式”提取成可迭代的长期记忆。
OpenViking 的核心思路是:不要把 Agent 的上下文只当成一堆向量片段,而是把它组织成一个可寻址、可浏览、可检索的虚拟文件系统。
OpenViking 是什么
OpenViking 是一个面向 AI Agent 的上下文数据库。它把资源、用户记忆、Agent 记忆、会话信息统一映射到 viking:// 协议下,通过类似文件系统的方式管理上下文。
它不是简单替代向量数据库,而是在向量检索之上增加了目录、层级、生命周期、记忆类型和可观察性。
整体结构可以理解成这样:
flowchart TD
A[AI Agent] --> B[OpenViking 上下文数据库]
B --> C[viking://resources]
B --> D[viking://user]
B --> E[viking://agent]
B --> F[viking://session]
C --> C1[项目文档]
C --> C2[代码仓库]
C --> C3[外部 URL]
D --> D1[用户画像]
D --> D2[用户偏好]
D --> D3[关注实体]
D --> D4[重要事件]
E --> E1[技能库]
E --> E2[任务案例]
E --> E3[可复用模式]
E --> E4[系统指令]
F --> F1[当前会话消息]
F --> F2[临时上下文]
这种设计让 Agent 可以同时使用两类能力:
- 确定性定位:像操作文件一样
ls、tree、read、grep。 - 语义检索:用
find、search找到语义相关的资源和记忆。
确定性路径解决“资料在哪里”的问题,语义检索解决“资料和问题是否相关”的问题。两者结合后,Agent 不再只能面对一个黑盒向量库。
文件系统范式:把上下文变成可管理的目录树
OpenViking 用 viking:// URI(Uniform Resource Identifier,统一资源标识符)标识上下文资源,基本形式是:
viking://{scope}/{path}
常见的 scope 有四类:
| scope | 含义 | 生命周期 | 示例 |
|---|---|---|---|
resources | 外部资源,如项目文档、代码仓库、URL | 长期有效 | viking://resources/my_project/readme |
user | 用户相关数据,如偏好、身份、关注对象 | 长期有效 | viking://user/memories/preferences |
agent | Agent 自身经验,如技能、案例、模式、指令 | 长期有效 | viking://agent/skills/code_review |
session | 会话级数据 | 随会话生命周期变化 | viking://session/current/messages |
一个典型的目录结构如下:
viking://
├── resources/
│ └── my_project/
│ ├── docs/
│ ├── src/
│ └── README.md
├── user/
│ └── memories/
│ ├── profile/
│ ├── preferences/
│ ├── entities/
│ └── events/
└── agent/
├── skills/
├── memories/
│ ├── cases/
│ └── patterns/
└── instructions/
这个模型和普通向量库的区别很明显。
| 对比点 | 平铺向量库 | OpenViking |
|---|---|---|
| 数据组织 | 文本 chunk 列表 | viking:// 目录树 |
| 定位方式 | 主要靠相似度 | 路径定位 + 语义检索 |
| 上下文关系 | 弱,依赖元数据 | 目录天然表达归属关系 |
| 可观察性 | 需要额外日志 | URI、目录、读取链路可追踪 |
| 适合对象 | 文档片段 | 文档、代码、记忆、技能、指令、会话 |
文件系统范式的价值不只是“看起来整齐”。当 Agent 需要解决一个复杂任务时,它可以先定位项目目录,再进入相关子目录,再读取必要文件,而不是一次性从全库召回一批相似片段。
L0/L1/L2:按信息粒度加载上下文
长任务中最贵的地方往往不是检索,而是把大量文本塞进模型上下文。OpenViking 用三级上下文结构解决这个问题。
| 层级 | 名称 | 典型大小 | 用途 |
|---|---|---|---|
| L0 | 摘要 | 约 100 tokens | 快速筛选候选资源 |
| L1 | 概览 | 约 2k tokens | 判断是否需要深入读取 |
| L2 | 详情 | 完整内容 | 读取原始资料或完整上下文 |
可以把它理解成文档阅读里的三个动作:
- 看标题和摘要,判断是否相关。
- 看目录和概览,判断哪部分有用。
- 只在必要时打开全文。
流程如下:
flowchart LR
Q[用户问题] --> A[检索候选资源]
A --> B[加载 L0 摘要]
B --> C{是否相关}
C -- 否 --> X[丢弃候选]
C -- 是 --> D[加载 L1 概览]
D --> E{是否需要细节}
E -- 否 --> R[返回概览级上下文]
E -- 是 --> F[加载 L2 完整内容]
F --> R
这种分层加载适合 Agent 的原因在于:大多数资料只需要参与“筛选”和“决策”,只有少数资料需要完整进入模型上下文。OpenViking 在对比 LanceDB 的测试中,通过这种方式显著降低了输入 Token 消耗。
目录递归检索:不是只找片段,而是沿目录探索
传统 RAG 常见做法是:用户问题进来,向量检索找 top-k 片段,把片段拼进 prompt。这个流程简单,但缺少全局视角。如果一个问题需要结合项目结构、历史案例和用户偏好,单次 top-k 很容易漏掉关键上下文。
OpenViking 的检索更像人查资料:先判断意图,再找大致位置,进入相关目录,继续细查,必要时递归深入子目录。
flowchart TD
A[用户请求] --> B[意图分析]
B --> C[生成多维查询]
C --> D[初始语义检索]
D --> E[定位高相关目录]
E --> F[读取目录 L0/L1]
F --> G{是否需要深入}
G -- 是 --> H[进入子目录二次检索]
H --> F
G -- 否 --> I[聚合候选上下文]
I --> J[返回带 URI 的结果]
目录递归检索包含几个关键点:
| 步骤 | 作用 |
|---|---|
| 意图分析 | 把用户请求拆成多个检索方向,例如项目背景、用户偏好、历史案例 |
| 初始定位 | 先找到相关资源目录,而不是直接锁定零散片段 |
| 目录内检索 | 在已知相关范围内做更精确的搜索 |
| 递归深入 | 目录仍然过大时继续进入子目录 |
| 结果聚合 | 合并最相关的上下文,并保留 URI 方便追踪 |
这种方式能减少“语义相似但上下文错位”的问题。例如用户问“这个仓库的鉴权逻辑怎么改”,系统不应该只返回几个包含“auth”的片段,还应该知道这些片段属于哪个服务、哪个模块、是否和当前任务历史有关。
自动会话管理:把对话变成长期记忆
Agent 的长期记忆不能只是聊天记录。聊天记录太长、太杂,直接保存没有太大价值。更合理的方式是:会话结束或提交时,从消息中提取结构化记忆,再写入对应命名空间。
OpenViking 会从会话中提取六类记忆:
| 类型 | 归属 | 说明 | 是否适合合并 |
|---|---|---|---|
profile | user | 用户身份属性,例如角色、背景 | 是 |
preferences | user | 用户偏好,例如输出格式、技术栈偏好 | 是 |
entities | user | 用户关注的人、项目、系统、业务对象 | 是 |
events | user | 重要事件、决策、时间点 | 否 |
cases | agent | 问题与解决方案,类似任务案例库 | 否 |
patterns | agent | 可复用的处理模式、经验规则 | 是 |
记忆写入流程如下:
sequenceDiagram
participant U as 用户/Agent
participant S as Session
participant L as LLM 大语言模型
participant V as 向量去重
participant DB as OpenViking 存储
U->>S: 产生会话消息
S->>L: 提交消息并请求提取记忆
L-->>S: 返回候选记忆
S->>V: 查找相似已有记忆
V-->>S: 返回重复或相近项
S->>L: 判断新增、合并或丢弃
L-->>S: 返回写入决策
S->>DB: 写入 user/agent 对应目录
这个流程解决两个问题:
- 记忆不会无限堆积:可合并的偏好、画像、模式会被更新,而不是重复写入。
- 任务经验能沉淀:Agent 完成任务后,可以把“问题 + 解决方案”保存为 case,后续遇到类似任务时复用。
常用能力和命令
OpenViking 提供的能力可以分成四组:资源管理、检索、会话管理和系统观测。
| 能力 | 命令示例 | 作用 |
|---|---|---|
| 导入资源 | ov add-resource | 导入本地文件、代码仓库或 URL |
| 导出导入 | ov export / ov import | 使用 .ovpack 迁移上下文包 |
| 浏览目录 | ov ls / ov tree / ov read | 像文件系统一样查看资源 |
| 语义检索 | ov find | 根据语义查找相关内容 |
| 上下文检索 | ov search | 结合上下文做更完整的检索 |
| 模式匹配 | ov grep / ov glob | 按文本或路径模式搜索 |
| 会话管理 | ov session new/list/get/delete | 管理会话生命周期 |
| 记忆提交 | ov session add-message / ov session commit | 写入消息并触发记忆提取 |
| 健康检查 | ov system status / ov system health | 查看服务状态 |
| 组件观测 | ov observer queue/vikingdb/vlm | 查看队列、数据库、模型组件状态 |
对于 Agent 系统来说,read 和 find 的组合很重要:
find负责发现可能相关的上下文。read负责按 URI 精确读取内容。tree负责让 Agent 理解当前资源结构。session commit负责把临时对话沉淀成长期记忆。
和 OpenClaw 集成:给 Agent 框架补长期记忆
OpenClaw 是一个 AI Agent 框架,OpenViking 可以作为它的长期记忆后端。集成后,Agent 对话过程中可以自动保存记忆,也可以在新会话中自动召回相关记忆。
安装方式:
cd /path/to/OpenViking
npx ./examples/openclaw-memory-plugin/setup-helper
openclaw gateway
安装助手会完成环境检查、配置创建和插件部署。
集成后的核心能力如下:
| 功能 | 说明 |
|---|---|
autoCapture | 自动从对话中提取记忆 |
autoRecall | 自动把相关记忆注入当前上下文 |
| 记忆去重 | 根据摘要和 URI 判断是否重复 |
| 智能排序 | 结合偏好、时间、词法重叠等信号排序 |
自动召回流程可以这样理解:
flowchart TD
A[OpenClaw 收到用户请求] --> B[OpenViking 检索相关记忆]
B --> C[按偏好、时间、词法重叠排序]
C --> D[筛选可注入上下文]
D --> E[OpenClaw 调用模型生成响应]
E --> F[会话结束或提交]
F --> G[OpenViking 提取并保存新记忆]
基于 LoCoMo10 长对话数据集的 1,540 个样例,OpenClaw 接入不同记忆后端后的结果如下:
| 方案 | 任务完成率 | 输入 Token |
|---|---|---|
| OpenClaw 原生方案 | 35.65% | 24,611,530 |
| OpenClaw + LanceDB | 44.55% | 51,574,530 |
| OpenClaw + OpenViking | 52.08% | 4,264,396 |
按表中数据计算:
| 对比对象 | 完成率变化 | 输入 Token 变化 |
|---|---|---|
| 相比 OpenClaw 原生方案 | 约 +46.1% | 约 -82.7% |
| 相比 OpenClaw + LanceDB | 约 +16.9% | 约 -91.7% |
这组数据说明,Agent 长期记忆不只是“多存一点历史”。如果上下文组织方式不合理,接入向量库后可能带来更多 Token 消耗;如果能按层级和目录检索,模型拿到的上下文更少,也更贴近任务需要。
配置示例
OpenViking 需要配置存储目录、Embedding(向量表示模型)和模型服务。一个基础配置如下:
{
"storage": {
"workspace": "/path/to/workspace"
},
"embedding": {
"dense": {
"provider": "volcengine",
"api_key": "<key>",
"model": "doubao-embedding-vision-250615",
"dimension": 1024
}
},
"vlm": {
"provider": "volcengine",
"api_key": "<key>",
"model": "doubao-seed-1-8-251228"
}
}
如果用于 OpenClaw 插件,也可以使用类似配置:
{
"vlm": {
"backend": "volcengine",
"api_key": "<your-key>",
"model": "doubao-seed-1-8-251228",
"api_base": "https://ark.cn-beijing.volces.com/api/v3"
},
"embedding": {
"dense": {
"backend": "volcengine",
"api_key": "<your-key>",
"model": "doubao-embedding-vision-250615",
"dimension": 1024
}
}
}
配置中的几个点需要注意:
| 配置项 | 作用 |
|---|---|
workspace | OpenViking 本地工作目录 |
embedding.dense.model | 用于语义检索的向量模型 |
dimension | 向量维度,必须和模型输出一致 |
vlm.model | 用于摘要、记忆提取、意图分析等任务的模型 |
api_key | 模型服务访问密钥,生产环境不要写进代码仓库 |
快速上手
安装 Python 包:
pip install openviking
安装 CLI(Command Line Interface,命令行工具):
curl -fsSL https://raw.githubusercontent.com/volcengine/OpenViking/main/crates/ov_cli/install.sh | bash
创建配置文件:
mkdir -p ~/.openviking
vim ~/.openviking/ov.conf
写入配置后启动服务:
openviking-server
导入一个 GitHub 仓库作为资源:
ov add-resource https://github.com/volcengine/OpenViking --wait
语义检索:
ov find "what is openviking"
查看资源目录树:
ov tree viking://resources/OpenViking -L 2
读取具体资源:
ov read viking://resources/OpenViking/README.md
一个典型使用链路如下:
flowchart LR
A[安装 OpenViking] --> B[配置模型和存储]
B --> C[启动 openviking-server]
C --> D[导入文档/代码/URL]
D --> E[使用 find/search 检索]
E --> F[Agent 读取相关 URI]
F --> G[提交会话并提取记忆]
和 PageIndex 怎么选
PageIndex 更偏向专业文档检索系统,它强调不依赖向量数据库,通过文档章节树和 LLM 推理做检索。OpenViking 更偏向 Agent 上下文管理,除了文档检索,还要管理用户记忆、Agent 技能和任务经验。
| 维度 | OpenViking | PageIndex |
|---|---|---|
| 定位 | 通用上下文数据库 | 专业文档检索系统 |
| 核心设计 | 文件系统 + 分层存储 + 会话记忆 | 文档章节树 + LLM 推理检索 |
| 存储模型 | viking:// 虚拟文件系统 | 章节层级树 |
| 检索方式 | 向量检索 + 目录递归 + 意图分析 | 主要依赖 LLM 推理 |
| 记忆系统 | 支持六类记忆提取与去重 | 不侧重长期记忆 |
| 基础设施 | 需要配置向量检索和模型服务 | 不强调向量数据库依赖 |
| Token 优化 | L0/L1/L2 分层加载 | 主要依赖文档结构和推理策略 |
| 更适合 | 长期运行的 Agent、多类型上下文 | 财报、法律等专业文档问答 |
选择时可以按任务类型判断:
| 场景 | 更适合的方案 |
|---|---|
| 要做长期个人助手,持续记住偏好和历史任务 | OpenViking |
| 要管理文档、代码、技能、指令、用户记忆 | OpenViking |
| 要让 Agent 自动沉淀案例和模式 | OpenViking |
| 主要需求是专业文档问答,文档目录很清晰 | PageIndex |
| 不想维护向量数据库,只做文档推理检索 | PageIndex |
| 对财报、法律等固定文档集做高精度问答 | PageIndex |
适合场景和不适合场景
OpenViking 适合上下文类型复杂、会话周期长、需要记忆沉淀的系统。
| 场景 | OpenViking 能解决的问题 |
|---|---|
| 个人 AI 助手 | 长期维护用户偏好、习惯、关注对象 |
| 开发团队协作 | 把项目文档、代码仓库、任务案例统一管理 |
| 企业知识管理 | 通过命名空间和 URI 管理多租户上下文 |
| 自主 Agent 系统 | 自动积累任务经验,让后续任务能复用历史案例 |
| 复杂 RAG 系统 | 用目录结构减少平铺 chunk 带来的召回噪声 |
不适合的情况也要提前判断:
| 场景 | 原因 |
|---|---|
| 只做简单客服问答 | 普通 RAG 或关键词检索可能已经够用 |
| 数据量很小 | 文件系统范式和记忆提取会增加工程复杂度 |
| 不希望引入模型做记忆提取 | OpenViking 的自动记忆依赖 LLM |
| 完全不能使用向量检索基础设施 | OpenViking 的语义检索需要 Embedding 支撑 |
| 只处理结构清晰的专业文档问答 | PageIndex 这类文档检索系统可能更直接 |
实施时容易踩的坑
1. 不要把所有内容都塞进一个目录
OpenViking 的优势来自目录结构。如果所有文档、记忆、技能都堆在同一层,目录递归检索的效果会下降。更合理的方式是按项目、业务域、用户、Agent 能力拆分目录。
viking://resources/
├── payment-service/
├── user-center/
└── data-platform/
viking://agent/skills/
├── code-review/
├── bug-fix/
└── requirement-analysis/
2. L0/L1 摘要质量会影响召回
分层加载能节省 Token,但前提是摘要和概览足够准确。如果 L0 摘要遗漏关键信息,相关资源可能在早期就被过滤掉。对关键文档、核心代码目录,可以适当检查生成的摘要质量。
3. 记忆合并要有边界
用户偏好和可复用模式适合合并,事件和任务案例不一定适合合并。比如“用户喜欢 Markdown 表格输出”可以更新为一条偏好;但“某次线上故障处理过程”最好保留为独立案例,否则会丢失时间线和决策背景。
4. 多租户要从 URI 设计开始
企业环境中,不同用户、团队、项目之间的数据隔离不能只依赖后期权限补丁。URI 命名空间、目录层级、访问控制要一起设计。
viking://resources/team-a/project-x/
viking://resources/team-b/project-y/
viking://user/user-123/memories/preferences/
viking://agent/support-bot/memories/cases/
5. Benchmark 不能直接替代业务测试
长对话数据集上的结果能说明分层上下文和目录检索的潜力,但实际系统还会受数据结构、模型能力、任务类型、召回策略影响。上线前至少要准备一组自己的测试问题,比较完成率、Token 成本、延迟和错误案例。
关键结论
OpenViking 的核心价值是把 Agent 上下文从“平铺片段集合”升级成“可寻址的上下文文件系统”。资源、用户记忆、Agent 记忆和会话数据都有明确位置,Agent 可以通过路径读取,也可以通过语义检索发现相关内容。
它最重要的机制有三类:
viking://虚拟文件系统:让上下文可组织、可定位、可追踪。- L0/L1/L2 分层加载:减少不必要的全文读取,降低 Token 消耗。
- 会话记忆提取:把临时对话沉淀为用户画像、偏好、事件、任务案例和可复用模式。
如果系统只是做简单问答,普通 RAG 可能更轻;如果目标是构建长期运行、能积累经验、能管理多类型上下文的 Agent,OpenViking 提供的是一套更完整的上下文管理基础设施。