使用 Vibe Coding 的这6 种后遗症,你有吗?

我已经很久没有沉浸式写代码了。

以前碰到一个复杂问题,我会花几个小时读调用链、画状态变化、跟踪异常路径。刚开始很慢,脑子里只有一些零散信息。随着上下文逐渐完整,代码会形成一张连续的结构图。再往后写,很多判断不需要反复查找,心流也就出现了。

现在的工作节奏完全变了。

我先给 Agent 描述需求,等它执行。等待期间又觉得空着可惜,于是打开第二个窗口,让另一个 Agent 补测试。看到还有时间,再开第三个任务处理重构。

十几分钟后,几个 Agent 陆续返回结果。我开始查看摘要、检查 diff、运行测试、补充要求、处理冲突。一个任务还没看完,另一个任务已经弹出完成通知。

一天下来,代码生成了很多,我却很少在同一个问题里连续停留半小时。

心流没了

Vibe Coding 最先改变的是注意力结构。

写代码原本是一种连续活动。理解需求、寻找入口、建立模型、设计实现、发现问题、修正判断,这些环节彼此相连。Agent 把它切成了很多轮对话:描述任务,等待结果,检查结果,再描述下一步。

每轮都很快,每轮都带来一点进度。

大脑很容易适应这种高频反馈。问题一旦需要长时间推演,我就会产生阻力。以前遇到难点,会继续读代码、查日志、进调试器。现在的第一反应经常是把问题发给 Agent,让它先分析一下。

思考开始变得外包化。

这不会让工程师立刻失去能力。更常见的变化是耐心下降。看十分钟调用链就想问 AI,调试几次没有结果就想换提示词,设计还没收敛就开始生成代码。

慢思考越来越难维持。

复杂工程问题偏偏依赖这种能力。并发状态、数据一致性、故障恢复和性能瓶颈,很少能靠几轮快速问答解决。它们需要人在同一套上下文里待得足够久,直到各种局部信息连成一体。

Agent 使用频率越高,我越忙,也越难进入这种状态。

Token 焦虑

额度快用完会焦虑,这很正常。额度没用完也会焦虑,就就有点奇怪了。

买了订阅,看到 token 还剩很多,会产生一种浪费感。离开工位之前,总想再布置一个任务。准备去开会,让 Agent 先跑一轮测试;准备吃饭,让它顺手整理模块;睡觉之前更容易上头,总觉得应该给 AI 加个通宵夜班。

真的是如群友所说:床前 token 光。

这种焦虑会慢慢改变任务优先级。原本没有必要立即处理的工作,因为 Agent 正好空闲,被提前塞进了队列。需求还没有想清楚,先做一个版本看看;某段代码虽然还能维护,先让 Agent 重构一下;测试已经够用,再补几十个用例似乎也没坏处。

Agent 忙起来了,人的待验收任务也堆起来了。

第二天早上打开电脑,几个任务全部显示完成。看起来像是白捡了一夜生产力。仔细检查才会发现,每个结果都需要重新加载上下文,都要判断实现边界,还要验证它有没有把局部问题扩展成新的抽象。

AI 上完夜班,我们开始加班验收。

更麻烦的是,等待结果本身也会占据注意力。人已经离开电脑,脑子里还惦记着任务有没有跑完、会不会失败、明天要看多少改动。休息时间变成了一段漫长的异步等待。

越用越累

刚开始用 Vibe Coding,我以为自己会轻松很多。实际体验是产出提高以后,疲惫感也跟着上升。

过去一天写两百行关键代码,我基本知道每一行为什么存在。现在几个 Agent 可以快速生成几千行改动。我的工作量没有消失,它从编写转移到了理解、判断和验收。

生成可以并行,理解通常只能串行。

一个 Agent 修改接口,一个 Agent 补充测试,另一个 Agent 调整调用方。它们各自都能完成任务,最后所有结果汇集到我这里。我需要判断接口语义有没有变化,测试是否沿用了错误假设,调用方有没有掩盖异常,几个改动能否同时成立。

机器的带宽增加了,人的带宽没有同步扩展。

当输出超过处理能力,审核质量会自然下降。最初还会逐行看 diff,后来只看摘要;最初会认真检查测试内容,后来看到绿色就继续;最初要求自己理解每个关键决策,后来开始依赖 Agent 提供的变更说明。

疲惫带来的危险,很少表现为明显的错误决定。它更像一种缓慢降低的验收标准。

每一次都只少看一点,每一次都觉得风险可控。几个月以后,代码库里已经出现大量没人完整理解的实现。

不想 review

我现在越来越不想看 AI 写的代码。

人工审核 AI 代码,有时比自己重写还累。自己写代码时,设计过程和实现过程是连续的。我知道哪些地方经过权衡,哪些地方只是临时处理,哪些假设需要后续验证。

面对 AI 生成的代码,这些上下文都要重新推导。

最让人疲惫的代码,往往还写得挺像样。命名规范,结构完整,注释齐全,测试也有。逐段看都有合理性,放回整个系统却经常显得多余。

一个边界条件被扩展成通用框架,一次局部修复引入新的中间层,三个表面相似的流程被强行抽象到一起。代码能运行,测试也能通过,但维护成本被悄悄推高了。

审核者需要花很大力气,才能解释为什么一份「正确」的代码不适合进入当前系统。

重复几次以后,人会开始逃避。既然测试过了,先合进去。出了问题,再让 Agent 修。下一次 Agent 又基于上一次生成的结构继续扩展,代码越来越多,理解越来越少。

最后会出现一种荒诞状态:人不愿意维护 AI 写的代码,于是继续让 AI 维护。

理解变浅

亲手写代码的过程,本身也是建立系统认知的过程。

为了实现一个功能,我需要找到入口,理解依赖,处理编译错误,观察测试失败,再确认数据如何穿过整个链路。实现完成以后,我对这部分系统已经形成了自己的判断。

Vibe Coding 跳过了其中大量过程。

Agent 告诉我改了哪些文件、采用了什么方案、测试结果如何。我可以很快获得一份完整说明,却没有经历那些失败、试探和修正。知道结果,与掌握系统之间,仍然隔着很长一段距离。

这种认知缺口在日常迭代中不容易暴露。Agent 还能继续修改,功能也能继续上线。等到线上故障、复杂重构或性能退化时,团队需要在压力下定位根因,欠下的理解成本才会集中出现。

每个人都参与过系统开发,问到关键链路却只能讲出局部。继续追问异常如何传播、数据如何恢复、容量边界在哪里,回答逐渐变成「让 Agent 分析一下」。

工具还在,工作可以继续。工程师对系统的控制感却在下降。

调度上瘾

多 Agent 会带来很强的生产感。

屏幕上同时跑着几个任务,状态不断变化,代码持续生成。即使我没有处理最困难的问题,也会觉得今天推进了很多工作。

这种感觉很容易上瘾。

我开始热衷于拆任务、写提示词、查看进度、追加要求。一天都在操作,一天都没有停下来。到了晚上,任务列表关闭了不少,却很难指出自己完成了哪段连续思考。

技术管理者更容易陷进去。我们的时间本来就被会议、消息和协作切碎,Agent 又提供了一种产出感很强的碎片化工作。它比回复消息更像研发,比真正做架构设计轻松,还能持续制造「事情正在推进」的反馈。

久而久之,启动任务替代了处理问题,完成数量替代了工程质量。

代码还在,人却远了

Vibe Coding 让我写得更快,也让我离代码更远。

这种距离很难通过提交数量看出来。功能持续上线,测试数量持续增加,仓库每天都很活跃。只有在关掉 Agent、独自面对系统时,才能感受到变化。

我还能不能连续读一小时代码?

能不能在没有摘要的情况下说清楚一次变更?

能不能独立判断某个抽象该不该存在?

线上出问题时,我脑子里有没有完整的执行链路?

这些问题比 token 使用量更让我焦虑。

我仍然每天使用 Vibe Coding,也很难再回到完全手写的状态。它确实提高了生产速度,只是这份速度附带了一组后遗症:心流消失、注意力碎片化、token 焦虑、审核疲劳、理解变浅,以及对调度和即时反馈的依赖。

以前写代码会累,累在实现。

现在也累,累在持续接收、持续判断、持续验收。机器一直在输出,我的大脑一直没有真正下班。

以上。

做 Agent 架构时,OpenViking 的几个可以学习的点

设计 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 用 lstreefind 浏览自己的上下文。

从架构角度来看,这个统一带来两个收益。第一,定位从概率性变成确定性。扁平向量库里想精确更新某个用户的编码习惯记忆,只能靠 metadata filter 打补丁;文件系统里就是一个路径寻址,viking://user/{user_id}/memories/preferences/coding_habits,增删改查全部确定。多租户隔离也顺带解决了——user/{user_id} 这层目录天然就是隔离边界,商业版文档里明确把多租户共享和隔离列为核心场景。

第二,Agent 与上下文之间的接口收敛成了一套文件操作原语。这一点对架构的影响比看起来大。我们之前自研记忆系统时设计过一套 memory.query(scope, filter, ...) 风格的 API,模型调用的出错率明显高于让它直接操作路径。文件系统是 LLM 预训练语料里高频出现的心智模型,lstree 的语义模型天然理解,不需要在 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 --upgradeopenviking-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 独立存在。

以上

RAG 的新思路:SAG 和 OpenViking

最近在看 RAG 的两个新思路,其实也不是说特别新,有点新瓶装旧酒的意思。

对于 RAG 的优化,一种线路是继续优化传统 RAG:切块更细一点,召回器多堆几层,重排再优化,最后把 prompt 拼得更精致。另一条线路是开始换问题定义:如果知识检索本身的建模方式就不对,后面那一长串补丁是不是从第一步就已经输了。

SAG 和 OpenViking 属于第二种。

这两个项目看起来也不在一个层面上。SAG 讨论的是检索架构,OpenViking 讨论的是 Agent 的上下文系统。但我看下来,它们都是在解决同一类问题:RAG 之所以越来越重,往往不是因为模型不够强,而是因为我们把「知识」和「上下文」这两个对象建模得太糙。

过去一年,团队在 RAG 上花的钱和精力,主要耗在三个地方:

  • 文档切块以后,语义边界被打碎;
  • 多跳关联靠 embedding 硬撞,召回经常断链;
  • 想补结构化能力,就往 GraphRAG 走,结果离线构图、实体归一、增量更新把系统拖住。

这里的问题是这条路线会把系统带向复杂化。

SAG

SAG 的核心论文《SAG: SQL-Retrieval Augmented Generation with Query-Time Dynamic Hyperedges》提出了一种非常精妙的架构。它不是传统 RAG 与 GraphRAG 的简单拼接,而是一套用自己的数据模型和执行路径替代二者的原创检索架构。

它的核心思想可以总结为八个字:轻量离线,动态建图。

1. 数据模型

传统 GraphRAG 把文本切碎,试图把所有知识都抽象成 (Subject, Predicate, Object) 的三元组。这种做法丢失了文本原本的上下文语义,导致最后召回出来的都是一些干瘪的关系链,LLM 很难根据这些碎片生成高质量的回答。

SAG 重新设计了数据模型:

  • Chunk  Event(事件):一个语义完整的文本块(Chunk)被映射为一个 Event。Event 承载该 Chunk 的完整上下文,它是最终输出和溯源的边界,不再被拆成彼此独立的三元组。
  • Chunk  Entities(实体):从该 Chunk 中抽取多个 Entities。这些实体只负责索引和扩展,不替代事件本身所承载的完整含义。
  • Event  Entities:建立事件与实体之间的关联,共同定义了一条潜在的超边(Latent Hyperedge)。
+-------------------------------------------------------------+
|                         Original Chunk                      |
+-------------------------------------------------------------+
                               |
                               v
+-------------------------------------------------------------+
|                         Event (完整语义)                     |
+-------------------------------------------------------------+
            /                  |                  \
           v                   v                   v
+------------------+   +------------------+   +------------------+
|     Entity A     |   |     Entity B     |   |     Entity C     |
+------------------+   +------------------+   +------------------+

这个设计让事件和实体各司其职。实体只用来做连接的「钩子」,而事件负责保留完整的语义。

2. 查询时动态超边

SAG 不预先构建、也不全局维护任何静态图谱。所有的关系推理,都是在检索发生的那一瞬间,通过关系型数据库的 SQL JOIN 动态计算出来的。

当一个用户查询(Query)进来时,在线检索流程如下:

  1. 种子定位:通过语义(向量)与词法(全文检索)信号,找到与查询最相关的「种子实体」和「种子事件」。
  2. SQL 动态扩展:利用关系型数据库的 SQL JOIN 查询,沿着这些种子实体,将共享相同实体的事件连接起来。
  3. 局部超边实例化:在查询时,仅针对当前查询所需的局部结构实例化「超边」,不进行任何全局图遍历。
  4. 证据还原:将筛选出的事件映射回原始 Chunk,去重后作为最强证据提供给 LLM 生成带引用的回答。

在这个过程中,我们不需要 Neo4j,不需要复杂的图算法,底层的存储与查询完全依赖标准的数据库基础设施(如 SQLite、PostgreSQL、LanceDB 等)。

因为超边是查询时动态计算的,所以当有新文档导入时,不需要重算或重构全局图谱。新 Chunk 只需要并行抽取自身的 Event、Entities 并写入数据库即可。这让系统天然支持了高并发的增量写入。

从跑分数据来看,在相同的 BGE-Large-EN-v1.5 Embedding 与 Qwen3.6-Flash LLM 配置下,SAG 在 HotpotQA、2WikiMultiHopQA 和 MuSiQue 的 9 项 Recall@1/2/5 指标中取得了 8 项最佳成绩。其平均 Recall@2/Recall@5 达到了 79.30%/88.18%,而 HippoRAG 2 仅为 68.14%/83.28%。

一些问题

SAG 不是银弹,还存在一些问题。

抽取质量依然依赖 LLM。Event 的切分和 Entity 的抽取用的还是大模型,模型抽错了,后面的动态连接就是在错误的实体上做 JOIN。SAG 降低了实体的语义负担,但没消除抽取本身的不确定性。这块的鲁棒性得拿自己的语料实测。

查询时的实体提取是另一个隐患。动态超边的起点是从 Query 里提出核心实体,如果用户的提问很口语、实体表达很模糊,种子定位偏了,后面整条链就歪了。这个环节的召回率我认为是整个系统最脆弱的地方,值得单独压测。

还有并发下的延迟分布。JOIN 在数据量大的时候,SQL 的执行计划、索引命中情况会直接影响尾延迟。其底层继承了数据库的并发能力,在海量数据情况下需要观察其延迟分布。

OpenViking

聊完 SAG,看下 OpenViking。它跟 SAG 不是同一个层面的东西,我把它俩放一篇文章里,是因为它们代表了同一个方向上两种不同深度的探索。

SAG 解决的是「怎么把知识检索得更准」。OpenViking 解决的是「Agent 的上下文该怎么组织」。前者是检索问题,后者是上下文工程问题。

火山引擎把它定位成一款面向 AI Agent 的上下文数据库,基于开源的 OpenViking 内核构建的全托管云服务。核心思想它自己概括成四句:虚拟文件系统、分层上下文、目录递归检索、可观测与自迭代。

万物皆文件

OpenViking 把 Memory、Resource、Skill 三样东西统一抽象成文件,全部映射到 viking:// 协议下的虚拟目录,每个条目有唯一的 URI。

这个抽象是 Agent 发展到现在的一种沉淀,这里最早是 Manus 在实践的逻辑。Agent 领域现在最乱的就是上下文管理。你有用户的长期记忆、有外部知识资源、有工具和技能定义,这三样东西各自用各自的存储、各自的检索方式,代码里到处是特判。OpenViking 把它们收敛成同一套文件语义之后,Agent 就能用 listfind 这种统一指令去操作所有上下文。

从模糊的语义匹配变成确定性的文件操作,这个转变对调试很有帮助。向量检索是个黑盒,你不知道为什么这次召回了这几条、漏了那几条。文件系统是白盒,路径、目录结构摆在那,Agent 走了哪条路一目了然。

分层加载

OpenViking 在上下文写入的时候,就自动把它处理成三层。

L0 是一句话摘要,用来快速判断。L1 是概述,包含核心信息和使用场景,供 Agent 在规划阶段决策。L2 是完整原始数据,Agent 确有必要时才深入读取。

这个设计针对的是一个很现实的成本问题。把海量上下文一次性塞进提示词,token 烧钱、容易爆窗口、还引入噪声。分层之后,Agent 在规划阶段只看 L0 和 L1 就能做大部分决策,只有真正要用某份资料的时候才去拉 L2。

我算过一笔账。一个复杂的多步 Agent 任务,如果每一步都把候选上下文的全文塞进去,token 消耗是指数级的。分层供给相当于给 Agent 一个「先看目录再翻正文」的能力,规划阶段的 token 成本能压下去一大截。具体压多少取决于你的任务形态,但这个方向省的钱是实打实的。

目录递归检索

OpenViking 的检索不是单次向量召回。流程是这样:先通过意图分析生成多个检索条件,用向量检索快速定位初始切片所在的高分目录,然后在这个目录下做二次检索,把高分结果更新到候选集合;如果目录下还有子目录,就逐层递归重复二次检索;最后拿到最相关的上下文返回。

「先锁定高分目录,再精细探索内容」,这套策略把向量检索的语义定位能力和文件系统的层次结构结合起来了。单纯的向量检索找到的是孤立的片段,它不理解片段所在的完整语境。目录递归能顺着文件的组织结构,把一个片段周围的语境一起带出来。

这个思路和 SAG 的动态超边其实有相通之处。两者都意识到孤立的语义片段不够用,都想在检索时把「关联」这层信息补回来。SAG 用的是共享实体的 SQL JOIN,OpenViking 用的是目录层级的递归遍历。一个走关系代数,一个走树形结构。解决的底层痛点是同一个。

可观测与自迭代

OpenViking 的检索过程,每次的目录浏览、文件定位轨迹都被完整留存,能看清问题根源、指导检索逻辑优化。

对做过 RAG 调优的人来说,这个能力的分量不用多解释。传统向量检索出了问题,你几乎无从下手,只能瞎调 embedding、瞎调 chunk size。有了完整的检索轨迹,你能精确复盘 Agent 每一次信息获取走了哪条路径,哪一步偏了。

自迭代那部分是通过 session.commit() 主动触发的。会话结束时,系统异步分析任务执行结果和用户反馈,自动更新到 User 和 Agent 的 /memory 目录下。它既更新用户偏好,也从任务执行经验里提炼操作技巧和工具使用经验。

这个闭环我持谨慎乐观。自动提炼记忆听着很美,但提炼的质量、更新的边界、错误记忆的污染问题,都是需要长期跑才能暴露的。我不会一上来就把它当成生产依赖,会先在低风险场景里观察它更新出来的记忆到底靠不靠谱。

SAG 和 OpenViking

写到这,我把 SAG 和 OpenViking 放到一起,讲讲我看到的相同点。

传统 RAG 的世界观是扁平的。所有知识被切成等长的 Chunk,拍平进一个向量空间,检索就是在这个空间里找最近邻。这套世界观简单、好扩展,但它主动丢弃了知识之间的结构信息。Chunk 和 Chunk 之间是什么关系,谁包含谁,谁引用谁,谁是谁的上下文,全都被拍平的过程碾掉了。

SAG 和 OpenViking 从两个不同的方向,试图把这层被碾掉的结构信息找回来。

SAG 找回的是「实体关联」这层结构。它承认知识点之间存在通过共享实体建立的隐式关联,并且用查询时的 SQL JOIN 把这层关联即时重建出来。它的贡献在于证明了这层结构不需要离线物化成一张昂贵的全局图,用关系型数据库现成的关联能力就能在查询时高效算出来。

OpenViking 找回的是「层次组织」这层结构。它承认知识天然有目录、有层级、有从属关系,并且用虚拟文件系统把这层组织显式地保留下来,检索的时候顺着这个层级递归下去。它的贡献在于把 Agent 的上下文从一堆散落的切片,重新组织成了一个可导航、可追溯的结构。

两者都在做同一件事:扁平化的向量检索丢失了太多结构,而这些结构恰恰是复杂查询和长程任务真正需要的东西。它们的分歧只在于用什么载体去承载这层结构。SAG 选了关系表和 SQL,OpenViking 选了文件系统和目录树。

怎么选

落到实际决策,可以分两个场景。

如果核心诉求是知识库的多跳检索精度,语料相对静态、增量频繁、又要给用户看得见的原文引用,建议评估 SAG。它的动态超边在多跳上的数据摆在那,增量友好和溯源能力恰好解决了之前方案的问题。部署门槛低,本地就能验,评估成本几乎为零。

如果做的是 Agent 产品,痛点在长程任务的上下文管理、记忆沉淀、多 Agent 协作,建议去评估 OpenViking。它解决的是比检索更上一层的问题,文件系统抽象和分层加载对控制 Agent 的 token 成本、提升可调试性比较有用。

这两个东西不冲突。理论上一个成熟的 Agent 系统,底层完全可以用 SAG 这类引擎做精准的知识检索,上层用 OpenViking 这类框架做上下文的组织和调度。一个管「检索得准」,一个管「组织得清」,各司其职。

检索这条路走到今天,值得关注的方向已经从「怎么把向量算得更快」转到了「怎么把结构找回来」。SAG 和 OpenViking 是这个转向上两个具体的答案,一个在检索层,一个在上下文层。

以上。