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。前者决定它今天看起来多聪明,后者决定它一年后还能不能继续长。

以上。

AI 时代,让自己慢下来

锡箔大佬在群里调侃,当前 AI 时代,只要你学得慢,你就不用学了。

是的,AI 发展太快了,回望去年的这个时候,我们写代码的方式还不一样,问问题的方式还不一样。

我不是焦虑效率的问题,也不是那种怀旧式的「古法编程才有灵魂」。我想的是:当生成成本持续下降,一个工程师最稀缺的能力,正在从「产出内容」快速转移到「做判断」。判断接口该不该拆,技术债该不该还,需求方嘴里的「必须」到底有多必须,模型给出的十种方案里哪一种能进生产,哪一种看上去漂亮、上线就炸。

这些事情,AI 没替我们做。相反,它把问题放大了。

因为现在最大的问题不再是「不会做」,而是「太容易做」。不会做的时候,人天然会慢一点,会查资料,会多问一句依赖边界,会想清楚为什么。太容易做的时候,团队最常见的路径就是:先生成,后理解;先上线,后治理;先把东西拼起来,再假设以后有时间收拾。

然而,「以后」通常没有以后。

越发觉着:AI 时代我们应该给自己保留一块慢思考的区域。这个「慢」不是拖延,不是低效,也不是故作深沉。它是一种刻意建立的认知阻尼:在系统已经足够快的时候,给判断过程增加必要的摩擦,避免人被工具的流速裹走。

那应该在哪里慢呢?

第一类,涉及不可逆成本的决策。架构选型、数据模型、权限边界、组织职责划分、供应商绑定、长期协议、核心链路改造,这些事情一旦定错,后面修复成本不是线性增加,而是指数级外溢。这里多花的两天,常常能省掉半年。

第二类,涉及复杂因果的问题。线上事故、质量下降、组织失灵、协作冲突、项目延期,这些问题都很讨厌,因为表象清楚,因果混乱。你以为是人不行,实际是流程激励错了;你以为是系统不稳,实际是变更策略太激进;你以为是模型效果差,实际是评测集污染了。这里如果追求快,通常只会更快地走向错误归因。

第三类,涉及个人能力沉淀的问题。写作、复盘、独处、长时间运动,我都把它们看成工程能力的一部分。它们看上去不产出代码,也不直接提升 QPS,但它们在训练更底层的东西:抽象能力、因果判断、注意力稳定性、抗噪能力。

「慢」也不是对抗效率,它是在给不同问题分配不同的时钟频率。流水线可以高频,人脑不能一直高频。CPU 长时间拉满会降频,人也一样。

如果有人问如何让自己慢下来,我觉得可以试试「写作,跑步,独处」

如果让我只保留一种慢思考训练方式,我大概率会选写作。

写作有几个好处。第一,成本低。你不需要设备,不需要场地,也不需要别人配合。第二,反馈直接。你只要写到第三段,就会发现自己到底有没有想清楚。第三,它能留下痕迹。很多模糊的感受,过几个月再回头看,你能看到自己当时的盲区和惯性。

作为技术人可以写些什么?个人觉得可以写如下的三类:

一类是方案备忘录。不是给别人看的那种完整文档,而是给自己看的判断草稿。问题是什么,已知事实有哪些,未知变量有哪些,我现在倾向哪个方案,为什么,最大的风险是什么,什么证据会让我改变主意。字不用多,关键是强迫自己把判断摊开。

一类是事故后记。不是标准复盘模板,而是写自己当时的认知过程。告警出现时,我第一反应是什么;我为什么排除了某条线索;我在哪个时间点开始被带偏;哪些历史经验帮了我,哪些历史经验害了我。这种东西写多了,慢慢会形成个人的故障判断档案。

还有一类,是长期主题写作。比如我们持续观察 AI 对研发组织的影响,或者持续观察某种架构范式在公司里的落地摩擦。这个过程很像做一个长期实验。每写一次,你都在更新自己的认知模型。它的回报不是立刻可见,但一年以后,你和大多数只看热闹的人会拉开明显差距。

写作最大的价值,是它逼你把借来的观点变成自己的结构。很多人平时听播客、看文章、刷帖子,输入很多,但脑子里一直是别人搭好的脚手架。只有自己写,才知道哪些梁是空的。

现在的信息环境非常密集。微信、钉钉、飞书、邮件、群消息、监控告警、PR 评论、AI 对话框,人的注意力被切成很多片。更麻烦的是,AI 还在不断提供一种幻觉:只要你卡住了,马上可以问,马上有回应,马上有一个差不多能用的答案。

久了之后,人会失去和一个难题长时间待在一起的能力。

而很多真正重要的问题,都不适合马上回答。一个组织为什么在扩张后决策质量下降,一个平台为什么越做越重,一个团队为什么开始迷恋短平快,一个技术负责人为什么明明很忙却越来越没有关键产出。这些问题都需要没有输入干扰的时间。你要让问题在脑子里发酵,要允许一些不舒服的空白存在。

AI 时代,人越来越容易只活在符号系统里:文档、消息、代码、表格、指标、提示词。跑步这种事的价值,在于让你暂时脱离符号洪流,回到一个更低带宽、但更连续的状态。这个状态对思考质量很重要。

当然,不一定非要跑步。长距离步行、游泳、骑行,甚至一个人安静地做家务,都可能进入类似状态。关键不在运动形式,在于持续、低干扰、有节律。

上面这些动作最终都是为了让自己有更好的判断力。

那如何构建判断力?

经常有人说「多见世面就有判断力」。这么说是有点空的,判断力当然和经验有关,但经验要看是怎样的经验。一个人做了十年项目,也可能只是把一年的经验重复了十次。

所以判断力要长出来,我觉得至少需要四样东西。

第一,能区分事实、解释和决策。浅一点,就像我和娃经常说的,这是一个观点还是一个事实。

第二,多想几步。

第三,能在不完整信息下做下注,决策。

第四,能复盘自己的错判。

就个人来说,一直在坚持的也就是写作了:

写作。不是为了发什么,也不是为了做内容号,也不是为了经营人设,就是把脑子里的判断落到纸面上。很多混乱的感觉,落到纸面上就清晰了。同时也是为了让有一个固定的和 AI 独处的时间。

我对「ai 时代,让自己慢下来」的理解,大概就是这么个意思:该快的地方拼命快,该慢的地方死守住。别把自己的大脑训练成一个只会接提示、吐结果的中转器。工具越来越强,人更不能放弃那部分缓慢、笨重、但决定上限的能力。

很多年后回头看,一个工程师、一个技术负责人,判断其能力强弱,大概率都不在他一小时能生成多少内容,而在他面对复杂局面时,能不能稳住,能不能看深一层,能不能在一堆看似正确的答案里,挑出那个真正应该做的决定。

这个能力,快不出来。

后记:

其实这篇文章也是在早上慢慢骑车的时候,忽然蹦出来的一个想法,周六还在想这周写点什么呢。

慢一点,也好。

以上。