做 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 是这个转向上两个具体的答案,一个在检索层,一个在上下文层。

以上。

Session First 和 Agent First,本身并没有高低之分

最近在思考一个问题:系统究竟把谁当成第一类公民。

现在我们看到很多的 AI 产品,,本质上还是「把聊天框做得更厚一点」。用户打开一个窗口,对着通识大模型说需求,模型在一个长 session 里记上下文、调几个工具、写几段内容、偶尔执行点操作。这个模式我称它为「Session First」。

「Session First」的模式跑得起来,落地也快。过去一段时间,桌面端的很多产品,包括一些 codex cc 一类的形态,都是这么长出来的。先有聊天,再把能力缝进去。先有 session,再把工具挂上去。整个产品又快又省,因为它继承的是大模型最自然的交互方式:对话。

但如果把时间线拉长,我觉得 Session First 像是一个过渡层。它把大模型带进软件,却没有真正重写软件。

另一个逻辑是 「Agent First」。

这里说的 Agent First,不是把 prompt 包一层 workflow 就算 agent。这里说的是一种更彻底的软件设计取向:系统从一开始就假设调用者不只是人,也包括 agent;系统的能力边界、接口形态、文档组织、安全机制、运行时观测,都优先围绕 agent 来设计。聊天只是入口之一,不再是核心结构。

过去我们是在和「通识大模型」对话,未来更多时候,我们是在和「带有领域知识、工具能力、任务规划能力的专用 agent」协作。再往前走,单一 agent 很可能都不够,基于 MaaS 的 agent teams 会逐步成为复杂任务的常态。Sakana AI 这类工作给了行业一个很有代表性的信号:多智能体协作,不只是研究兴趣,它在复杂探索任务上确实可能优于单体。

这种两种不同的范式,其实也没有高级和低级之分。二者背后的系统假设不同,工程代价不同,性能瓶颈不同,能解决的问题类型也不同。

Session First 和 Agent First 的不同

Session First 和 Agent First,表面上都可能长得像「用户输入一句话,系统输出一个结果」。很多人可能会觉得两者只是包装差异。其实差异蛮大的。

Session First 的中心对象是「会话」。系统假设一切能力都围绕一个持续增长的上下文展开。用户说一句,模型接一句;模型靠历史消息理解意图,靠当前 prompt 决定行为。工具调用存在,但工具通常是会话的附属物。它们由模型在 session 内临时选择、临时编排、临时解释。

所以在 Session First 里,能力组织方式通常是这样的:

  1. 先有一个大而全的聊天入口;
  2. 再有一组工具函数;
  3. 再在 system prompt 或 tool spec 里告诉模型什么时候调用它们;
  4. 复杂任务靠更长的上下文、更复杂的提示词、更精细的 few-shot 去兜。

这个模式最大的好处,是产品和研发都能快速起跑。我们不需要先把系统抽象成可组合能力,也不需要先考虑 agent 的长期运行、恢复、权限边界、状态持久化。只要模型够强、上下文够长、工具挂得上去,很多事情都能先做出来。

Agent First 的中心对象则是「行动体」。系统假设执行任务的主体是 agent,它会自己读取规范、规划步骤、调用工具、检查结果、重试修正。人在这个系统里依然重要,但人不再是唯一的控制中心。更准确地说,系统从「为人类交互而生」转向「为可委托执行而生」。

这个变化会连锁改写很多设计决策。

传统软件里,人是第一类公民。系统主要通过 UI 提供能力,文档写给人看,按钮给人点,异常信息也默认人会读。Agent First 里,agent 变成第一类公民。系统的关键界面不再是页面和按钮,而是 API、工具协议、语义化描述、状态机、权限模型、回调事件、执行日志。

传统模式是:

  • 人读文档;
  • 人理解业务逻辑;
  • 人决定点哪个按钮;
  • 人承担串联流程的责任。

Agent 模式是:

  • Agent 读取规范;
  • Agent 形成计划;
  • Agent 调用工具;
  • Agent 分析返回值;
  • Agent 根据反馈继续执行或者回滚。

这不是交互方式的小修小补,这是控制权和复杂性承载位置的转移。

Session First 把复杂性藏在会话里。
Agent First 把复杂性显式地放进系统结构里。

我更倾向后者。因为在规模化阶段会 Session First 开始需要大量的修补并且还不合脚。

Session First 的红利

Session First 也不是说不行了,落后了,它只是有自己的舒适区或边界。

它为什么会成为大多数团队的第一个选择?因为它天然适合模型的原生能力。

大模型最成熟的接口就是聊天接口。你给它上下文,它续写;你给它 instruction,它服从;你给它工具定义,它在概率空间里学着调用。这是当前已经成熟了的,并且对于大家的谁知来说没有门槛的。。产品经理能理解,前端能接,后端能包,用户也能马上用。

从落地顺序看,Session First 有三个明显优势。

交付速度快

最早一批 AI 应用能起量,基本都吃到了这个红利。做一个对话框,叠一层历史上下文,挂几类工具,外加 prompt 工程和少量业务逻辑,一个可卖的产品就出来了。

如果团队处在探索期,需求还没稳定,任务边界也不清晰,Session First 的性价比很高。因为我们可以把大量未定型的业务规则临时编码进 prompt,而不是过早地固化到接口和状态机里。说白了,它适合试错。

交互弹性高

很多需求在早期根本说不清。用户自己也不知道该点哪个按钮,只知道「我想把这堆信息处理一下」。这时聊天入口比传统 UI 更自然。Session First 天然适合承接模糊需求,尤其适合开放式任务、咨询类任务、内容类任务。

对通识模型友好

Session First 依赖的是模型在语言理解和上下文整合上的强项。很多场景下,不需要精细建模世界状态,只需要让模型在一个较长的 session 里维持语义连贯,效果就已经够用了。

所以如果一个产品主要解决的是下面这些问题,Session First 我认为完全合理:

  • 单轮或短链路任务;
  • 任务结果主要是文本、建议、草稿、分析;
  • 工具调用数量少,失败代价低;
  • 用户愿意在回路中持续确认;
  • 业务状态变化弱,对幂等性和恢复能力要求不高。

比如代码解释、文档问答、简历润色、轻量报表分析、知识库检索助手,这些都很适合。

问题出在很多团队做着做着,把它用到了不该用的地方。

Session 的代价

Session First 最大的问题,不是效果问题,而是系统复杂性的位置不对。

我们可以把 session 理解成一个不断膨胀的黑盒。任务描述、历史记录、工具调用痕迹、失败重试信息、用户偏好、临时约束,全都塞进去。模型在黑盒里靠注意力机制和 token 预算自行判断什么重要、什么该忽略、什么该继续执行。

短任务还行。链路一长,问题就开始多了。

状态污染

会话越长,状态越容易脏。一个典型问题是历史上下文对当前决策的隐性干扰。模型没有传统意义上的干净状态管理,它只有一段被不断续写的上下文。早期的一句错误假设、一次失败调用、一个过时约束,都可能在后续步骤中持续影响行为。

工程上我们会看到一些很烦的现象:

  • 明明用户已经修改目标,模型还沿着旧计划跑;
  • 明明工具返回了失败,模型把失败结果当成成功上下文继续推理;
  • 明明当前任务和上个任务无关,模型还把旧 session 里的偏好带进来。

这些都不是 prompt 多写两句能解决的。因为根因在于 session 本身不是一个严谨的状态容器。

上下文成本失控

Session First 很吃上下文。任务越复杂,历史越长,系统 prompt 越复杂,tool spec 越多,token 消耗越惊人。很多团队前期盯着模型单价,后期才发现账单真正膨胀的是「无效上下文」。

更糟的是,这部分成本并不总能换来线性收益。超过某个长度以后,模型对上下文的利用率明显下降。你花了更多 token,只换来更模糊的关注分布、更高的遗漏概率。

有一些系统,一次复杂任务真正有价值的工作 token 可能只占总 token 的 20% 到 30%,剩下的都在重复喂历史、喂规则、喂工具描述、喂先前失败记录。这样的系统,成本结构很难看。

工具选择不稳定

在 Session First 里,工具往往是通过提示词暴露给模型。模型根据自然语言描述决定什么时候调哪个工具。这种方式灵活,但稳定性一般。尤其当工具数量上来以后,工具间语义重叠、参数边界相近、返回格式不一致,模型的选择质量会迅速下降。

一个常见误区,是以为给工具写更长更详细的 description 就能解决。实际经验正相反:description 越长,竞争工具越多,模型越容易在语义相邻区域摇摆。最终你会发现,问题不是模型笨,而是整个工具层根本没有被设计成适合被模型消费。

可恢复性差

Session 是连续流,不擅长离散恢复。任务执行到一半,模型挂了、超时了、工具限流了、用户关闭页面了,系统怎么从中间恢复?很多 Session First 产品的恢复策略要么是重放整个对话,要么让模型读历史「自己想起来」。

这个策略在低风险任务里还能接受,在执行型任务里就很危险。因为它没有明确的检查点,没有确定的已完成步骤,没有结构化的执行日志,恢复质量完全依赖模型在长上下文里的自我理解。

可观测性弱

你问一个 Session First 系统:「为什么它刚才这么做?」答案通常很难给。因为真正的决策过程埋在 session 和模型隐状态里。你最多能看到 prompt、工具调用记录和输出,但很难形成稳定的、可归因的行为分析。

这会直接影响调试、评估、审计和优化。团队很容易陷入一种很熟悉的工作流:改 prompt、跑样例、感觉好一点、上线、再出新问题、继续改 prompt。系统像在「训一头很聪明但脾气不稳定的动物」,而不是在维护一个可控软件。

转向 Agent

Agent First 出现,本质上是在回答一个问题:当任务不再是聊天,而是委托执行时,系统该怎么设计?

用一名话来概括:Session First 优先组织对话,Agent First 优先组织能力、状态和约束。

这两者的差别,在简单场景里不明显;一旦任务变成多步骤、长周期、高风险、强工具依赖,这个差别会迅速放大。

Agent First 的核心变化有三层。

第一层,agent 拥有独立的任务身份。
它不再只是当前聊天窗口里的一个响应函数,而是一个可启动、可暂停、可恢复、可审计的执行单元。它有自己的目标、记忆、工具权限、运行环境和生命周期。

第二层,系统能力被显式结构化。
什么能力能调用,输入输出是什么,失败怎么表示,重试边界在哪,副作用怎么隔离,全部要写清楚。因为 agent 不是靠「猜」来用系统,它得靠规范来用系统。

第三层,任务执行被流程化和可观测化。
agent 的计划、步骤、结果检查、异常处理、人工介入点,都需要成为系统的一部分,而不是 prompt 里的一段希望。

这就是为什么我说 Agent First 更像软件设计理念,而不只是交互升级。它要求开发者从一开始就考虑 agent 的接入体验。注意,这里的「接入体验」不是 SDK 文档写得漂不漂亮,而是系统有没有把 agent 当成真正的使用者来对待。

对人友好的系统,重点是 UI。
对 agent 友好的系统,重点是 API、协议、文档、沙箱、日志。

这个顺序一换,整套架构都会变。

第一类公民

传统软件的第一类公民是人。因为系统操作链条默认由人承担:读页面、理解状态、做选择、点按钮、确认风险、处理异常。

Agent First 的变化在于,这条链路开始迁移给 agent。系统如果还保留「很多关键信息只藏在页面里、很多操作只能靠人脑理解、很多异常只有人看得懂」的设计,那 agent 就只能在外面绕路,最后产品体验会非常拧巴。

所以所谓「agent 是第一类公民」,落到工程上至少意味着四件事。

能力必须接口化

页面点击不是能力,API 才是。
表格展示不是能力,结构化查询和变更才是。
人工读懂的描述不算完成,机器可消费的 schema 才算完成。

很多团队表面上说在做 agent,实际上只是让模型去模拟用户点页面,或者让 Playwright 去跑浏览器自动化。这能用,但我通常把它看成过渡手段,不会把它当成长期基建。因为 UI 自动化的脆弱性太高,成本也太高。一旦页面变了、字段换了、弹窗多了、权限策略改了,整个链路就坏了。

如果一项业务能力值得被 agent 使用,那它应该先被抽成稳定接口。

语义必须外显

我们靠经验猜按钮含义,agent 不行。我们得把操作语义、字段含义、约束条件、异常语义都写出来。很多传统系统文档的问题,不是文档少,而是文档默认阅读者是熟悉业务的人。里面有大量省略、上下文跳跃、术语别名、口头约定。

人能脑补。agent 不会脑补,它会误解。

机器友好的文档,不是把原文档丢给 RAG 就结束了。它要求内容可索引、可切片、可定位、可引用、可验证。最好还能区分「定义」「约束」「样例」「反例」「危险操作」「返回码语义」。

权限必须细粒度

给人开的权限,往往是按角色开的。给 agent 开权限,粒度要更细。因为 agent 的调用频率高、组合能力强、自动化程度高,任何一个权限放大,都可能把小问题变成系统性事故。

我见过一些团队初期为了快,直接给 agent 一个「管理员 token」,想着先把链路跑通。跑通确实跑通了,后面风控和审计基本没法收场。Agent First 里,权限模型必须从 day 1 就设计进去。至少要做到工具级、资源级、动作级的边界清晰。

结果必须可审计

如果 agent 能执行动作,那所有关键动作都要留痕,谁发起、为什么发起、使用了哪些上下文、调用了哪些工具、拿到了哪些结果、做了什么决策、是否有人确认,都得能追出来。

这不是为了满足审计部门,而是为了我们自己能把系统维护下去。没有可审计性,复杂 agent 系统很快会变成「偶尔非常惊艳,偶尔完全失控」的黑箱。

四层结构

如果我们把 Agent First 的工程原则压缩成一个递进结构,它可以拆成四层:能力层、理解层、连接层、信任层。

API 优先

最底下是能力层,也就是 API 优先。它解决的是「Agent 能做什么」。

很多 AI 团队容易犯一个错误:先做 prompt,再做工具,再补 API。顺序反了。只要你准备认真做 agent,API 就应该先于 prompt 存在。

因为 prompt 负责引导决策,API 才负责承载能力。没有稳定能力面,agent 的执行质量永远靠运气。

我看一个系统适不适合 Agent First,第一眼就看它的 API 长什么样。重点不在 REST 还是 GraphQL,也不在用不用 MCP,而在这几个问题:

  • 接口语义是否单一清晰;
  • 参数是否结构化且有约束;
  • 返回值是否可判定成功失败;
  • 幂等性是否明确;
  • 长任务是否支持异步和回调;
  • 副作用操作是否支持 dry-run 或预检查;
  • 错误码是否可用于 agent 自恢复。

举个很实际的坑。很多内部系统的 API 是给前端页面写的,不是给 agent 写的。于是你会看到:

  • 一个接口返回几十个业务无关字段;
  • 失败时只返回「操作失败,请联系管理员」;
  • 同一个字段在不同接口里名字还不一样;
  • 创建和更新共用一个入口,副作用混杂;
  • 数据查询支持模糊匹配,但没有稳定过滤条件。

这种 API 给前端开发凑合能用,给 agent 基本就是灾难。因为 agent 消费接口时最怕三件事:语义不稳定、返回不可判定、失败不可恢复。

API 优先不是一句口号,它意味着你要为了 agent 重写一部分服务边界。代价不小,但省下的是后面无数轮 prompt 补丁。

机器文档

有了能力层,还不够。Agent 知道系统「能做什么」,不代表它知道「怎么正确地做」。

这就是理解层,也就是机器友好文档。

很多团队对文档的理解还停留在「给模型塞进知识库」。坦白说,这一步最多算资料接入,不算文档工程。机器友好文档要求内容本身就是为 agent 理解和执行设计的。

我们写文档喜欢写背景、写故事、写注意事项穿插在长段落里。机器文档要反过来,尽量消除叙事性,强化检索和判定性。什么场景能用哪个接口,前置条件是什么,参数组合有什么限制,成功条件是什么,失败后应该重试还是终止,全部要能被定位出来。

我比较推崇一种写法:把文档拆成五类最小单元。

  1. 定义单元:术语、对象、字段、状态含义。
  2. 操作单元:动作描述、输入输出、前置条件、后置条件。
  3. 约束单元:权限要求、配额、时序、互斥关系。
  4. 异常单元:错误码、成因、恢复建议、是否可重试。
  5. 样例单元:正确示例、错误示例、边界示例。

这样写出来的文档,对人读可能不友好,但对 agent 非常友好。因为 agent 需要的不是阅读体验,而是最短路径上的高密度语义。

还有一个容易被忽略的点:文档版本化。
如果系统能力在变,而 agent 依赖旧文档决策,事故几乎是必然的。机器文档必须带版本、带生效范围、带弃用说明。更进一步,文档变更最好能够被 agent 订阅或者被平台主动推送。否则你会得到一堆「以前能跑今天突然不行」的鬼问题。

协议层

再往上一层是连接层,也就是标准化协议。我们都知道 MCP,它当前重要性确实在上升。

Agent First 一旦进入平台化阶段,连接成本会成为瓶颈。每接一个系统都重新对工具做 schema 包装、鉴权对接、错误语义映射、流式交互适配,团队很快就会被集成工作拖死。标准协议的价值就在这里:让 agent 对外部能力做到尽可能低摩擦的即插即用。

协议不是为了优雅,是为了降低耦合和重复劳动。它至少解决三个问题:

  • 能力发现:agent 如何知道外部提供了哪些工具和资源;
  • 调用协商:参数 schema、返回 schema、流式能力、状态反馈如何统一;
  • 安全边界:认证、授权、调用隔离、资源限制如何标准化表达。

MCP 这类协议的意义,不只是统一 tool calling 的表面格式,更重要的是把「能力元数据」变成平台可理解的对象。一旦元数据标准化,很多平台能力才能长出来:自动装配、权限编排、调用治理、能力市场、兼容性检查、离线评测。

协议统一不会自动带来效果统一。现实里最常见的问题是:大家都说自己支持标准,结果 schema 质量参差不齐,语义粒度不一致,错误处理风格也不同。最后 agent 虽然能连上,依旧很难稳定用好。

所以协议层只是接入下限,不是体验上限。系统方如果指望「支持 MCP 了,agent 就能用了」,十有八九会失望。

信任成本

最上面一层是信任层:安全、沙箱、可观测性。它解决的是「Agent 如何被安全地使用」。

这层往往是被低估的。因为很多团队在前期更关心效果演示,安全和观测总想放后面补。等 agent 真开始执行动作,补起来就很痛苦。

Agent 系统的风险和传统自动化脚本不完全一样。脚本通常路径固定、输入有限、行为可枚举。Agent 的输入是开放的,计划是动态的,工具组合是可变的,自修正带来恢复能力,也带来行为不可预测性。这种系统如果没有信任层,部署规模一上来迟早出事。

信任层可以分为三块。

安全边界

包括权限控制、数据隔离、密钥管理、配额限制、危险操作确认机制。所有高风险动作都要能分级:只读、可写、可执行、不可逆。不同级别的动作,对应不同的确认和审计策略。

还有一件事必须单独说:prompt injection。
只要 agent 会读取外部内容、再基于内容调用工具,prompt injection 就不是附加风险,而是基本风险。你不能假设模型会自己免疫。系统层必须有输入隔离、指令优先级控制、工具调用白名单、敏感动作二次确认、结果验证。

沙箱执行

如果 agent 能运行代码、操作文件、访问网络,就必须有沙箱。别指望靠「模型会守规矩」来兜底。资源限制、网络出口策略、文件系统隔离、进程生命周期管理,这些都是必须项。

很多桌面端产品今天还在用一个比较重的本地 session 容器去承接 agent 行为,这在早期合理,因为本地环境天然带着用户上下文和工具可得性。但一旦平台化,执行环境一定要可控、可回收、可复制。否则你会发现 bug 根本没法稳定复现。

可观测性

这一块经常被做得太浅。普通日志不够。你需要的是面向 agent 的运行时观测:任务级 trace、步骤级事件、工具调用链、上下文快照、计划变更、重试原因、人工接管点、最终结果评估。

有了这些数据,很多事情才有可能做:行为分析、失败归因、离线回放、A/B 对比、策略优化、合规审计。

我甚至会说,没有可观测性,Agent First 根本不成立。因为你没法持续优化一个你看不见的系统。

单体与团队

再往前一步,Agent First 还会带来一个自然演进:从单一 agent 走向 agent teams。

这个趋势不难理解。单体 agent 的优势是简单、上下文统一、决策路径短。缺点也明显:任务一复杂,规划、执行、验证、知识检索、异常恢复全压在一个主体上,容易出现上下文拥堵和角色冲突。模型一边要想战略,一边要写细节,一边还要检查自己,稳定性会下降。

多 agent 协作的思路,是把不同职责拆开。比如规划 agent 负责分解任务,执行 agent 负责调用工具,验证 agent 负责检查输出,审计 agent 负责看风险和合规。你提到 Sakana AI,我觉得它给行业的启发就在这里:复杂问题的效果上限,未必来自更大的单体,而可能来自更合理的协作结构。

但别高估 agent teams 的短期收益。它的工程成本很高。

第一,通信成本会增加。
agent 之间传递的信息如果不够压缩,token 成本会迅速膨胀。很多团队做多 agent,最后账单翻倍,效果提升却不明显,问题就出在这里。

第二,错误归因更难。
单体 agent 出错,你还知道看一条链。多 agent 出错,很可能是上游规划有偏差、中游执行误解了任务、下游验证规则又太松。没有细致的 trace,很难定位。

第三,协作协议本身就是复杂度。
谁能给谁发任务,谁对谁有覆盖权,冲突怎么解决,结果以谁为准,失败是否回滚,人工在什么点介入,这些全得定规则。规则一多,系统会变得很重。

它是复杂任务的方向,但不是所有产品都该急着上。很多团队连单体 agent 的能力边界、观测体系、权限模型都没建好,就直接跳多 agent,最后只会把问题放大。

个人的判断

如果今天让我给团队定路线,我不会在所有场景里一刀切推 Agent First,也不会继续把 Session First 当主架构。

我的判断是这样的:

凡是以「理解、生成、陪伴、咨询」为主,任务链条短,用户始终在线,副作用低的场景,Session First 依然是最有效率的方案。别把简单问题搞复杂。一个高质量 session 产品,照样能有非常强的竞争力。

凡是以「委托执行、跨系统操作、长周期任务、可恢复流程、强审计要求」为主的场景,应该尽早转向 Agent First。拖得越久,后面迁移成本越高。因为你的 prompt、工具、日志、权限、数据结构都会按 Session First 的惯性越长越歪,最后很难矫正。

从行业演进看,我认为我们会经历三个阶段:

第一阶段,通识模型 + 聊天入口主导。
第二阶段,聊天入口还在,但底层逐步 agent 化,能力和状态开始结构化。
第三阶段,很多系统默认面向 agent 开放,我们反而通过 agent 间接使用软件。

今天大多数团队还处在第一阶段和第二阶段之间。很多产品表面上已经在说 agent,骨子里还是 session 产品。这个阶段没什么丢人的,行业本来就处在过渡期。问题在于,团队自己得知道自己在哪,不要把一个 prompt-heavy 的聊天系统误以为已经完成了架构升级。

小结

Session First 帮行业把 AI 快速带进了产品。它的重要性不用否认。没有这一阶段,大量需求不会被激活,很多团队也不会积累起对模型能力边界的真实理解。

但它的问题也越来越明显:状态管理松散、成本结构失真、工具使用脆弱、恢复和审计能力薄弱。任务越复杂,缺点越放大。

Agent First 把软件重新组织了一遍:把会话里的隐含复杂性,搬回系统里显式管理;把面向人的操作界面,扩展成面向 agent 的能力界面;把「模型偶尔能做成」变成「系统可稳定交付」。

如果要走这条路,我们就需要重写 API,补文档债,需要重做权限和日志,就会发现以前很多偷过的懒都要补回来。可如果我们的目标不是做一个会聊天的功能,而是做一个能被委托工作的系统,这些账早晚都要还。

所以我现在看一个 AI 产品会更关心它底下埋的是 session,还是 agent。前者决定它今天看起来多聪明,后者决定它一年后还能不能继续长。

以上。