设计 Agent 架构时,有一个模块的边界经常画不清晰:上下文。规划、工具调用、执行循环这些组件的职责都好切分,唯独「Agent 该知道什么」这件事,散落在 prompt 模板、RAG 管道、记忆插件和会话历史四个地方,各管一段,互不通气。
比较常见的状态是知识走一条 RAG 管道,用户记忆走一个独立的 memory 服务,工具使用经验干脆没有沉淀机制,靠 system prompt 里手写的几条注意事项撑着。跑长周期任务时问题集中爆发:第三十轮时 Agent 忘了第五轮的约束;召回了一段错误文档,事后想归因,向量库只给一个相似度 0.83,别的什么都没有。
这两个 case 背后是同一个架构缺陷:上下文没有被当作一个独立子系统来设计,它只是若干条数据管道的松散集合。
最近把火山引擎开源的 OpenViking 看了一遍,它把自己定位成「面向 AI 智能体的上下文数据库」,GitHub 上 27.2k star。这个定位本身就是一个架构主张:上下文应该是 Agent 架构里一个有统一接口、有存储模型、有检索语义、可观测的独立组件,地位类比业务系统里的数据库。
沿着这个主张往下拆,它有几个设计决策对做 Agent 架构的人有一些参考价值。
统一存储模型
Agent 架构里第一个要回答的问题:记忆、知识、技能这三类上下文,存储模型是分开还是统一。
分开是多数团队的现状,也是我们踩过的坑——三套 schema、三套检索接口、三套更新逻辑,Agent 侧要维护三种访问心智。OpenViking 的选择是统一:全部抽象成文件,挂在 viking:// 协议下的虚拟文件系统里,每个条目一个唯一 URI。它给出的目录结构:
viking://
├── resources/ # 资源:项目文档、代码库、网页等
│ └── 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/
Agent 用 ls、tree、find 浏览自己的上下文。
从架构角度来看,这个统一带来两个收益。第一,定位从概率性变成确定性。扁平向量库里想精确更新某个用户的编码习惯记忆,只能靠 metadata filter 打补丁;文件系统里就是一个路径寻址,viking://user/{user_id}/memories/preferences/coding_habits,增删改查全部确定。多租户隔离也顺带解决了——user/{user_id} 这层目录天然就是隔离边界,商业版文档里明确把多租户共享和隔离列为核心场景。
第二,Agent 与上下文之间的接口收敛成了一套文件操作原语。这一点对架构的影响比看起来大。我们之前自研记忆系统时设计过一套 memory.query(scope, filter, ...) 风格的 API,模型调用的出错率明显高于让它直接操作路径。文件系统是 LLM 预训练语料里高频出现的心智模型,ls 和 tree 的语义模型天然理解,不需要在 prompt 里教。接口设计顺着模型先验走,省下的是持续的 prompt 工程成本。
代价在写入侧的分类决策。内容归置到哪个路径,做错了后续检索会系统性偏航,扁平向量库至少没有「放错文件夹」这种失败模式。OpenViking 靠写入时的自动语义处理来做归置,这个环节的质量上限决定了整棵文件树的可用性,我认为是它工程上最脆弱的一环。
预算分层供给
第二个架构问题:上下文以什么粒度供给给模型。
传统 RAG 的答案是 chunk 全量——检索 top-k 塞进 prompt,k 靠拍脑袋。这在架构上等于把上下文预算的管理责任丢给了一个魔法数字。OpenViking 的方案是写入时预计算三层表示:
- L0(摘要):约 100 tokens,一句话总结,快速判断相关性
- L1(概览):约 2k tokens,核心信息和使用场景,供规划阶段决策
- L2(详情):完整原始数据,确有必要时才读
每个目录也带自己的 .abstract 和 .overview,Agent 读任何完整文件之前,先花 100 个 token 判断这个方向值不值得深入。
放到 Agent 的执行循环里看,这三层恰好对应了三个阶段的信息需求:候选筛选阶段用 L0 扫一遍,规划阶段对少数目标加载 L1,执行阶段只对必要条目读 L2。上下文供给从一次性的赌博变成了跟随 Agent 决策流程的渐进加载,粒度和阶段对齐了。
数据上,OpenViking 0.3.22 在 LoCoMo 长对话记忆评测里,三种 Agent 集成的准确率到 80–83%,原生记忆只有 24–57%;输入 token 减少 34.3%–91.0%,查询时延降低 58.45%–66.10%。token 降幅区间这么宽,说明收益高度依赖任务形态:判断型任务能省九成,需要全量细节的任务省不了多少。评测脚本在仓库 ./benchmark 目录,可自行复现。
架构上的 trade-off 转移到了写入路径。L0/L1 由模型生成,每次数据摄入都有一笔推理开销,且是异步的——README 明确提示 add-resource 不加 --wait 时语义处理需要等待。写入吞吐敏感或数据高频变更的场景,这条路径会成为瓶颈。更隐蔽的风险是摘要写歪:L0 错了,后续所有基于它的相关性判断连带出错,等于在检索链路最上游埋单点。官方提供 ov reindex <uri> --mode semantic_and_vectors 重新生成语义产物再刷新向量,说明他们自己也预期摘要需要返工。
即便不引入 OpenViking,「写入时预计算多粒度表示、按 Agent 决策阶段供给」这个模式可以直接抄进自建架构。
检索即导航
检索组件在 Agent 架构里通常被实现成一个无状态函数:query 进,top-k 出。OpenViking 把它改成了一个有过程的导航。
先通过意图分析生成多个检索条件;向量检索定位初始切片所在的高分目录;在该目录下二次检索,高分结果更新进候选集;有子目录就逐层递归;最终返回最相关的上下文,连同周边语境一起。
一句话概括:先锁定高分目录,再向下精细探索。
这解决的是扁平 top-k 在 Agent 场景下的一个结构性缺陷——碎片没有语境。命中一个 chunk,Agent 不知道它前后是什么、属于哪份文档的哪个章节,拿到的是信息孤岛。导航式检索的返回结果自带位置和邻居:这段内容出自 API 文档的鉴权章节,同目录下还有 endpoints 说明。对代码库问答这类强依赖结构的任务,这个差异是决定性的。
代价:多轮向量查询加上可能的多次判断,单次检索的绝对延迟一定高于一把梭的 ANN。前面提到的时延降低 58%–66%,我的理解是端到端口径——省下的 token 让生成阶段变快,摊平了检索阶段的开销。架构选型时要按流量形态判断:Agent 任务型场景,单次任务价值高、容忍秒级检索,划算;高 QPS 低延迟的在线检索,这套递归策略不合适。
全链路留痕
Agent 架构的可观测性讨论,通常止步于工具调用日志。OpenViking 把留痕做进了检索内部:每次查询都保留完整的目录浏览轨迹,结果不对时能看到它出自哪条路径。
做过 RAG 生产运维的人知道 bad case 归因有多难。用户投诉答案错了,排查下来只能看到「这几个 chunk 相似度最高所以被召回」,正确内容为什么没进 top-k,向量空间不会解释。最后退化成调 embedding、调 chunk 大小、调 k 值的炼丹循环。
轨迹留存把归因变成可逐步 debug 的过程:检索在哪个目录拐错了弯、哪一层的 L0 摘要误导了判断,路径上每一步可查。修复动作随之有了着力点——重写某个目录的 abstract,或者调整文件归置,都对应到具体操作。配套的 OpenViking Helper 桌面端(Beta,支持 macOS 和 Windows x64)能解析 Claude Code、Codex、Trae 的会话,展示召回、Prompt 注入、MCP 调用、捕获和提交事件,Agent 与上下文系统之间的全部交互摆在明面上。
这一条我建议所有做 Agent 基础设施的团队照抄,无论用不用 OpenViking:把「检索决策可回放」写进架构的非功能需求。存储和埋点的成本,第一次生产事故排查时就能收回来。
经验回写闭环
多数 Agent 架构是开环的:任务执行完,除了对话历史什么都不留,下次遇到同类任务从零开始。OpenViking 在架构里补了一条回写路径:会话通过 session.commit() 显式提交后,系统异步提取两类内容写入长期记忆——用户偏好,和 Agent 经验,落到对应的 /memory 目录下。
用户偏好各家都在做。Agent 经验这条更值得看:从任务执行结果里提取操作技巧、工具使用经验,供后续同类任务复用。tau2-bench 的数据:经验记忆让任务成功率在 Retail 提升 6.87 个百分点,Airline 提升 11.87 个百分点,对比同一 LLM 无记忆基线。模型没动,纯靠架构里加一条经验沉淀回路,拿到两位数以内的成功率增量。
对比另一条提升路线——攒数据做 SFT 或 RL 微调,周期以周计,成本以万计。经验记忆改的是上下文而非权重,迭代周期是每次会话。两条路线不互斥,但在架构演进的排序上,外置经验回路的边际成本低得多,应该排在微调前面。
两处要留神。一是提取质量:异步抽取本身是 LLM 调用,抽错等于往长期记忆注入脏数据,且脏记忆会在后续任务里持续生效,危害大于一次性的错误回答。二是显式 commit 这个设计——记忆更新由开发者主动触发而非全自动,「哪些会话值得沉淀」的裁量权留在应用层。我们内部一度想做全自动沉淀,现在倾向于保留这个开关,至少在提取质量有验证机制之前。
接入成本
把这套东西放进现有 Agent 架构的成本,不高。
Python 3.10 以上,pip install openviking --upgrade,openviking-server init 走交互式向导——支持火山引擎、OpenAI、Codex OAuth、Kimi、GLM 和本地 Ollama,选 Ollama 还能按硬件拉合适的模型。openviking-server doctor 启动前体检配置、Python 版本、提供商连通性和磁盘空间。有官方 Docker 镜像和 Helm 部署。
集成面很宽:Claude Code、Codex、OpenClaw、Hermes、Cursor、Trae、OpenCode、pi、MCP 客户端、LangChain / LangGraph 都有官方接入,集成做的事是把召回注入 Agent 上下文并自动提交会话记忆。如果你的架构本来就走 MCP 或 LangGraph,接入成本主要在配置层。
许可证要过法务。主项目 AGPLv3,crates/ov_cli 和 examples 是 Apache 2.0。AGPLv3 自用没问题,基于它对外提供网络服务会触发传染性条款的开源义务。商业版 OpenViking Service 承诺与开源版共享同一套代码内核,差异在托管运维、基于 VikingDB 的规模(宣称万亿级向量、百亿数据毫秒级检索)、SLA 和企业级安全合规,有至多 50 个文件的免费试用和迁移工具。开源版默认本地存储加单机向量引擎,数据规模上去后的可靠性要自己扛,架构容量规划时要计入。
背后有论文支撑:VikingMem(arXiv:2605.29640),已被 VLDB 2026 接收,开源版实现了论文描述的部分核心能力。团队在按数据库系统的标准做存储和检索设计,这在 Agent 记忆类项目里少见。
需要注意的点
三点。
其一,整个体系的地基是写入时的自动语义处理——摘要、概览、目录归置全靠模型生成,这些产物没有质量下界。LoCoMo 和 tau2-bench 覆盖的场景有限,换到术语密集的企业知识库,L0 摘要的准确率会不会崩,要拿自己的真实数据验证,别信 benchmark 直接上生产。
其二,导航式检索的延迟特性划定了适用边界,架构选型时按流量形态判断,前面说过了。
其三,项目还早,README 自己承认「要做的事还很多」。1813 次 commit、92 个 open issue、320 个 PR,迭代活跃,反面是 API 稳定性存疑,核心链路重度依赖它要做好跟版本的准备。
回到 Agent 架构本身。「上下文作为独立子系统」「统一文件存储模型」「按决策阶段分层供给」「检索决策可回放」「经验回写闭环」,这五个设计每一个都能脱离 OpenViking 独立存在。
以上