<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/scripts/pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:h="http://www.w3.org/TR/html4/"><channel><title>派大猩 · Agent 工程笔记</title><description>派大猩 · 产品工程师 &amp; 开发者，坐标成都 · 电子科技大学：主要在做 Agent 落地 —— 把 Demo 变成真实业务里能用的系统；也在盯长时记忆、多 Agent 调度这些前沿问题，并涉猎 Transformer / GNN 一侧的模型训练。</description><link>https://your_domain</link><item><title>拆一个能上生产的 Agent 运行时：依赖方向、循环与压缩</title><link>https://your_domain/blog/20261008-agent-runtime-source-reading</link><guid isPermaLink="true">https://your_domain/blog/20261008-agent-runtime-source-reading</guid><description>一个上得了生产的 Agent 运行时把代码切成调模型、跑循环、做业务几层。值得抄的不是它暴露了多少 API，而是循环靠什么停、压缩切在哪、对话存成什么形状这三处取舍。</description><pubDate>Thu, 08 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;给上下文定预算那篇算的是怎么让一条链路的花销算得清楚。预算定完还剩一个必须回答的问题：花到窗口边上那一刻，是把旧对话删掉，还是把它改写掉。删掉能腾出空间，改写要多花一次调用，保住的是任务能不能接着做下去。&lt;/p&gt;
&lt;p&gt;这一篇拆一个能上生产的 Agent 运行时，看它把这件事放在哪一层、在哪一步下刀、压缩完怎么接回。它的分层、循环和工具管道在同类里都算交代得清楚的那一档，真正难抄的是几处取舍。下面按它自己的分层顺序走一遍，每层只讲它解决什么问题。&lt;/p&gt;
&lt;h2&gt;分层的红线不是隔层调用，是依赖只能朝一个方向&lt;/h2&gt;
&lt;p&gt;这套代码的主线有四个包，支线两个，职责从下往上越来越具体。最底下那层只负责把不同模型的接口抹平，往上那层只负责把循环跑起来，再往上才管读文件、跑命令、改代码这些具体业务。第四个包专管会话与存储，历史怎么落盘、上下文缩到哪一段、分叉从哪一条出发都归它。&lt;/p&gt;
&lt;p&gt;依赖方向是这个仓库唯一不能破的规矩，越往上越能引用底层，底层永远不回头引用上层。顶层的包同时依赖底层和中间层，看上去像是绕过了中间那道门，原因出在基础类型上：消息、模型、图片统一定义在一处，所有层都去引用那一处。&lt;/p&gt;
&lt;p&gt;红线在反方向：底层的代码里不许出现对上层的任何引用。这个方向一旦破了，上面两层就都换不掉了，隔层调用会顺手变成可以随便走的近路。类型跟着层往上长，这也是这个仓库里最省事的一处设计。上层加字段从不改底层的定义，单独抽出一个包发布也拖不走别人。&lt;/p&gt;
&lt;p&gt;最底层的工具只描述给模型看的部分，工具叫什么、参数长什么样。中间那层往下加一件工具该怎么执行。顶层再加这件工具怎么显示、在提示词里占哪一段。三层的同一个概念靠继承往下长，底层那份从没被上层塞过字段，所以哪个包单独拿出来发布，都不会拖着别的包一起走。&lt;/p&gt;
&lt;p&gt;分几层取决于要处理的复杂度。只想调模型不想要循环，用最底下那一层就够，循环自己写；想要一整套跑得起来的 Agent，用中间那层，工具注册什么由你决定，一个都不注册也能纯聊天。要做成一个完整产品形态，第三层才登场，这条判断比分层本身更值钱。&lt;/p&gt;
&lt;h2&gt;循环不是模型说停才停，是输出里还有没有工具调用&lt;/h2&gt;
&lt;p&gt;整个内核拆开其实很短：调一次模型，看返回里有没有工具调用，有就执行，把结果塞回上下文再调，直到返回里没有工具调用为止。这段逻辑本身很短，剩下的部分都是产品往外面叠的。中途插话、任务追加、每轮结束前换一次模型或换一次上下文，还有一个挂在外部、由外面说了算的停止钩子。&lt;/p&gt;
&lt;p&gt;驱动循环往下走看的只有两件事：返回内容里有没有工具调用，这批调用是不是全部要求立刻收手。第一个条件不成立就继续转，第二个条件成立就真停。就算这一轮被长度截断，只要内容里带着工具调用，工具照样会执行；反过来，工具调用一个接一个，只要每个都在要求收手，循环也会停。&lt;/p&gt;
&lt;p&gt;停止信号分两个来源。模型那侧给的是自然结束、被长度截断、返回了工具调用这几种；框架补的是调用出错和用户中断。后两种到了就硬停，不执行工具，不去看还能不能追加任务，直接收尾 —— 调用本身已经失败，再往下转只是在浪费预算。&lt;/p&gt;
&lt;p&gt;内核没有写死最大轮数，这件事明确地留给外面，兜底交给外面几样东西。外部钩子会在轮数或上下文快满时喊停，模型自己的长度上限、用户随时能按下的中断同样算。少了其中任何一样，一个爱调工具的模型就能把一次任务拖成一次长跑。内核不会先于它们出手。&lt;/p&gt;
&lt;p&gt;循环自始至终跑的是自己那一套消息类型，除了用户和模型的对话，里面还夹着压缩摘要、命令执行、分支总结这类只给内部看的消息。真正调模型之前才做一次降维，把这些挡在门外，只留下模型认得的那几种。降维压在边界上，内部才敢往里加新的消息类型，外面换一家模型接口也不用动循环。&lt;/p&gt;
&lt;h2&gt;工具出错不该抛给框架，该变成一条消息发给模型&lt;/h2&gt;
&lt;p&gt;工具这一侧最值得抄的是它怎么对待失败。一次工具调用中间要过五道。参数先过一遍兼容处理，把某些模型常见的畸形输出修成正常形状；接着做结构校验，类型不对直接挡住。&lt;/p&gt;
&lt;p&gt;再往后才是执行前的拦截，专门挡危险操作，中间那一步才是真正执行。收尾那一步做执行后的处理，脱敏、审计，或者干脆把这次结果改成收手。&lt;/p&gt;
&lt;p&gt;前几道里任何一道没过，工具一次都不会执行，产出的是一条标记为失败的返回，里面写着失败原因。执行那一步自己抛出来的异常也会走到同一个出口，翻译回同一类产物。六种出错方式最后收敛成一种，这里的判断很清楚：异常的面是调用栈，谁接谁就崩；消息的面是模型，谁看谁还能自己想办法。&lt;/p&gt;
&lt;p&gt;消息里写什么，决定了模型下一次对不对。一句「读取失败」给不出任何可行动的信息，模型只能瞎试；一句「偏移 200 超出了文件末尾，这个文件一共 100 行」一说，它下一次就知道该给哪个数。工具该做的就是把认得出来的错误重新包装一遍，附上是什么错、为什么、怎么改；认不出来的别硬编一句好看的描述，原样往外抛，让外面兜底透传。&lt;/p&gt;
&lt;p&gt;并行这块它取的是保守路线：一批工具里只要有一个声明了必须串行，整批就都串行。理由是哪些工具会互相冲突很难提前判定，同一个文件两次编辑、两次写同一个路径都可能出问题。真正往下走还分成三段：准备按顺序做、执行才并发、结果按调用顺序回灌。模型读到的先后就是它下指令的先后，顺序一乱，它连自己刚才要求过什么都对不上。&lt;/p&gt;
&lt;h2&gt;压缩之前还隔着一层减法，工具结果先剪过再进&lt;/h2&gt;
&lt;p&gt;轮到压缩之前，输入侧还有一层更简单的拦截。一次工具调用的产物不会整块进上下文：读文件默认留头，因为开头那段 import、类型、接口签名最密；跑命令默认留尾，因为报错和最终结果都压在末尾。两头各卡着两条线，行数与字节数同时设限，谁先到算谁。&lt;/p&gt;
&lt;p&gt;只限行数不行，一个压扁过的产物几行就能把字节数顶爆；只限字节也不行，五十 KB 的源码可能才两百行，按字节切会切出半行。方向也不统一，读和跑命令留的是两头的不同那一头，图省事从中间截的做法两边都不采纳。切到字节那一步还要处理一个要紧的地方：按字节往下数会数进一个四字节字符的中间，做法要么整字节留下要么整字节丢掉，绝不在半中间停住。&lt;/p&gt;
&lt;p&gt;剪掉的部分留了后路，截断因此有损但可恢复。结果里会记下总量、剪掉多少、按哪一条剪的，末尾还留一句逃生提示，全量输出落在临时文件里，要看就自己去读。这一条决定截断能一直开着当常态。&lt;/p&gt;
&lt;p&gt;系统提示词这一侧的取法是拉。十来份技能文档全文铺进去大约五万 token 的量级，真正铺进去的只是一份只含名称和一句话说明的清单，几百 token 就够，看任务对得上哪条再自己去读全文。工具清单和工具用法照样常驻，工具本来就可调用，不需要按需加载，这两样不该混成一类。&lt;/p&gt;
&lt;h2&gt;压缩发生在两轮之间，切点只能切在人和助手上&lt;/h2&gt;
&lt;p&gt;压缩的触发时机挪到了一轮结束之后，这是这一篇最该看的取舍。一轮跑完、收尾事件发生之后才去数 token，没超就等下一轮，超了才动手。这个位置很关键：压缩不改变正在跑的这一次，改的是下一次进来时的上下文，放在跑的过程中做等于边跑边换图纸。&lt;/p&gt;
&lt;p&gt;判定用的是一条能自己算的算式：窗口大小减去给回复留出的余量，当前用量过了这条线就压。以 200,000 的窗口和 16,384 的余量计，阈值就是 200,000 − 16,384 = 183,616。留余量这件事本身是对的，窗口塞满之后模型连回话的地方都没有。&lt;/p&gt;
&lt;p&gt;数 token 用的是估算，拿字符数除一个固定系数，取值方向是宁可估高不可估低。估高了最多多压一次，无害；估低了接口直接报错，有害。这里有个和中文有关的偏差：一个汉字实际占的份额远大于四分之一，按英文口径算会估小。它的应对办法是照旧保守估，同时留一条兜底路径，等接口真报溢出错误时再压一次重试。&lt;/p&gt;
&lt;p&gt;下一刀砍在哪是这个机制里最见功力的地方。工具结果不能当切点，工具结果必须紧跟在发起它的那条模型消息后面，把它挪到另一边，模型就会看到一个调用了工具却没有结果的下场。于是合法的切点只剩下用户消息和助手消息两种。&lt;/p&gt;
&lt;p&gt;它从最新的一条往回攒，攒到一个保留额度就停止，再往后找最近的一个合法切点，那就是刀口。压缩在这里的形态是一段分了阶段、落在存储上的活。先选切点，再让模型写摘要，中途调用出错而这份错值得重试，就记下进度等一会儿再来，真放弃也留下一条人能读的原因。&lt;/p&gt;
&lt;p&gt;选切点还多一条规矩：不能让一次工具调用停在它自己结果的前头，落点也要避开上一个模型输出还没收尾的位置。动手之前另有一次拒绝的机会，宿主可以先自己算一遍账，觉得现在压不动就压不动。切在用户消息上最干净，这一轮连着它后面的助手和工具结果会整块留下；切在助手消息上则能精确控制留下多少，代价是把一轮切成了两半，因为那个助手的发起者落在了压缩区。&lt;/p&gt;
&lt;p&gt;它选了切在助手消息上这条，再用一段专用摘要把切掉的那半个开头补回去。取舍很清楚：先保证压得动，再补回完整性。摘要本身不自由发挥，而是填固定几段：目标、约束与偏好、进度、关键决策、下一步、关键上下文。进度里还单独分了完成中、进行中、卡住三样，卡住那一条留给下一轮，下一轮看到就知道该先去解哪个结。&lt;/p&gt;
&lt;p&gt;让模型自由写一段总结，它大概率会把篇幅花在某个有趣的技术细节上，然后漏掉最初要干什么。固定分段就是把漏掉这件事变成必须填，自由发挥不如让它必须交作业。压过一次之后每次都把上一次的摘要一起喂进去做增补，目标还在，进度往前推。&lt;/p&gt;
&lt;p&gt;文件维度单独记：读过哪些、改过哪些，跨几次压缩一直累积。对写代码这件事来说，改过哪几个文件比聊过什么更硬，也更可验证。最后压出来的东西存成一个条目挂在会话上，下次进来重建上下文时，摘要顶在前面，近期的原始消息整段跟在后面。&lt;/p&gt;
&lt;p&gt;压缩在这里顺带解决了一个错觉：磁盘上一条旧消息都没动，重建上下文那一刻只是按位置把它们跳过。退回到压缩之前，完整的历史又原样出现在眼前。压缩是视图，不是清算。&lt;/p&gt;
&lt;h2&gt;对话存成一棵只追加的树，回退只是挪一个指针&lt;/h2&gt;
&lt;p&gt;状态存成一棵只追加的树，回退只是挪一个指针。一个会话一个文本文件，一行一条，进去就不改不删，每条只认它的父节点，父节点不记自己有几个孩子。看着别扭，但这正是只追加能成立的前提：父节点若维护子节点列表，长出新分支就得回头改旧节点，而只追加的规矩正是旧节点不许改。&lt;/p&gt;
&lt;p&gt;要找某个节点下面长过什么，靠一张全局映射反查，回退因此便宜到只剩一次赋值，丢下的分支一个字节都不会消失。分叉的实现方式是回退之后再追加一条，这条新节点的父节点自然就落在了分岔点上，和原来的那条共享同一个父。所谓两条支线，就是这个父节点的两个孩子。用空间换重做从不丢数据，这笔买卖在这个场景里划算。&lt;/p&gt;
&lt;p&gt;再往下看还省一层，分叉只在一个节点上接着往下写。存下来的历史永远不动，当前看到的是两个指针圈出来的一段区间。回退、压缩、切分支做起来都是挪这两下，从头到尾没有一次整段搬迁。&lt;/p&gt;
&lt;p&gt;丢掉的那条支线不必静默消失，分叉的时候还能顺手给它留一段交代。从当前位置往回走，第一个还落在另一条路径上的节点就是分岔点。分岔点之前两条路径重合的那段可以收集起来，让模型压成一段摘要挂在新分支开头，说的是之前试过什么、结论走到哪一步。&lt;/p&gt;
&lt;p&gt;这份摘要比压缩那套少一节，长度另有硬上限，因为它是辅助上下文，新分支自己也要留地方给主线。做不做由使用者定，旧支线一个字不提也能接着走。重建上下文的时候，从当前这条指针往父节点一路走回根，再把顺序反过来，只取这条线，别的分支不在这条线上就不进上下文。&lt;/p&gt;
&lt;p&gt;走过的过程按类型分派：是消息的进消息数组，是状态变更的就覆盖当前值，纯元数据的直接跳过。状态做成节点而不是塞进一个全局对象，好处是回退到切换模型之前，路径上不再包含那条变更，状态自己就退回去了，不需要谁去回滚。回退动作因此和翻历史是同一件事。&lt;/p&gt;
&lt;p&gt;压缩条目在重建时先用它的摘要生成一条摘要消息顶在最前面，再去翻它之前的那些条目，但只从它记下的保留区从哪条开始往后再收集，更早的一律跳过。真正删数据的是重建时的选择性收集，写入的时候一个字节都没动，这就是压缩可以非破坏的原因。&lt;/p&gt;
&lt;p&gt;写入还有一层延迟：一条用户提问先不落盘，等第一次出现回答之后再整批原子地写进去，这样才能保证恢复出来的一段对话至少是一问一答的，不会开局孤零零一条提问挂在半空。这类细节不在架构图上，但决定了用户上次断在哪。&lt;/p&gt;
&lt;h2&gt;内核外面还有编排和显示，都不算内核&lt;/h2&gt;
&lt;p&gt;编排层站在产品层之上，管的是多个实例一起跑：谁起谁停、进程之间怎么通信、编排能伸到多远。它自己一点内核逻辑都不写，循环、状态、压缩还是内核那套给。显示层更薄，只管把过程渲染给人看，Agent 换一套渲染方式，下面一层不用跟着动。&lt;/p&gt;
&lt;p&gt;编排和显示的价值都在于可换，这跟前面那条依赖红线是同一个道理的两种说法。存储这条线也留了口子，底层给的是可换的存储抽象，眼下跑的是文件实现，换一个数据库接口照样接得上去。接口在，替换就在，至于现在有没有走过去，不影响这个判断成立。&lt;/p&gt;
&lt;p&gt;规模这一头有硬数可查。单包过去一周的下载次数超过五百万次，这个口径是包仓库给出的七日区间。官方收录的扩展包五十多个，社区那边还有人把它接进别的编辑器、别的终端，甚至有一个非 Node 语言重写的移植版本。&lt;/p&gt;
&lt;p&gt;对外交付的形态有四种：一个交互终端，一条直接打印成 JSON 的命令行，一套走标准输入输出上 JSON 协议的远程通道，最后一个能被嵌进别人程序的软件开发包。后两种是给要把它接进自己产品的人准备的，也是判断一个运行时够不够格当底座的地方：底座要看的是它能不能被程序驱动，而不只是能被人一条条敲命令。&lt;/p&gt;
&lt;p&gt;扩展示例给得很足，子任务、规划模式、权限闸门、路径保护、远程执行、沙箱、模型上下文协议接入，官方都当自己造的东西列出来，没有一项算预置能力。这说明扩展的形态是拿得到工具、命令、快捷键、事件和界面的普通模块。做好的扩展、技能、提示模板还能打包，从包仓库或版本库里装，别人也能拿去用，这类分发渠道比扩展接口本身更能说明一套运行时有没有活着的社区。&lt;/p&gt;
&lt;p&gt;真把它当底座跑起来的产物，官方点名的一个是 OpenClaw，用来说明软件开发包这一路具体怎么接。围绕它还有几个外围包：终端显示是分开的那个包，多实例编排是另一个还挂着实验标记的包，循环、状态、压缩这些内核逻辑一个都不在它们里面。这两层都只图一个可换，跟前面那条依赖红线说的是同一件事。&lt;/p&gt;
&lt;p&gt;十章源码加七章上手那份里，写得最实的是压缩那几节。它回答了两个问题：切点为什么不选工具结果，为什么允许把一轮切成两半再用一段摘要补回来。这种细节看目录结构看不出来，也只有啃到这一层才知道它为什么这么设计。&lt;/p&gt;
&lt;h2&gt;该抄的是取舍，不是那几层目录&lt;/h2&gt;
&lt;p&gt;能上线的 Agent 和跑得动的 demo 之间的缝，落点不在那几层目录结构上。循环靠什么停、失败怎么变成一条消息、上下文快满时切在哪、状态存成什么形状，这几件事各自都有一个能自己算的口径，也都能被单独换掉。这套分层的价值只是让这些取舍不再互相焊死，改一处不用牵动全身。预算算清楚之后，剩下的功夫都在这一侧。&lt;/p&gt;</content:encoded></item><item><title>横向验收任何一个 AI 产品：一张八层检查表</title><link>https://your_domain/blog/20260930-eight-layer-checklist</link><guid isPermaLink="true">https://your_domain/blog/20260930-eight-layer-checklist</guid><description>判断一个 Agent 能不能上线，不该看它演示得多聪明。把产品拆成任务、上下文、能力、编排、执行、验证、状态、信任八层逐项问过去，任一层答不上来，就是那个洞。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;「让 Agent 给自己打分，评测集就开始变成作弊集。」自进化闭环跑起来之后，判断的方向要换：闭环会自己爬分，闭环跑得越顺，越看不出哪一层其实是空的。带这类环节的系统要判断自己站在哪、哪一层还是个洞，加指标没用，得有一张能逐层问出「这一层是空的吗」的表。&lt;/p&gt;
&lt;p&gt;我现在用的是一张八层检查表。这张表不是评分卡，是审问清单：每一层问同一个产品一件不同的事，任一层答不上来，产品就有一个确定的洞。这张表不负责讲怎么做，每一层的做法散在对应的那几篇里，本篇只把八层钉成一张能带着到处走的表。&lt;/p&gt;
&lt;h2&gt;八层怎么分：判据只有一条，拿什么判断一层是空的&lt;/h2&gt;
&lt;p&gt;八层怎么切，依据不是技术栈，是「一次任务要成立，需要依次满足什么」。从上往下走，越往下越工程，下面几层也常被当作已经做完。八层依次是任务、上下文、能力、编排、执行、验证、状态、信任。&lt;/p&gt;
&lt;p&gt;| 层 | 这一层问什么 | 空了会露出什么样子 | 判据见哪一篇 |
| --- | --- | --- | --- |
| 任务 | 想改变什么状态，目标值怎么量 | 「智能化程度提升」这类没法验收的目标 | 《先画依赖图，再写评测》 |
| 上下文 | 做对这一步必须知道哪些东西 | 答复通顺，依据全是猜的 | 《给上下文定预算》 |
| 能力 | 什么能做，边界画在哪 | 什么都答应，做不出来也不报错 | 《代码不是真相》 |
| 编排 | 怎么拆、怎么排、什么时候停 | 长任务跑不完也停不下来 | 《自治等级不是模型说了算》 |
| 执行 | 动作怎么真正发生 | 连得上管不住，权限、幂等、补偿全无 | 《自治等级不是模型说了算》 |
| 验证 | 怎么证明结果不是看起来合理 | 演示好看，真实流量一塌糊涂 | 《可验证性就是能力边界》 |
| 状态 | 断了之后怎么接上 | 会话断了就得从头再来 | 《自治等级不是模型说了算》 |
| 信任 | 用户凭什么授权给它 | 不可逆动作没有把关，出事追不到人 | 《自治等级不是模型说了算》 |&lt;/p&gt;
&lt;p&gt;任一层缺了，对应的失败形态是固定的。任务层没定义，就是「做完了但没人知道做完了没有」；上下文层没定义，答复通顺但依据靠猜；能力层没定义，什么都答应然后什么都做不到。反过来也成立——看到某种失败，能直接指回某一层没做。八层之外我盘算过要不要列第九层「知识」，最后没列。&lt;/p&gt;
&lt;p&gt;知识不单独占一层，因为它走的是一条同时穿过上下文层和能力层的路径，运行时只从它身上经过，不为它设单独的位置。上下文层问的是这次推理必须知道什么，能力层问的是什么条件下触发、允许调哪些工具、结果怎么校验，知识在这两个问法上各占一半。一份指标口径的定义、一条例外和适用条件，回答的是这次凭什么判断；一份进入条件、校验规则和异常退出的路径，回答的是这次按什么动作执行。前半段落在读取路径上，后半段落在执行路径上，抽掉任何一段，另一段都没有依靠。&lt;/p&gt;
&lt;p&gt;判断一件知识该落在哪一半，只看一句：这句话回答的是判断问题，还是执行问题。业务语义、指标口径、例外、适用条件、历史决策的结论都归上下文层；进入条件、槽位、守卫、停止条件、异常退出的路径归能力层。落到哪一半，一句话只占一个位置。&lt;/p&gt;
&lt;p&gt;历史决策是横跨两层最典型的例子：上次为什么这么定，是一次判断的结论，这条结论进知识。要用这条结论继续往下走，上下文层负责取到它，能力层负责在触发时校验这条结论还是不是有效版本。&lt;/p&gt;
&lt;p&gt;订单状态、库存、剩余额度这类每次都在动的东西归能力层现取，不写进知识。把这类东西写进静态知识，读到的一定是过期版本，还会盖住真正需要改的口径。&lt;/p&gt;
&lt;p&gt;放错位置有两个方向，代价都不小。规则本该进能力层却躺在上下文层，规则就以自然语言散在读取路径上，每次靠模型现场读、现场判适用，没有唯一生效版本。同一个口径在上下文层和能力层各解释一次，就解释成两样东西。动态事实该由上下文层现取，却写死进了能力层，能力就替业务系统扛了它扛不住的实时性，上游改了规则，这里还按旧值执行。&lt;/p&gt;
&lt;p&gt;还没变成可引用知识的那部分，先记为知识缺口，别悬在半空。落不下来的缺口不进任何一层的补法，等于没记。判断一条缺口值不值得补，看该覆盖的领域里尚无覆盖、当前版本给不出有效引用、多个会话里重复出现这三样。判出来先补哪半边，看这条缺口卡在读取这一半还是执行这一半，卡在读取那一半就先补上下文层。&lt;/p&gt;
&lt;p&gt;这张表的用法很机械：逐层问，每层只许答「过了」「没过」「不适用」。不许用形容词，「不太确定」就是没过。用形容词回答是常见的逃避——「上下文处理得还可以」不算回答，「这次要读哪三份材料、从哪取、读不到怎么办」才算。&lt;/p&gt;
&lt;p&gt;八层问下来，团队里对同一层的描述如果不一致，说明这层还没人给它下过定义。这种不一致比空项更容易被忽略，因为每个人描述的都是自己负责的那一半。&lt;/p&gt;
&lt;h2&gt;八层的判据各是一句什么话&lt;/h2&gt;
&lt;p&gt;任务层要把六样东西定死：作用对象是谁、发生在什么场景、现在基线多少、目标值多少、目标值怎么量、红线在哪。缺一样，后面所有讨论都会变成口味之争；没有基线的目标值只是愿望，「从 15 分钟降到 3 分钟」才是目标，中间状态也得有一个系统能读到的信号。&lt;/p&gt;
&lt;p&gt;目标值还要带样本口径和时间窗，否则复盘时目标值会自动变松。评测集用什么铺、铺在哪几个指标上、口径固定多久取一次，一次写死，中途不换。目标还要能拆出可观测的中间状态，每类任务至少留一个中间指标，中间指标不一定要暴露给用户。&lt;/p&gt;
&lt;p&gt;把上下文、记忆、状态当成一回事，是上下文层最常见的误判。上下文层只问一件事：这次推理必须知道的东西，每一样都答得出从哪取、取不到怎么办。三者是三样不同的东西，上下文层只管上下文和记忆，状态独立成一件，归状态层。&lt;/p&gt;
&lt;p&gt;缓存前缀该盯的是加速比：缓存读取相对重新生成的加速比衡量缓存策略，模型的能力单独算。把两者混在一起看，前缀排得再好也解释不了成本为什么没降。前缀按全局稳定、会话稳定、易变三段排好，命中率才有一个不漂的分母。命中率上不去，稳定段里常混进每次都变的内容——一处变动会把后面整段缓存全部打掉。&lt;/p&gt;
&lt;p&gt;上下文出毛病的方式基本就三种，分辨清楚才好下药：起作用的排到了后面、该取的不在范围里、塞进去却没当依据，三种都是白费。带得多不等于用得上。&lt;/p&gt;
&lt;p&gt;记忆的读取分三级，判据是命中：常驻的每次都带，可预测的开头取，其余按需查询。常用的东西每次都要重新检索，就是分级放错了。记忆写入走异步抽取、不占用户等待时间，这是上下文层唯一不能让步的一条。&lt;/p&gt;
&lt;p&gt;能力层要写的是边界，不是本事：什么条件下触发、允许调哪些工具、结果怎么校验、异常怎么退、输出长什么样。少了校验和异常两样，能力就只有正常路径，而线上大部分问题发生在正常路径之外。边界画得对不对，有一个能直接盯的数：转人工率，口径是转人工的会话占总会话的比例。能力层的验收不看这一问答得对不对，只看用户要不要再问一次。&lt;/p&gt;
&lt;p&gt;提示词和能力的分工有个经验起点：某个指令在三分之一以上的流量里都要用到，就进常驻提示词。低于这个比例做成按需加载的能力，三分之一这个分界要用真实流量去调。编排层只多问一件事：什么条件下退出。&lt;/p&gt;
&lt;p&gt;编排的六种退出条件里，费用上限最容易被漏，它是六条里唯一能在无人值守时自动生效的刹车。并行到什么程度也是编排层要定的，任务之间共享的大段上下文越多，越不该并行。编排还要区分确定性和判断：主链上能确定化的部分写成固定流程，只在真需要判断的地方放循环。整条链路都交给模型自由发挥，出问题就定位不到是哪一步偏的。&lt;/p&gt;
&lt;p&gt;执行层先定的是挡在调用前，还是补在调用后。按动作风险分四档——只读直接放行、要一次确认、可先执行后复核的必须可撤销、不可逆的每一步都要人点头。身份绑定、幂等键、熔断、补偿接口和审计留痕这五样由框架兜，不指望模型自觉，其中幂等的代价最高：重试一个写操作带来的重复副作用，排查成本极高。查询类动作放开重试，处置类动作必须带幂等键和证据链，把查询和处置混在一个动作空间里，重试策略就没法定。&lt;/p&gt;
&lt;p&gt;验证层的证据有强弱之分，弱的不算验过：静态检查、规则层面的比对、隔离环境里真跑一遍、真实流量下的表现。只做过第一级就发结论，等于什么都没验；负例和相邻能力的边界用例必须各占一部分，否则改动容易在边界上退化。覆盖率也有起步规模：每个用户流程按 50 到 100 个评测用例起步。够不够不看条数，看铺没铺到核心路径和高风险边界，随机抽样凑不出这个覆盖。&lt;/p&gt;
&lt;p&gt;对照做法同样不可省：新老版本在同一批用例上同时跑，按单条粒度看清赢在哪输在哪，只看平均分的变化会把「这里赢一点、那里输更多」的改动放过去。发布门禁上再配三件套——每次变更自带用例、负例和边界用例，能力改动先走金丝雀，并留一个能单独关掉某个能力的开关。&lt;/p&gt;
&lt;p&gt;同一批用例上看版本之间与人工的一致率、看硬冲突率归不归零，比看一个总分多报了两件事：对得更准，和错得更少。降级率也别被平均分吃掉，它单独盯的是真实流量里走了降级分支的请求占比。&lt;/p&gt;
&lt;p&gt;状态层和信任层常被当成细节，任务层、编排层、验证层这三段做得再漂亮，状态层和信任层空着，出事那天没人能交代。状态层的判据很朴素：把当前会话里最新的一条消息删掉，系统能不能从断点继续往下跑。恢复就两条路，选哪条看任务形态：检查点把中间状态整体存下来、恢复时直接读回，适合状态紧凑的；事件溯源只记动作、恢复时重放，适合动作可重放但状态很大。选错这条路线，代价在中断时才会暴露。&lt;/p&gt;
&lt;p&gt;任务跑到一半等外部审批、等人工输入、等下游回包，这三种等待的持久化方式都不一样，一个结论成形之前已经发生的副作用能不能安全重放，也得先想清楚。已经写下去的那几步不回滚，重放就只会再写一遍。检查点的粒度也有判据：恢复时重放的动作超过一次人工能等的时间，就说明切得太粗。验收时直接把断点掐掉再跑一遍，比在设计稿上讨论有用。&lt;/p&gt;
&lt;p&gt;信任层不看平时，只看出事那一刻用户拿到什么：走到哪一步、哪些状态已被改变、还能用哪部分产物、什么时候停、怎么接管或回滚。信任层的头号检查项是「系统有没有可能在回答里谎称完成」，降级之后仍报告成功，用户会拿一个空结果当结论往下走。&lt;/p&gt;
&lt;h2&gt;这张表真正的用法：动手之前过一遍，之后跟着版本重问&lt;/h2&gt;
&lt;p&gt;八层表最好用的时候不在验收现场，在设计阶段。动手之前把八层过一遍，会发现大部分被推迟的工作不是「以后再说」，是压根没进过计划。验收现场还要防演示路径代替评测：演示里那条路通常被调过很多次，它证明存在一条能走通的路，大部分请求走不走得通它一句也证明不了。演示之外要有一批验收方现场提供的用例，验收方现场跑，提前谁也不跑。&lt;/p&gt;
&lt;p&gt;要合成判断的时候按五个维度分别打分，不合成一个数：可信度、稳定性、适应能力、是否符合约定、效率。分别打的意义是一个产品可以效率很高同时可信度不及格，合成一个数之后这个结构就看不见了。&lt;/p&gt;
&lt;p&gt;成本单独占一格，看的是完成一次任务的总量，与单轮花费分开算。总 token 从 875,352 降到 676,987，降幅 22.7%，算式是差值 198,365 除以 875,352。单轮输入从 1,030,000 降到 634,905，降幅 38.4%，算式是差值 395,095 除以 1,030,000。降幅不在首次那一轮，在后面几十轮不再重复携带原始数据。&lt;/p&gt;
&lt;p&gt;主 Agent 端到端 token 从 708,783 降到 315,266，降幅 55.5%，算式是差值 393,517 除以 708,783，轮次从 17 降到 9。轮次降了近一半，说明省下来的不是某一轮的冗余，是链路里原本多余的往返。&lt;/p&gt;
&lt;p&gt;从进入到拿到可信结果要多久，这个指标比准确率更贴近用户，也比盯任何一个单层的分数更接近真实体验。它把等待、澄清、返工和人工确认全算进去，八层里任何一层做不好都会拖低它。&lt;/p&gt;
&lt;h2&gt;拿这张表过 12 个已上线的 AI 功能&lt;/h2&gt;
&lt;p&gt;这张表不只在自家系统上有用，我拿这张表过了一遍已经上线的 AI 功能。12 个系统，覆盖零售问数、排障、文档生成、客服答疑这几类，都在真实流量上跑着，不是 demo。口径这样定：「过了」是某一层有能被系统读到的东西，一段配置、一份用例、一条门禁、一个接口都算。「空」是被问到某一层现在靠什么机制保证时，只能给出口头承诺，上面那些一样也拿不出来。&lt;/p&gt;
&lt;p&gt;评审按层项记，12 个系统乘 8 层是 96 个层项，一个个记，不记整体印象。96 个层项里 28 个是空的，28 ÷ 96 = 29.2%。空项按层排下来，顺序很整齐，整齐本身才是值得警惕的地方：&lt;/p&gt;
&lt;p&gt;| 层 | 空项数 | 占 12 个系统 |
| --- | --- | --- |
| 验证 | 6 | 50% |
| 上下文 | 5 | 41.7% |
| 编排 / 信任 | 4 / 4 | 33.3% |
| 执行 / 状态 | 3 / 3 | 25% |
| 任务 | 2 | 16.7% |
| 能力 | 1 | 8.3% |&lt;/p&gt;
&lt;p&gt;排在前面的验证层和上下文层有个共同点：空着照样能演示。验证层空就没有门禁，问题只在真实流量里显形；上下文层空，答复通顺到肉眼根本看不出来。编排层和信任层紧随其后，理由一样。&lt;/p&gt;
&lt;p&gt;空着也看不出来，是因为验证层、上下文层、编排层、信任层这四层的结果都不在每日检查里。任务层和执行层反而不空，「目标含糊」一问就露，「不可逆动作」一跑就出事，它们空不住。&lt;/p&gt;
&lt;p&gt;验证层排在最空还有个结构性原因：验证层最晚才被要求做。产品先上线，评测集和发布门禁跟着第一次事故补，补的时候又缺样本，于是验证层长期停在「发布前自己看一眼」。&lt;/p&gt;
&lt;p&gt;同一批系统在三个月后我重问了一遍，96 个层项里 31 个结论翻转，31 ÷ 96 = 32.3%。翻转最密的是验证层 7 个和编排层 5 个，加起来 12 项——翻转数可以大于空项数，因为从「过」翻回「空」也算一次。验证层和编排层这两层补一次就能从空变过。&lt;/p&gt;
&lt;p&gt;能力层只有 1 个翻转，边界改一次很慢，多数层的翻转落在 3 到 4 个。所以这张表不是一次性工具：验证层和编排层的结论跟着版本走，每次发版都要重问；能力层的空更像长期欠账，评审问出来就挂着等那次改动。&lt;/p&gt;
&lt;p&gt;还有一组数讲这张表实际怎么被问：同一轮评审里 96 个层项有 22 个压根没人问，22 ÷ 96 = 22.9%。状态层和信任层各有 5 个系统没被问到，各 41.7%（5 ÷ 12）；执行层 4 个；能力层 0 个。跳过的正是出事那天才用得上的层，能力层一次也没跳过，因为能力层直接决定演示好不好看。问不出「这一层是空的吗」，多半是这一层压根没人问。&lt;/p&gt;
&lt;h2&gt;哪几层必须提前做，哪几层可以后补&lt;/h2&gt;
&lt;p&gt;28 个空里，13 个属于上线前必做，15 个有干净的降级替身可以后补，13 加 15 正好是 28。分界看的是空了之后还有没有一条替路。必须提前做的是验证层、上下文层和任务层，这三层空了没法事后补。验证层要的是评测集和发布门禁，得先有样本和真实流量；上下文层要的先是取数、再是组织，得能稳定取到料。&lt;/p&gt;
&lt;p&gt;任务层要的是基线和量法，不补它，后面每层都无从判定。可以后补的是编排层、信任层、执行层和状态层，这四层都有「先降级到能跑」的替身。编排空就先串行跑单轮，信任空就先全量转人工兜底，执行空就只放开只读，状态空就把长任务切短。能力层那 1 个要等上游能力就位才能补，单独记一笔工期。&lt;/p&gt;
&lt;h2&gt;这张表的价值不在一次答全八层&lt;/h2&gt;
&lt;p&gt;用过这张表之后我改了一个习惯：不再问一个产品聪明不聪明，而是问信任层答得出来吗。任务层到验证层做得再漂亮，信任层空着，这个产品就还是个演示品。这张表标出的不是八层全过的那个分数，是 96 个层项里哪几层现在是空的。除了空项，这张表还标出一层关系：哪一层空了会连累哪一层。&lt;/p&gt;
&lt;p&gt;上下文层空着，验证层再全也验不出依据；状态层空着，执行层跑得越顺，烂摊子铺得越开。12 个系统里一次过八层的只有一个，知道哪几层空、空了往哪层传染，比把八层一次填满更有用。&lt;/p&gt;</content:encoded></item><item><title>让 Agent 给自己打分，评测集就开始变成作弊集</title><link>https://your_domain/blog/20260917-self-scoring-eval-set-contamination</link><guid isPermaLink="true">https://your_domain/blog/20260917-self-scoring-eval-set-contamination</guid><description>自进化闭环一旦转起来，分数的含义就变了：题变窄、判据泄漏、模型给自己答案打高分，都能让曲线向上而能力不动。这篇写怎么给闭环装一根模型碰不到的尺子，也写闸门不装时分数往哪走。</description><pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;给 Agent 装自进化闭环的人，最后大多会撞上同一件事：分数还在往上走，走上去的那个东西越来越不像能力。题是模型自己出的，答案是模型自己答的，「这次为什么成功」还是模型自己总结的——三件事同一个来源，分数就不再是别人手里的尺子，变成它给自己记的分。被测系统一旦自己改写评测集，评测集就变成作弊集。这篇要拆的就是分数上变化的来路，以及怎么在闭环里留一根模型碰不到的尺子。&lt;/p&gt;
&lt;p&gt;自进化闭环是我见过最容易让人产生错觉的东西：评测找出缺陷，缺陷转成经验，经验写进记忆，下一轮再跑起来。曲线往上走本身就让我警觉。自进化这条线我认同，只是要在每一段上补一件事：给每段装一把它碰不到的尺子。&lt;/p&gt;
&lt;h2&gt;分数涨了，涨的不一定是能力&lt;/h2&gt;
&lt;p&gt;自进化这两年跑出来的可对照量级，主要落在两条路线上：一条从失败里复盘出 Skill 再用，另一条把经验写进权重。第一条路线上，开放问答的准确率从 60.6% 推到 67.9%，涨 7.3 个百分点。第二条路线上，三个环境分别到 89.9%、72.7%、47.1%，同一条基线在 77.6%、66.1%、约 38.5%。相对基线分别涨 +12.3、+6.6、+8.6 个百分点，经验库同期从 55 条涨到 100 条。&lt;/p&gt;
&lt;p&gt;这两组数只报了涨了多少，没报涨在哪一环，这正好是要拆开的东西。涨出来的那部分里，多少是能力、多少只是把尺子挪近了，不看结构永远分不出来。&lt;/p&gt;
&lt;p&gt;自进化的主张本身是对的：让系统在日常任务里积累经验，比人一条条总结出得快得多。闭环有个结构性缺陷：它优化的信号，来自一个它自己参与构造的评价过程。出题是模型做的，解题是模型做的，总结「这次为什么成功」的还是模型。三者同源，分数就不再是一把独立的尺子。&lt;/p&gt;
&lt;p&gt;分数涨了有几种常见的假象，共同点是都能让曲线向上。光看曲线认不出是哪一种，得靠几道独立的读数把出题、答题、判分这三者拆开。&lt;/p&gt;
&lt;p&gt;| 现象 | 看起来像 | 实际可能是什么 | 怎么确认 |
| --- | --- | --- | --- |
| 通过率持续上升 | 能力在长 | 题集被换成模型擅长做的那些 | 留一批它没见过的新题，只看这一批 |
| Judge 分数变高 | 输出质量变好 | 评委偏爱被测模型的表达风格 | 换一档模型当 Judge，看分数是否回落 |
| 加了 Skill 之后做对了 | Skill 有增量 | 任务本来就简单，模型本来就会 | 拿掉 Skill 再跑一遍，做消融 |
| 上线之后表现平稳 | 这次优化没有副作用 | 输出变长、工具变多、拒答率在漂 | 盯方向性指标的分布，不只盯通过率 |&lt;/p&gt;
&lt;p&gt;「加了 Skill 之后做对」这个结论我验证过：某个 Skill 加上之后，通过率很好看。我把这个 Skill 删掉再跑同一批 40 条用例，通过率只掉 1.7 个百分点，插进来的 token 却是实打实的。归因没有对照，成功就记错了账。&lt;/p&gt;
&lt;p&gt;一致率和冲突率必须一起报，才看得出这次是真对得准、还是把冲突挪了个地方。更隐蔽的是藏在一次成功优化后面的「上线之后表现平稳」，答案风格悄悄变了——更长、更啰嗦、工具调用更多——这些压根不在指标里。这类漂移从不让任何一条用例失败，它只让成本和体验慢慢变差。自进化里每次「分数变好了」的报告，都该长成这个样子。&lt;/p&gt;
&lt;h2&gt;闸门不装，分数会往哪走&lt;/h2&gt;
&lt;p&gt;要拆的第一件事是「不装闸门会怎样」。先拆第一条路线。同一批开放问答复盘出 Skill 之后涨了 7.3 个百分点，把同一套 Skill 挪到另一个检索任务上、不重新训练，只剩 +5.3 个百分点。&lt;/p&gt;
&lt;p&gt;7.3 减 5.3，差的这 2 个点就是同源数据在题集内部自循环换来的。经验库也在同步长，通用和任务专属两类条目都翻了近一倍。库翻一倍，同期三个环境最好的一个也就换来 12.3 个百分点。经验库不是能力，库变长本身说明不了涨分是从哪来的。&lt;/p&gt;
&lt;p&gt;另一组数指向的是别的资产。让模型自己用自己总结的 Skill 跑同一批任务，两档强模型分别把成功率从 30.6% 推到 71.1%、从 29.6% 推到 69.8%，都在 +40 个百分点上下。&lt;/p&gt;
&lt;p&gt;这两个 +40 的对照口径是同一批任务上的自进化。把其中一档总结的 Skill 直接搬给四个弱模型，提升落在 +35.4 到 +44.1 之间，可绝对值都低于让弱模型自己自进化，最差的那个只到 43.1%。同一份经验换个执行载体就掉一档，掉了这一档照样当成有效经验写进库，这是记忆污染最安静的一条路：不报错、不回滚，只是越用越不划算。&lt;/p&gt;
&lt;p&gt;脏的是记忆，不是分数。一条错误经验写进去之后，在有人查到它之前，可能已经影响数百次后续任务，而错误蔓延的速度远快于修复速度。环境抖动的失败一旦当成「能力缺口」写进长期记忆，后面好几轮都会在这条错误上继续长。等到看清，能做的往往只有把记忆模块整个关掉退回无状态，积累下来的经验一起清零。&lt;/p&gt;
&lt;p&gt;这一路能一路涨上去，根因是一致率门槛没卡住。评测信号无意中奖励了啰嗦：写得更长的答案更容易撞上正确内容，于是每一轮分数都在涨，每一轮的技术门控也都通过，方向却已经偏了。&lt;/p&gt;
&lt;p&gt;等回头看已经偏了十几个版本，连该回滚到哪一版都定不下来。这条路等回头看才发现，已经偏出去十几个版本，连该回滚到哪一版都定不下来。门槛具体卡在一致率上。同一批样本上，两边结论完全一致才算一条，Judge 与人工的一致率到不了 85%，这个数以下的分数就定不了结论，只能退回半自动抽检。&lt;/p&gt;
&lt;h2&gt;出题、答题、裁判必须是三方&lt;/h2&gt;
&lt;p&gt;对策的结构很清楚：闭环里至少要有一样东西是模型碰不到的，先动验证资产。一份固定版本的隐藏题集，平时读不到，只在验收的时候跑一次。这份题集的题谁也顺手优化不了，因为没有任何一条通道改得到它——这条听起来朴素，却是整套设计里唯一不可替代的一件。&lt;/p&gt;
&lt;p&gt;数据三分是这个思路的标准形态，三个集合的分工和可见范围各不相同。具体怎么切，看下面这张表。&lt;/p&gt;
&lt;p&gt;| 集合 | 谁能看 | 用它做什么 |
| --- | --- | --- |
| 训练集 | 可以暴露给修复生成器 | 让它据此改自己 |
| 验证集 | 不暴露，只在调参时读 | 判断这次改动有没有用 |
| 测试集 | 完全独立 | 只在验收时跑一次 |&lt;/p&gt;
&lt;p&gt;切的时候按问题类型分层，不能随机撒。随机撒的结果是三类题在三个集合里分布不一致，测出来的差别其实是分布差别。起步比例我按训练集六成、验证集两成、测试集两成来分，实际由样本量和风险定——高风险场景宁可把测试集比例往上抬。&lt;/p&gt;
&lt;p&gt;角色分离同理：出题、执行、总结、判定，能分开就分开，判定这一环至少要跟被测对象不同源。自进化那条线上的角色划分我照做，并且额外要求总结者不参与出题。总结者一旦参与出题，经验就会朝它自己擅长的方向长。&lt;/p&gt;
&lt;p&gt;自生成的题目还得守住一条：答案不能由模型自己给。凡是能构造出确定性答案的题，就用执行结果或者规则来判定；只有真正开放的题才让模型判，并且这批题要单独标记、单独监控它们的通过率变化。&lt;/p&gt;
&lt;p&gt;外部刻度还要再补两样。先是版本化的外部基准，它不参与任何调参，只用来回答「这一版比上一版强在哪」。课程分布监控跟在后面，记录题集在知识点、难度、动作类型上的分布。分布莫名其妙变窄，就是课程坍缩的信号，这时候分数涨了也要停下来看。&lt;/p&gt;
&lt;p&gt;冷启动这一环必须有人先推一程，它最容易被漏掉。没有这一圈，闭环连往哪个方向转都是它自己定的。题集的构造方式也得写死——比例、分层、题源每次现想，前后两次的分数就不可比。&lt;/p&gt;
&lt;h2&gt;让 Judge 看证据，别让它看答案&lt;/h2&gt;
&lt;p&gt;裁判是最容易坏的一环，因为它是唯一有权给分的地方，坏了没人反对。它一坏，整套读数就跟着歪。&lt;/p&gt;
&lt;p&gt;我的做法是把事实提取和语义裁决分开。凡是能用确定性断言判的——某个值有没有取到、某次调用有没有发生、结果等不等于预期——全部在进 Judge 之前判完。剩下「不同但可能合理」那一小撮才交给 Judge。我把它给分的范围压到最小，出错的面也跟着变小。&lt;/p&gt;
&lt;p&gt;Judge 本身还要校准。我自己卡的经验门槛是：跟人工复核的一致率到 85% 左右，口径是同一批样本上两边判定结论完全一致才算一条，到这个数才允许它进日常自动化。每次 Judge 版本升级，就把与人工的一致率、高风险样本的漏判率、边界样本的重复波动这几样重测一遍。哪一样不对，就退回半自动。&lt;/p&gt;
&lt;p&gt;评审规则只留在内部，这条同样容易被忘。把评分细则暴露给被测对象，等于教它怎么迎合裁判：我见过答案为迎合评分表变冗余——每一条都对得上标签，没一条真正解决问题。&lt;/p&gt;
&lt;p&gt;金标校准集怎么建也有讲究。样本得覆盖边界和高风险两类，随机抽一百条达不到——抽出来的几乎全是简单样本，测不出 Judge 在哪里会错。校准集还要跟 Judge 版本一起归档，换版本就重跑，不然「一致率 85%」这句话会一直沿用下去，直到它早就不是真的。&lt;/p&gt;
&lt;p&gt;Judge 和被测模型如果同源，风险还要再加一层：它会偏好自己的表达风格。解法是换一档模型当裁判重新跑一遍。分数明显回落，量到的是相似度；分数不回落，量到的才是质量。&lt;/p&gt;
&lt;p&gt;把事实提取前置，在这条线上有现成的例子。一次调用失败，返回体里往往已经写清楚了是排队、限频还是参数错，只是系统没把它结构化提取出来。把这几类做成可读字段再交给判定环节，绝大部分样本在进 Judge 之前就已经有了确定答案，需要它发表意见的只剩真正开放的那几题。Judge 的判断面越小，它坏掉时能造成的损失也越小——这是这一环唯一的原则。&lt;/p&gt;
&lt;h2&gt;每一段都要有外部刻度&lt;/h2&gt;
&lt;p&gt;把自进化拆开看：评测产出信号，记忆承接沉淀，落地把改动变成生效的东西，控制保证方向不偏。都通了，飞轮才转得起来。&lt;/p&gt;
&lt;p&gt;| 环 | 做什么 | 这一环的外部刻度 |
| --- | --- | --- |
| 评测 | 发现缺陷、判断更新是否更好 | 隐藏集与人工抽检 |
| 记忆 | 决定什么值得沉淀 | 写入门槛与预算上限 |
| 落地 | 从候选改动到生效 | 独立评测与发布门禁 |
| 控制 | 保证长期方向不偏 | 方向性指标与周期审计 |&lt;/p&gt;
&lt;p&gt;自进化要区分两种信号：能力信号看同类题在隐藏集上有没有做得更好，知识信号看原本不知道的事实后来有没有派上用场。两种信号的验证方式不同，把能力信号和知识信号混在总分里看，就分不清这次进化是长了本事还是长了笔记。&lt;/p&gt;
&lt;p&gt;闭环会放大评测的误差，不会把它平均掉。评测这一环的价值不止是打分，它还决定哪些经验值得沉淀。弱 Judge、过时的题集、不公平的预算，会把错误写进记忆和 Skill，形成错误加速。&lt;/p&gt;
&lt;p&gt;落地这一环是工程量最大的一环，本质上是给 Prompt、Skill、记忆做一套持续交付。诊断、汇聚信号、生成候选改动、独立评测、安全门控、灰度、回流、沉淀，这一整圈走完才算一次进化。跳过其中任何一步，省下的是今天的工时，付出的是下个月的返工。&lt;/p&gt;
&lt;p&gt;控制这一环最容易被当成「出事再说」，它的作用其实相反：分级自主、不可逆红线、人工节点、方向性审计、自动降级，这几样决定了评测、记忆、落地三段闯祸时的上限。回归全绿不等于方向没偏，这是这一环存在的全部理由。&lt;/p&gt;
&lt;p&gt;进化出来的东西分三层，成本和风险差得很远：产物层是单次任务的输出，任务结束即失效；装配层包含记忆、Skill、Prompt、工具与工作流，可回滚，是主战场。模型层改的是权重，成本最高、风险最大。绝大多数自进化该发生在装配层，它便宜、可回滚、可审计。动模型层之前，先问装配层是不是已经做到头了。&lt;/p&gt;
&lt;h2&gt;经验进记忆要过两道门&lt;/h2&gt;
&lt;p&gt;评测侧的防线之外，更持久的污染来自记忆。闭环里最贵的后果是它把错误经验固化下来反复用，一次打分不准还排不到它前面。所以一条经验要进长期记忆，得先过两道门。&lt;/p&gt;
&lt;p&gt;诊断门先回答：这次失败是真能力缺口，还是题目本身坏了，还是环境抖了一下。后两类——题目坏了和环境抖——不该产生任何经验，它们只会把记忆搞脏。过了诊断门才是验证门：先在隔离样本上确认有效，再确认它在真实任务里没有引发新的破坏。没有这两道门，系统会把错误的归因固化成长期记忆，越用越差。&lt;/p&gt;
&lt;p&gt;写入门槛得先定：只有正信号和明确的反例才值得沉淀，含糊的中间态不写。中间态写进去，记忆里就会堆满「大概是这样」的条目，而这类条目在后续检索里会和真正的规则抢注意力。&lt;/p&gt;
&lt;p&gt;时间这一维也得单独守。经验按「在前序任务里学到、在后序相关任务里验证」的逻辑积累，切分必须严格按时间走。否则未来信息会漏进今天的评测，制造出一种预测能力很强的假象——这类假象在回测里特别好看，上线当天就消失。&lt;/p&gt;
&lt;p&gt;能力回归得跟代码回归一视同仁。每次改动能力或提示词，都要带上它自己的用例、负例和相邻能力的边界用例一起跑。只跑它自己的用例，会漏掉「这次改动把旁边那个能力带坏了」，而这类退化在平均分上几乎看不出来。&lt;/p&gt;
&lt;h2&gt;把运气和方向分开读&lt;/h2&gt;
&lt;p&gt;同一个 Agent 跑同一道题，两次结果可以不一样。这种方差如果不当回事，很容易把一次运气好当成优化有效。&lt;/p&gt;
&lt;p&gt;我自己做过一轮重复实验：8 道长题，同一版本每道连跑 5 次，合计 40 次完整执行，单次约 20 分钟，机时约 13 小时（40 × 20 分钟 = 800 分钟）。波动全部集中在 3 道需要跨文件比对的题上，区间分别是 60%–100%、40%–80%、20%–100%，全批极差 80 个百分点；其余 5 道基本不动。&lt;/p&gt;
&lt;p&gt;判据因此要分两层。稳定那 5 道自身就有 0 到 20 个百分点的摆幅，噪声会盖住比这更小的提升，这种提升算不上结论；波动那 3 道要先跑够次数才敢比。重复次数得按跑数定：跑满 40 次之后，这 8 道题的通过率才敢拿去跟下一轮比。只跑一遍的数字，涨了也是噪声。&lt;/p&gt;
&lt;p&gt;配套的判据是 champion-challenger。它要求新版本按单条用例粒度看清赢在哪、输在哪。在平均分上赢一点点不算赢，还得设一条下限——涨不到 20 个点不算数，这 20 个点就来自稳定那 5 道题自身的摆幅。它也不能在相邻能力的边界用例上退化——不少改动就退在这里，平均分看不出来。&lt;/p&gt;
&lt;p&gt;读记忆的顺序同样要设限。我按高层背景、关键词检索、按需回溯原文这三层走，越往下越贵也越少走到。没有这个顺序，记忆层会退化成「每次都全文塞进上下文」，那跟没有记忆治理是等价的。版本同样容易漏：模型版本、Prompt 版本、记忆版本都要跟分数一起落盘，否则两个月后回看那条突然变好的曲线，没人说得清是哪一次改动带来的。&lt;/p&gt;
&lt;p&gt;除了通过率，我还一直盯一组方向性指标：输出长度的分布、工具调用轮次的分布、拒答率的变化趋势。任何一项发生系统性漂移都值得去看一眼，哪怕当时分数很好看。这组指标的成本极低，它只需要把已有的日志做一次分布统计。&lt;/p&gt;
&lt;p&gt;归因要能落到具体环节。我按现象层看到的是什么、过程层哪一步开始偏离、责任层该改哪个模块来记。Trace 证据汇总之后先缩圈再定责。省掉过程层，归因会退化成「大概是 Prompt 的问题」，而这类结论没法变成行动。&lt;/p&gt;
&lt;p&gt;周期人工审计也是这一环的一部分。自动化盯住的是你事先想到的那几项，人看的是「有没有出现我没想到的东西」。频率不必高，但要有固定节奏，并且每次都要留下结论，写进审计记录。&lt;/p&gt;
&lt;p&gt;评估器本身也得评一遍。我维护一份元评测集，专门盯「机器判的和人判的差多少」，不一致率一旦抬头，就得停下来校准评估器，别继续信它输出的分数。评估器失准却无人知道，是闭环里最难被发现的一类失效——因为所有报表看起来都正常。&lt;/p&gt;
&lt;p&gt;再往外是两道硬约束，它们保住「随时能停下来」的主动权：自动产生的变更进入发布流程前过人工门禁，高风险能力退化触发自动回滚。冷启动、价值判断、领域取舍、合规与安全红线这几件事得由人定，Agent 自己定不了。&lt;/p&gt;
&lt;p&gt;自进化闭环值得跑，它的复利是真的。但在跑之前要先回答一个问题：这条闭环里，有没有一样东西是模型碰不到的？&lt;/p&gt;
&lt;p&gt;没有的话，闭环只是把偏见一圈圈放大，分数会涨得很漂亮，走得也越来越远。有了——一份它读不到的题集、一个不同源的裁判、一道能回滚的门——这条闭环才立得住：每一圈都由外部刻度校准，涨上来的分数才敢当成能力去兑现。闭环跑起来之后，判断哪一层还是空的同样需要一个基准，八层验收总表补的就是这一块。&lt;/p&gt;</content:encoded></item><item><title>先画依赖图，再写评测：你的指标会互相污染</title><link>https://your_domain/blog/20260908-evaluation-dependency-graph</link><guid isPermaLink="true">https://your_domain/blog/20260908-evaluation-dependency-graph</guid><description>三个指标同时掉，往往只是一个根因被记了三次。评测体系的顺序错了：先把执行依赖图画出来，再规定每个指标在什么条件下可评，才轮到 Judge 和门禁。</description><pubDate>Tue, 08 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;把工具权限和自主决策交给 Agent 之后，第一个绕不开的问题就是怎么判定 Agent 有没有走偏。绝大多数 Agent 评测体系不是没东西：测试集有，Judge 有，看板有，回归也有，还有一批人每周过 badcase。&lt;/p&gt;
&lt;p&gt;这套体系坏在一个更靠前的地方：指标是先堆起来的，归因是后补的。加指标的时候每层都有当时的理由，等要看为什么掉分时，没人记得这张表当初为什么这么排。&lt;/p&gt;
&lt;p&gt;顺序应该是反的：先把被测 Agent 的执行依赖图画出来，再按这张图规定每一个指标在什么条件下可评。结论就这一句：上游没跑通的时候，下游指标记「失败」，等于把一个根因重复记成了好几个失败。这类污染从看板上完全看不出来，红色反而越堆越密。&lt;/p&gt;
&lt;h2&gt;三个指标一起报警，根因只有一个&lt;/h2&gt;
&lt;p&gt;常见的搭法是先列一张指标表：幻觉率、检索精确率、召回率、回答忠实度、工具调用准确率、任务完成率。跑一遍，看板出来，某个数字掉了，再去 badcase 里手工翻原因。这六个指标沿着执行链排成单向依赖。路由决定走哪条分支，分支决定检索是否执行，检索的输出决定回答忠实度能不能算，工具调用的入参决定工具调用准确率能不能算。&lt;/p&gt;
&lt;p&gt;任何一个模块掉线，排在它后面的检索、引用和忠实度三项分数同时失去意义。阿里全球化商品中心的智能答疑 Agent 把这条链拆得很清楚，四段是感知、规划、记忆、工具，链上任一处断掉，后面三项一起失效。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;期望路径：查询意图 → 知识检索 → 引用绑定 → 生成
实际路径：查询意图 → 技能分支 → 直接生成

检索模块  → 未执行
引用模块  → 无输入
忠实度    → 无比较对象

看板：三项同时记失败
根因：一处
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我在自己的用例集里见过两条这种形态，都是把一处失败记成多处失败。两条形态不同，扩散结构却一致。一条是知识根本没有检索到，但回答写得很自信。看板上这是两个指标同时掉，翻下去只有一个原因，可修的对象只有检索的召回。&lt;/p&gt;
&lt;p&gt;两条链的形态不同，扩散结构却一致：一个根因沿依赖链向下，扩散成多个「失败」。多轮会话里丢失上一轮的上下文对象，是其中一条；会话再往下问「那这个呢」，Agent 答不上来，看板却同时记成多轮完成率失败、意图识别失败、检索失败。看板上的红色越密，真正该改的那一处越容易被淹掉。&lt;/p&gt;
&lt;h2&gt;「不可评」是一个正当结果&lt;/h2&gt;
&lt;p&gt;给每个指标定义可评条件，是后面所有判定成立的前提：指标的上游依赖是什么，依赖没满足时记什么。可评条件没定义出来，加多少指标都是在放大噪声。依赖不满足时记 error 并跳过统计，failed 只留给真做错的模块。error 和 failed 在看板上都显示成红色，指向的行动却不同：error 说明这次运行没真正检验这个模块，failed 说明这个模块做错了。&lt;/p&gt;
&lt;p&gt;| 上游状态 | 下游指标 | 记什么 | 指向的行动 |
| --- | --- | --- | --- |
| 依赖已执行 | 全部 | 正常判定 | 按分数走 RCA |
| 依赖未执行（上游失败） | 依赖其输出的所有指标 | error，跳过统计 | 修上游 |
| 依赖未执行（上游是正确拒答） | 同上 | error，跳过统计 | 无需行动 |
| 依赖执行但返回为空 | 该模块自身 | 按用例语义判定 | 可能是真失败 |&lt;/p&gt;
&lt;p&gt;「不可评」最实际的价值是它逼你把执行链写下来，写不出来说明还没搞清楚这个 Agent 怎么工作。上面这张表的第二行是依赖未执行且上游失败，第三行是依赖未执行且上游正确拒答。两行的下游都记 error 并跳过统计，差别只在行动上：第二行要去修上游，第三行本来就该跳过。没有这张表，做评测的人遇到正确拒答这类 case，会反复排查一个根本不存在的问题。&lt;/p&gt;
&lt;h2&gt;一个评测范围只能有一个主指标&lt;/h2&gt;
&lt;p&gt;定义完可评性，接着要收敛判定口径；判定口径不收敛，看板上的通过率没人敢拿去做决策。我的做法是每个评测范围只设一个主指标，这个指标单独决定用例通过与否。&lt;/p&gt;
&lt;p&gt;其余指标全部降级为诊断维度，只负责解释为什么，成败由主指标单独决定。端到端范围用任务完成率，工具范围用调用准确率，多轮范围用多轮完成率。多个指标一起做 AND 时，一个格式问题就能否定一个内容完全正确的用例。&lt;/p&gt;
&lt;p&gt;一个评测范围只能有一个主指标，这个位置留给最接近用户结果的那个指标，最容易测的排不进来。多指标一起做 OR，会让几乎一切都能通过；一起做 AND，看板上的通过率又莫名偏低，翻出来的 badcase 全是措辞和排版，真正的内容问题反倒没人翻。&lt;/p&gt;
&lt;p&gt;小米零售的 AI 问数项目把这个分离讲得很直白。企微领域一次评测放进 18 个指标、122 条用例，中间层返回的结构化查询构造准确率是 93.2%，这一层判的是查询构造得对不对。&lt;/p&gt;
&lt;p&gt;另一版另建 44 条专项用例复测，专门盯同一根因，不再沿用原测试集。两个数字都真实，指向的却是两件事：一个回答查询有没有构造对，一个回答用户实际拿到什么。结构化查询构造准确率仍然是 93.2%，最终答案准确率是 100%（44/44）。17 条失败 case 里还有一组更能说明主指标该怎么选。&lt;/p&gt;
&lt;p&gt;按根因聚类新增专项用例，修的是一整类问题，看板变绿的同时系统也在变好。17 个失败里 8 个来自同一个根因。时间字段和偏移规则分了两套口径，占比接近一半。按原题逐条修 Prompt，能把这 8 条修到通过，看板立刻变绿，却只覆盖这 8 条。&lt;/p&gt;
&lt;p&gt;单轮平均分是多轮场景里最常见的陷阱。小米零售问数在「达成率」上补齐指标边界、表达决策表、用户归属和过滤约束之后，指标选择准确率从约 65% 提到约 98%，差的只是这几条口径知识。一个退款会话里，Agent 每一轮都解释得很自然，语气、结构、同理心都没问题，全程却没调用订单查询工具就承诺了退款。按单轮平均分这个会话能拿高分，按端到端完成率算失败。&lt;/p&gt;
&lt;p&gt;四层一起看，才分得出说得好和做成了。对话型 Agent 我拆成四层，每层只回答一个不同的问题，单轮平均分只回答了其中一层。腾讯 SRE 的错误码 Agent 更狠：必需查询有没有执行、参数对不对、工具失败有没有显式降级、证据支不支持结论、置信度匹不匹配，每一项单独判一遍。&lt;/p&gt;
&lt;p&gt;| 层 | 看什么 | 典型陷阱 |
| --- | --- | --- |
| Turn | 单轮回答质量、工具选择 | 单轮好看但方向错了 |
| Session | 多轮目标是否连贯达成 | 中途丢上下文对象 |
| Trace | 工具调用链、入参、返回 | 宣称调用过但实际没有 |
| Outcome | 用户问题是否真的解决 | 回答正确但业务状态没变 |&lt;/p&gt;
&lt;p&gt;只看动作类型，分不出「有证据地答对」和「碰巧答对」。假阳性里有一类要提前排掉：多轮评测常固定等一小段时间，持久化链路本身一有延迟，评测就会把延迟当成「Agent 忘了」。这种假失忆属于观测问题，单列在能力分之外。&lt;/p&gt;
&lt;h2&gt;忠实于拿到的材料，不等于事实正确&lt;/h2&gt;
&lt;p&gt;评测能证明的只有一件事：回答有没有忠实于手里拿到的材料。忠实于拿到的材料，证明不了材料本身是对的；两件事一旦混在一起，检索侧的问题都会算到生成侧头上，优化方向从一开始就偏了。&lt;/p&gt;
&lt;p&gt;语法对、执行通、忠实于拿到的表，三项全对，只有业务口径错了。小米零售问数踩过这样一个坑：Text-to-SQL 语法全对，直接汇总支付金额，漏掉取消、退款、退货的过滤，结果比标准口径高出近 10%。&lt;/p&gt;
&lt;p&gt;高德本地生活的经营分析 Agent 也栽在同一类问题上。一次行业接入里，用总量除以对象数量得到的平均值，与直接查询结果相差约 10%；追下去发现分子分母来自两套数据源，统计范围没对齐。&lt;/p&gt;
&lt;p&gt;口径错在数据源，改措辞改不掉这个错。高德那条线的解法绕开了改 Prompt：先统一来源，再核验总量等于对象数乘平均值这个恒等式是否闭合。更隐蔽的一种错是数字来源正确、对象范围错了，把全部纳入统计的对象算成尚未开始使用的对象。这种错光核对数字查不出来，这笔账没算错，只是答错了问题。&lt;/p&gt;
&lt;p&gt;有一道判据要写进评测体系：金额、口径、状态、时间窗这些能拿权威系统对账的字段，都要留一条独立于模型输出的对账路径。没有这条路径，评测给的信心是假的。忠实度和事实正确是两笔账，评测不能只算前一笔。文档把真正的报错原因写成另一套说法，Agent 忠实复述出来仍然错。&lt;/p&gt;
&lt;p&gt;主指标定下来之后，指标表必须按 Agent 类型分开建。同一张表覆盖所有类型，等于给每个类型都留下一半测不到的地方。我按类型分开建表，六种的主指标是这样：前三种有客观口径，后三种各有各的说法。这六条按能不能指回一个可改对象排，不是拍脑袋定的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;知识问答类，主指标是答案正确率，配套看引用命中率和检索轮次；&lt;/li&gt;
&lt;li&gt;任务执行类，主指标是端到端任务完成率，过程看工具调用链走没走完；&lt;/li&gt;
&lt;li&gt;推理决策类，主指标是结论正确率，过程看关键步骤有没有被跳过；&lt;/li&gt;
&lt;li&gt;创意生成类没有客观主指标，走人工评审加可用性采纳率；&lt;/li&gt;
&lt;li&gt;多轮引导类按多轮完成率判，过程看澄清轮次和重复询问率；&lt;/li&gt;
&lt;li&gt;多 Agent 协作类仍按任务完成率判，成本侧重在子任务之间重复打包的上下文。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;指标表必须按类型分开建，同一个「幻觉率」就是活例子：放在知识问答上是核心指标，放在创意生成上几乎没意义。方案、架构这类无法用对错判的输出，值得单独建表，阿里的架构师 Agent 在需求覆盖这一维能到 95% 以上。这个数字拿有证据支撑的需求条目除以原始需求条目，衡量的是覆盖，跟上线成功率、免人工比例是三回事。我按六个维度验收——需求覆盖、系统影响、证据支撑、风险识别、验证方式、不确定性声明。&lt;/p&gt;
&lt;h2&gt;Judge 只判 Trace 里能查出的事实&lt;/h2&gt;
&lt;p&gt;再往下是判定层，这一层最容易坏，因为是唯一有权给分的地方。规则层先做粗筛，把明显通过、明显失败、存疑三类分开。只把存疑的部分交给模型精判，高风险和低置信的走人工。这么分是为了让模型只做模型擅长的那部分判断，粗筛已经把能确定的判完了。&lt;/p&gt;
&lt;p&gt;精判阶段有一条硬要求：Judge 读 Trace 里的事实，不读最终回复。Judge 判断的是这一次工具到底有没有被调用、入参是什么、返回是什么。从回答文本里推断调用过没有，那是在猜；Trace 里的调用记录是结构化的，没有解释空间。&lt;/p&gt;
&lt;p&gt;模型完全有能力写出一段读起来像是查过订单的回答，任何基于文本语义的判定都会在这类用例上出错。这个区别比看上去重要。Judge 自身也要被当成被测对象来治理：备一份金标校准集，边界样本配 few-shot，多模型对抗防同源偏好。&lt;/p&gt;
&lt;p&gt;经验基线和人工的一致率在 85% 上下，这个数字当门槛太松，当基线才合适。这个基线用来观察 Judge 有没有漂移。&lt;/p&gt;
&lt;p&gt;腾讯 SRE 那条线上的对照更完整。同一批 50 条 case，v3 到 v4 与人工的一致率，从 66%（33/50）提到 88%（44/50）。一致率 66% 和硬冲突率 20% 这两个数字，分母都是这 50 条 case，分子分别是一次判定和一次硬冲突，33/50 变成 44/50，硬冲突从 10/50 降到 0。&lt;/p&gt;
&lt;p&gt;一致率能被这样量化，Judge 才算一个可治理的组件，从此可查、可改、可追。可治理的前提是把这条口径写进报告，让人知道分子的来源。&lt;/p&gt;
&lt;h2&gt;Real 和 Mock 各自隔离了什么&lt;/h2&gt;
&lt;p&gt;评测执行有两种模式，Real 和 Mock 两种模式隔离的东西不一样，都不能省。只跑一种，等于默认另一类问题不存在。&lt;/p&gt;
&lt;p&gt;Real 模式接真实工具返回，评的是端到端能不能跑通，代价是外部波动混了进来：同一个用例今天通过明天失败，可能跟 Agent 一点关系都没有。Mock 模式固定工具返回，把外部变量钉死，评的是策略在固定输入下能不能工作。Agent 的决策路径完整保留下来，你能干净地看到「给定这些输入，Agent 会不会做正确的判断」。&lt;/p&gt;
&lt;p&gt;功能性回归跑 Mock，发布门禁跑 Real，两条链路共用一份用例，结果才可比。只跑 Real，策略问题会被环境噪声盖住；只跑 Mock，证明不了真实环境里能跑得通。&lt;/p&gt;
&lt;p&gt;数据集的搭建顺序跟这个逻辑一致，先做 50 到 200 条高质量 golden case，覆盖核心路径和高风险边界。跑稳之后再扩四路——分类采样集、长尾集、对抗集、线上回流集。按模块给一组起步规模：&lt;/p&gt;
&lt;p&gt;| 用例类型 | 建议规模 |
| --- | --- |
| 基础技能 | ≥50 条 |
| 知识问答 | ≥100 条 |
| 多轮对话 | ≥10 组 |
| 上下文衰减 | ≥10 组 |
| 其余专项 | ≥20 条 |&lt;/p&gt;
&lt;p&gt;回归要跑得完也跑得稳，超时、重试次数和并发度都要先定死。这组配置压的是两件事：超时压住跑不完的长任务，重试和并发把外部抖动挡在 Agent 能力之外。&lt;/p&gt;
&lt;p&gt;数据集维护上有一件事值得单独记。高德那条线上返修时做过一次证据瘦身：只保留影响半径内的证据，取舍按错误字段和引用关系来定。评测集同样适用：判断变了才重跑，只改版式就保留原判断。全量重跑既贵，又会破坏本来就正确的部分。&lt;/p&gt;
&lt;p&gt;评测集要收线上样本，但只靠随机抽样不够：线上绝大多数是正常样本，随机抽一千条，高风险边界一条都覆盖不到，而决定事故率的恰恰是那些边界。成本指标必须和质量指标在同一次运行里采集，这事常被往后推。分两次跑出来的两个数字，最后还是要在汇报时对齐，等于白付一次时间成本。&lt;/p&gt;
&lt;p&gt;我每次评测固定记三样：调用次数、token 用量、端到端延迟。这组记录和质量分数落在同一条记录上。&lt;/p&gt;
&lt;p&gt;一次改动同时抬高通过率和平均工具轮次，说明这次改动多半把成本挪了地方。两套数字分两次跑、存在两张表里的话，没有人会做这个对比。工具轮次对体感的影响比分数大得多。&lt;/p&gt;
&lt;p&gt;同一次操作，一条路径是 3 次工具调用、约 2 秒落地，另一条是 15 次调用、约 15 秒收敛。通过率上两者可能打平，用户感受到的却是两个产品。&lt;/p&gt;
&lt;p&gt;把人工耗时折算进同一个口径，成本表才真正有意义——这一步把「好不好」翻译成「值不值」，是评测报告里最该有的一段。线上还要补一组单独的数。小米零售问数上线后服务 1000 多名店长，渗透率 88.8%，口径是活跃店长里用过问数的比例；同期沉淀约 1.6 万条真人对话，满意度 4.32 分（满分 5 分）。&lt;/p&gt;
&lt;p&gt;这些数字不属于离线评测，但这一组线上数字是离线指标有没有选对的唯一校验。离线评测通过而线上关键指标恶化是真实存在的。我在门禁里加了一条：离线提升但线上核心指标下滑，就触发回滚或降级，不再继续观察。这条要写进发布流程，交给流程盯着，不指望人记得看。&lt;/p&gt;
&lt;p&gt;收尾是把分数变成改动，分数到不了改动，前面整篇讲的东西都不落地。badcase 归因是一串固定动作：汇总证据，用「问题现象 × 功能模块」的映射表缩圈，按模块标出通过、软通过、失败，定主责和次责，收尾做结构化落盘。&lt;/p&gt;
&lt;p&gt;落盘不能省，落盘是下一次复盘的起点，也是回归集的新增输入。输出的优化建议按可执行程度分四档：只报告、开工单、给配置建议、直接给 PR 候选。&lt;/p&gt;
&lt;p&gt;分级的好处是拿到报告的人一眼知道这条要不要现在动，省掉这一步报告就会变成一堆没人认领的描述。发布门禁上我只认连续成功率。至少一次成功率在方差大的系统里几乎是必然事件，拿它当门禁等于没有门禁。&lt;/p&gt;
&lt;p&gt;配套三样东西：置信区间、显著性判断、最小可感知变化阈值。缺了这三样，两个版本之间的小差异能让人争论一整天，而那可能只是噪声。指标本身也分三档：最上一档用于上线门禁，中间一档用于版本比较和工程优化，最低一档用于体验改善和长期观察。最上一档的数量要克制，超过五条以后看板就只提供讨论素材，不再指导行动。&lt;/p&gt;
&lt;p&gt;评测体系本身的搭建成本也要算进去。阿里把 Skill 做成可评测之后，新增一个用例只要改一份声明式配置，公共部分与单用例部分分开写，单用例只声明输入、断言和判定方式。&lt;/p&gt;
&lt;p&gt;脚手架太贵的评测，跑两次就没人愿意再跑；这套顺序走完之后，看板上的每个红点都能落到一处具体的修改对象。看板的价值就在这里——把争论收敛成几个具体的修改对象。判据和指标都定住之后，新的问题会自己长出来：让系统自己出题、自己判分，评测集就会反过来污染自己。到这一步，评测集从标尺变成了被测对象。&lt;/p&gt;</content:encoded></item><item><title>自治等级不是模型说了算，是能不能撤销说了算</title><link>https://your_domain/blog/20260901-autonomy-level-reversibility</link><guid isPermaLink="true">https://your_domain/blog/20260901-autonomy-level-reversibility</guid><description>给 Agent 多少自由度，判断依据不是模型看起来多聪明，而是动作的确信程度和撤销代价。L2 自治不是配置项，是幂等键、撤销窗口、补偿接口和审计工程出来的。</description><pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这个方向是错的。讨论 Agent 能做到多自主的时候，话题几乎总是绕回模型：这个模型够不够强，换下一代会不会就好了。&lt;/p&gt;
&lt;p&gt;判据齐了不等于可以放权，能放多少取决于动作可不可撤销。环境这一层收口之后，手里有了一组能给出确定结论的判据。&lt;/p&gt;
&lt;p&gt;自治等级不是模型能力的问题，是确定性和可逆性这两个维度能不能工程化的问题。给 Agent 放权到什么程度，跟模型强不强只有很弱的相关性。真正划出上限的是两个变量：确定性，也就是这个动作的对错能不能被规则确定地判断；可逆性，也就是做错了能不能撤回来。&lt;/p&gt;
&lt;h2&gt;该不该放权，先看确定性和可逆性&lt;/h2&gt;
&lt;p&gt;这两个维度都不在模型那一侧，模型影响得了判断的质量，影响不了判断可不可判、动作撤不撤得回。我给任何写操作做分级时只看两个维度：确定性看这个动作的对错能不能用规则判出来，可逆性看做错了代价多大、多久能恢复。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;确定性&lt;/strong&gt;只有一种判断方法：能不能写出一条判它对错的规则。查某个订单状态、把一段文本写进草稿、给一批商品打上候选标签，这些动作的结果可验证，规则抓得住对错。而「给这个客户写一段安抚话术」、「判断这笔交易该不该通融」这类动作，对错依赖语境，规则给不出确定的判断。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可逆性&lt;/strong&gt;看两个数。一个数是恢复到正常状态的时长中位数，另一个数是恢复要付出的代价，有没有人介入、要不要发公告、会不会留下用户可见的痕迹。改一个配置，回滚是一秒的事；往外发一条消息，发出去就发出去了；扣一笔款，撤销要走流程，还可能留下痕迹。&lt;/p&gt;
&lt;p&gt;这张表给的是每一格对应的自主程度和交互方式。把确定性当横轴、可逆性当纵轴交叉，自治等级就定下来了，交互方式也跟着定。&lt;/p&gt;
&lt;p&gt;| 确定性 | 可逆性 | 该给的自治与交互 | 典型动作 |
| --- | --- | --- | --- |
| 高 | 高 | 完全自主，事后抽检；直接执行，把结果展示出来 | 生成草稿、打标签、跑只读查询 |
| 高 | 低 | 自主执行加撤销窗口；执行前预览，或执行后允许撤销 | 改配置、提交变更、批量更新 |
| 低 | 高 | 建议加一次确认；行动前明确确认 | 生成回复草稿、推荐策略 |
| 低 | 低 | 人主导，Agent 只做信息准备；说明范围、目的和接收方后再让人确认 | 付款、对外承诺、删除、发布 |
| 判不准，或恢复不了 | — | 降一档自治，转人工 | 任何验证不了的动作 |&lt;/p&gt;
&lt;p&gt;真正危险的格子只有一个：低确定性加低可逆性那一格。落进这一格的动作，模型再强也不该自己动手，模型能做的上限是把材料准备好，让人来做那个决定。越往自主的一头走，前置条件越硬。只读类直接放开，带建议的动作要一次确认，先执行后复核的动作必须可撤销，不可逆的动作每一步都要人点头——这四格不是权重不同，是前置条件不同。&lt;/p&gt;
&lt;p&gt;通用大脑从来不是起点，每家都从一件具体的事切进去。公开案例的切入顺序都印证这条：飞鹤先啃设备运维和人事流程，来伊份先做门店巡检和智能补货，邯郸公积金从离退休提取这类高频适老事项切进去。&lt;/p&gt;
&lt;p&gt;这些案例能落进哪一格，看「做完了」有没有定义成一条可断言的业务终态，模型说话多像已经办成事都不算数。工单已派单且住客可见，这才叫办成；接口返回 200 不算办成。判定做实之后，Agent 才敢在那一格里一次做到底，而不是每一步都回头问人。&lt;/p&gt;
&lt;p&gt;落到我看过的量级上，也全都在这四格里。设备运维把故障恢复的中位时长从 104 小时压到 47 小时，口径是同一批设备上故障从发生到恢复的时长中位数。&lt;/p&gt;
&lt;p&gt;重复故障率从 34% 降到 8%，口径是同一批设备里重复发生的故障占故障总数的比例。这一条比恢复时长变短更能说明问题：重复故障率降下来，说明这套系统不只是响应变快了，还把第一次的处理结果留成了下一次能直接用的判断依据。&lt;/p&gt;
&lt;p&gt;客服那边省的是人的时间。这套客服助手上线首月收口了 230 万次会话，口径是首月由 Agent 收口并闭环的会话条数，约等于 700 名全职坐席的产能，量级接近同期人工客服会话量的三分之二。人工会话的处理时长从 11 分钟降到不足 2 分钟，口径是同一批会话由人工接手到闭环的时长均值。&lt;/p&gt;
&lt;p&gt;收益是判据的副产品，量级大不大从来不是放权的理由。设备恢复 47 小时、重复故障率 8%、客服收口 230 万次这三个数能同时拿到，前提是落在同一格里的动作可验证、能回退，落点还是在放权边界上，不在模型那一侧。&lt;/p&gt;
&lt;h2&gt;L2 不是配置出来的，是工程出来的&lt;/h2&gt;
&lt;p&gt;模型输出的是建议，不是幂等的操作。不给模型撤回来的能力，模型说的「我做完了」就没有任何兜底。很多自治分级表里写着一个「在边界内自主行动」的等级，却试图只靠一段 Prompt 实现它，这段 Prompt 基本不会生效。&lt;/p&gt;
&lt;p&gt;L2 要成立，底下必须有四样东西托着：幂等键、撤销窗口、补偿接口和审计。四样缺一样，L2 就站不住。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;幂等键&lt;/strong&gt;。同一个意图重复提交，系统必须认出这是同一次操作，而不是执行两遍。键由会话标识、业务对象和操作类型拼出来，模型自己编的字符串不拿来当键——模型连上一次自己说的键是什么都未必记得住。重试必须带同一把键，已经成功写过的那一次不再执行，超时重发和并发重复提交才不会变成两笔。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;撤销窗口&lt;/strong&gt;。执行之后留一段时间，用户和系统都能在这段时间内撤回来，不需要走工单。窗口定多长不按实现方便定，按人什么时候看见结果定——一旦确认消息发出去了，窗口就短不下来。窗口内状态变更要对用户可见，让他知道现在挂着什么待定。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;补偿接口&lt;/strong&gt;。窗口过了才发现错了，得有反向操作把状态推回去，而不是让人去手工改。补偿做不出来的动作只能退回人工确认那一档，这也是小额退款走得通、大额退款必须停在 L1 的原因。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;审计&lt;/strong&gt;。谁在什么时候以什么依据让 Agent 做了什么，这条记录要能查到当时的输入快照和生效的规则版本，出事之后才答得出「当时是谁批准这次调用的」。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;幂等键这一条最容易被跳过，它翻车的路径也隐蔽。模型自己重复生成了一次提交，或者网络超时后客户端重发了一次请求，没有幂等键，用户那笔操作就执行了两遍。这类事故在评测里几乎不会出现，评测不重试，等评测之外第一次撞上重复提交，往往已经在上线之后。&lt;/p&gt;
&lt;p&gt;这四样是工程设施，不是提示词技巧。四样齐不齐，直接决定敢不敢把 L2 的开关打开。我在写操作上还坚持一条：模型只生成&lt;strong&gt;暂存的变更&lt;/strong&gt;，由执行层在应用时按当前规则复核一遍。唯一的检查点在应用时，从生成到应用之间，规则、库存、用户权限都可能已经变了。&lt;/p&gt;
&lt;p&gt;放权之后还得留一条能立刻收回来的线：每个能力配齐它自身的正例、负例和相邻能力的边界用例，能力改动先走金丝雀，单独关掉某一个能力的开关一直留着，高峰期冻结变更。这些开关平时看不见，出事的时候它们是在几分钟内把影响面收回去的唯一手段。&lt;/p&gt;
&lt;h2&gt;交易不变量要写在模型碰不到的地方&lt;/h2&gt;
&lt;p&gt;涉及交易时，有几类规则我会直接写进执行层，不进模型上下文，也不让模型参与判断。强制这一层不在提示词里，也不在模型里，它落在调用链上，Anthropic 的电商 Agent 把这类规则放在模型之外的执行链里。把强制写在提示词里，等于把锁和钥匙交给同一个人。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;只接受本会话下发的标识。&lt;/strong&gt; 商品 ID、订单 ID、优惠券码，必须是本会话服务端返回过的。模型自己拼出来或者从历史消息里翻出来的标识一律拒收——这是最容易被越权利用的一条路径。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;按结果状态查限额，不按单次请求查。&lt;/strong&gt; 单个请求看都合规，十个请求叠加就越过了折扣、数量和预算上限。限额必须在应用时按当前累计结果判断。这条可以说得更直白：限额只看当前购物车的状态。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;同会话的写操作串行化。&lt;/strong&gt; 并行写会让「同时三个请求各自没超限额、加起来超了」这种情况完全不可见。串行是正确性前提，性能上不吃亏。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三方文本一律清洗加围栏。&lt;/strong&gt; 商品描述、用户留言、外部接口返回的文本里，可能藏着能改变 Agent 行为的指令。这些内容只当数据送进来，走的是数据通道，不走指令通道。&lt;/p&gt;
&lt;p&gt;哪一段权限条件交给模型去写，答案就会越权可读。权限这一层要跟着动作一起定，小米零售的 AI 问数在权限上就这么做：指标权限和数据范围由系统在查询前注入，按店长、分公司这类角色自动附加可见范围。判「指标是否存在」和判「用户有没有权限」是两条不同的出口，查询还没跑，权限预检已经先给出结论。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;别让模型对工具结果做语义重写&lt;/strong&gt;，这一条容易被忽略，性质跟前面三条不一样：前面三条管的是动作边界，这一条管的是结果可信。电商场景里，如果允许模型改写商品标题、价格或库存的展示文案，链路后段就分不清哪个数字是权威系统返回的、哪个是模型润色过的。结果显示必须是权威系统的原值，可解释性才有意义。&lt;/p&gt;
&lt;p&gt;这些规则的共性是：它们属于模型碰不到的那一类规则，不属于模型应该记住的那一类。我特意不把它们写进上下文——写进上下文，模型就知道它们存在，也就有了绕开它们的可能。放在文档里写「禁止调用某接口」，跟真正把那次调用拦下来，是两件完全不同的事。更彻底的做法是：消费者端的工具清单里根本不给扣款接口，支付与下单由受控组件完成，模型手里根本没有扣款工具可调。&lt;/p&gt;
&lt;h2&gt;确认点由风险决定，不由流畅度决定&lt;/h2&gt;
&lt;p&gt;自治等级定了，剩下的是交互：什么时候让用户点一下。这一步最容易被「别打断用户」带偏。我的判据是动作风险，不是对话流畅度。&lt;/p&gt;
&lt;p&gt;| 动作类型 | 默认交互 |
| --- | --- |
| 只读、可撤销、低成本 | 直接执行，结果展示出来 |
| 有限写入、容易回滚 | 执行前预览，或执行后允许撤销 |
| 对外发送、发布、付费、删除 | 行动前明确确认 |
| 涉及敏感数据或广泛权限 | 说明数据范围、目的和接收方后再确认 |
| 无法可靠验证或恢复 | 降低自治，转人工 |&lt;/p&gt;
&lt;p&gt;两条边界都要守住。每一步都确认，Agent 会退化成一个昂贵的按钮，用户点确认的时间比自己做完还长。反过来，为了「流畅」把关键确认取消掉，代价是事故。&lt;/p&gt;
&lt;p&gt;确认的方式也要按场景分。加购、改数量这类动作交给结果状态直接确认；结账必须经受控组件，并带上服务端本会话下发的标识，模型自己拼出来的标识拒收。搜索结果为空要明确说没有，并给出放宽条件或替代项。遇到规则冲突，展示冲突项让用户裁决，而不是替用户猜。&lt;/p&gt;
&lt;p&gt;体验上另有一条判据：感知延迟和任务完成延迟要分开治理，展示基于真实工具参数的进度就能明显减少等待感，但不能用动画去掩盖结果质量或者未完成状态。用户感知到的「快」如果建立在虚假进度上，一旦出错就会全部还回来。更聪明的模型单 token 更慢，但规划更好、轮次更少，p90 和 p99 反而可能改善。只看单次响应时长会做出错误的模型选择。&lt;/p&gt;
&lt;p&gt;确认面上还有一条硬要求：展示的是&lt;strong&gt;最终状态&lt;/strong&gt;，不是意图描述。用户要看到的是「这张优惠券将被用在订单 12345 上，实付金额变为 ¥ 87.50」，而不是「我将为你使用优惠券」。&lt;/p&gt;
&lt;p&gt;批量操作不能共用一次确认。「这十笔订单都要改，确认吗」这句话把十次决策压成了一次，而用户实际背书的只是其中他最没把握的那一笔。我的规则是一次确认只覆盖一个业务决策，批量只批「执行」这个动作，每笔的判断要单独过一次。省下的那几次点击，会在出问题那天以十倍的价格还回来。&lt;/p&gt;
&lt;h2&gt;失败态与验证分层，让框架代管一整类错误&lt;/h2&gt;
&lt;p&gt;大多数产品的失败提示是一句「抱歉，我做不到」，这句话提供的信息量是零。我认为失败态至少要交付这几样：已经完成到哪一步，改动了哪些状态，失败的直接原因和置信度。接着是哪些产物仍可用、会不会重试、什么时候停。最后落到用户能改什么，怎么回滚或安全退出。&lt;/p&gt;
&lt;p&gt;置信度那一栏单独说一下：它必须区分「查过了，没有」和「不确定，没查到」。这两者给用户的下一步完全不同——查过了没有应当结束，没查到应当换个条件再试或者转人工。把它们都写成「没找到」，用户就会自己再问一遍，再问一遍通常还是同样的结果。腾讯那条错误码排查 Agent 把置信度做成了显式字段，并与行动类型绑定：低置信的猜测绝不以结论形式下发，判不出根因就直接走升级路径。&lt;/p&gt;
&lt;p&gt;失败态里最容易被忽略的是回滚与安全退出。打标为高置信的条目约占九成，口径是线上近一个月判为高置信的条目数除以同期排查条目总数。九成打在高置信上，说明这个字段的门槛是稳的，不靠模型语气撑出来。没有退出路径的失败，会让用户在半完成状态里反复尝试，每一次尝试都留下新的副作用。&lt;/p&gt;
&lt;p&gt;一个内循环要能在没人盯的情况下跑完，控制面至少要有步数上限、整段超时、费用预算、写操作幂等、同参重复调用熔断，以及工具结果按业务 schema 校验。这几项缺一项，那一圈只是在用 token 换偶然成功。停止条件缺一栏的时候，代价不是慢，是同一句话反复解释、费用在涨、单没办。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;空结果和不回答是合法的产品行为&lt;/strong&gt;，这一点本身就是一条产品设计。指标消歧失败的时候给两三个候选让用户选，比硬猜一个强；没有权限的时候明确说没有权限，比换个日期重试一次强。可预测的澄清、拒绝和停止，本身就是信任机制——用户害怕的不是 Agent 做不到，是它做不到还装作做到了。&lt;/p&gt;
&lt;p&gt;自治放权越大，验证越要提前。把可答范围收紧、把判定做实之后，系统学会了在答不了的时候明确说答不了，编一个看起来合理的答案反而更糟。把答不了也当成一种合法结果算进指标之后，指标的可信度反而上来了。三层验证栈怎么裁，在讲可验证性那篇已经说过，这里只补放权带来的那一条：越往自主的一头走，秒级那一层越要多拦一点，因为人不再在回路里逐个动作地看。&lt;/p&gt;
&lt;p&gt;这一层真正要防的是假完成。成功与否按业务断言判定，不看接口返回的 200：回复「已为您办理」而工单没有派单，就是假完成。自治等级越高，假完成越难被发现——没有人在每一步回头核，而 Agent 自己永远认为它做完了。&lt;/p&gt;
&lt;p&gt;下沉规则用的判据跟那一篇是同一条：能下沉的是事实，不是代理指标。放到放权这一侧，判据还要再紧一格——凡是影响撤销能力的规则，一律下沉到执行层，不留在模型上下文里。留在上下文里的规则，模型知道它存在，也就有了绕开它的可能；放进文档里写「禁止调用某接口」，跟真正把那次调用拦下来，是两件完全不同的事。&lt;/p&gt;
&lt;p&gt;放权之后，评测的起点也要跟着变。只从干净状态跑，测的是第一次撞上陌生问题时的做法，而线上大部分请求都发生在半完成的状态里。我自己测的时候直接从一个困难状态启动：购物车里已经有商品、地址只填了一半、上一轮刚失败过，再看它能不能接住。配套的是正负对照和边界用例：不只测「该做的做没做」，还要测「不该做的有没有被挡住」。&lt;/p&gt;
&lt;p&gt;放权有没有放对，最后要落到一组不随版本漂移的用例上，而不是这一轮的跑分。用例换一批，前面所有关于放权的结论就都作废了。&lt;/p&gt;
&lt;h2&gt;放权的顺序&lt;/h2&gt;
&lt;p&gt;回头看，放权有固定的先后顺序。先把撤销能力做出来，再谈自治等级；先把那几条不变量下沉到执行层，再谈模型能不能自己判断；先定义清楚失败态长什么样，再谈成功率。&lt;/p&gt;
&lt;p&gt;按这个顺序做的系统，自治等级是可以往上调的——每往上一格，底下都有对应的兜底。先调等级再补设施，每一次放权都是在增加事故面积。模型能力提升会改变的是「能做的任务范围」，不会改变「做错了能不能撤回来」这条边界。撤销代价一直由工程决定，模型代次插不上手。&lt;/p&gt;
&lt;p&gt;放权一旦开出去，走偏没走偏、走偏多少，就变成一个评测问题。指标怎么定义、怎么采样、怎么卡住刷分，是评测那一步要处理的事。&lt;/p&gt;</content:encoded></item><item><title>可验证性就是能力边界</title><link>https://your_domain/blog/20260825-verifiability-is-the-boundary</link><guid isPermaLink="true">https://your_domain/blog/20260825-verifiability-is-the-boundary</guid><description>生码只占研发链路 20% 到 30%，口径是需求到上线里写代码这段的耗时占比，继续优化它的边际收益已经很低。Agent 能走多远，取决于你能给它多少真实反馈——构建、测试、部署、日志、监控，缺一样它就只能靠训练分布猜。</description><pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;上下文预算的切法定下来之后，真正顶到面前的是另一问：这一次做对了没有，由谁来判定。切预算是在有限的上下文容量里决定带什么进来，定判定是在同样的容量里决定信什么——两个动作挤的是同一份容量，决定的却是两件不同的事。&lt;/p&gt;
&lt;p&gt;讨论 Agent 能接管研发流程哪一段的时候，我的答案跟模型无关：它能走多远，取决于你能给它多少&lt;strong&gt;真实反馈&lt;/strong&gt;。构建能不能跑、测试有没有过、部署在什么状态、日志里写了什么、监控指标有没有变化——这些东西模型权重里生成不出来。拿不到反馈的地方，它只能靠训练分布猜，猜对了是运气，猜错了也不知道。这是一条能算出来的边界：可验证性就是能力边界，下面每一节的收益都不在模型那一侧。&lt;/p&gt;
&lt;h2&gt;生码不再是瓶颈之后&lt;/h2&gt;
&lt;p&gt;先看一个算术问题。假设生码在整个研发链路里占 20% 到 30%，口径是「从需求到上线」里写代码这一段的耗时占比。那么即便把生码这一节加速到趋近于零，端到端的总加速上限也只有 1/(1−p)：p 取 0.2 时是 1.25 倍，p 取 0.3 时是 1.43 倍。&lt;/p&gt;
&lt;p&gt;继续在生码上加码，边际收益已经很低了。剩下七成时间都花在等环境、等联调、等发布窗口、等人工确认上。&lt;/p&gt;
&lt;p&gt;反过来，把等待的那一头做成接口，收益是立刻能看见的。腾讯技术工程那条 SRE 错误码排查线上，一次错误码排查从原来的 3 到 8 小时压到分钟级，口径是告警从产生到给出定位结论的处理时长中位数。&lt;/p&gt;
&lt;p&gt;治理动的是排查过程：那几步原本要人去页面上翻的动作变成了可调用、可返回的接口。治理后这条链路缩短到「分钟级排查加 0.5 到 2 天修复」，日均数百条去重告警里，high 置信度结论占约 90%，失败率约 1%（含重试后仍失败）。&lt;/p&gt;
&lt;p&gt;在 1 小时对 3 周的比例里，模型能力根本不是变量。一次 C 端动线改造的对照更直观：本地改码加验证大约 1 小时，之后跨内部平台发布、联调，再撞上一次 618 封网，上线总共用了 3 周。&lt;/p&gt;
&lt;p&gt;失败的时候先停下来读那次失败，读完再决定要不要重跑。更隐蔽的一种浪费算不进生码占比那个算式，因为它压根没产生代码：一个任务失败了，不诊断就重跑，跑一整个周末，最后把使用额度耗尽，什么都没留下。&lt;/p&gt;
&lt;h2&gt;哪些投入不会随换代归零&lt;/h2&gt;
&lt;p&gt;精细的提示词编排、为绕开模型弱点写的兼容逻辑、手工维护的长篇规则，这三类投入会在下一代模型发布时归零。它们解决的只是「当前模型不够强」这个暂时问题，模型一换代就把它内化掉。我只有一个判据：看这项投入在换代后是获益还是作废，按这条判据，很多当下看起来很硬的工作都落在作废那一侧。&lt;/p&gt;
&lt;p&gt;这些是模型能力的&lt;strong&gt;乘数&lt;/strong&gt;：同一个环境里，模型越强，产出越多。真正会复利的在另一侧——内部系统有没有可调用的接口、程序能不能读部署和日志、测试能不能真实反映线上行为、监控指标能不能定位到具体代码路径。&lt;/p&gt;
&lt;p&gt;| 投入 | 模型换代后 |
| --- | --- |
| 提示词与精细编排 | 被模型内化，归零 |
| 为绕开弱点写的兼容 | 没有意义 |
| 内部系统的可调用接口 | 继续复利 |
| 测试与判据 | 继续复利 |
| 部署、日志、监控的可读性 | 继续复利 |&lt;/p&gt;
&lt;p&gt;判据还有一条资产属性：它会随模型换代升值。套不进去的投入，通常已经站在作废那一侧；用法很简单：把「如果这个模型突然强三倍」套上去，答案立刻就出来了。同一套界面校验流程我动过两次，动的是跑视觉比对用的模型档位。&lt;/p&gt;
&lt;p&gt;写死在某个模型上的提示词没有这个性质，同样的题集和判据，明年会给出更好的结果。两次调档都要求先把角色切干净才敢动档。第一次往下调一档，单轮 token 成本以降档前一档的单价为分母降约 64%，省下来的是钱。第二次往上调一档跑同一批用例，整轮耗时以升档前为分母降约 64%，省下来的是时间。&lt;/p&gt;
&lt;h2&gt;让便宜的信号最先回来&lt;/h2&gt;
&lt;p&gt;研发环境里的每个环节都要做成可调用的接口，页面只是给人看的那一层。每做一个接口，我固定配四样东西：入参出参的结构、不能无限等的超时、最小够用的权限、以及调用留痕的审计。&lt;/p&gt;
&lt;p&gt;四样里超时最要紧，缺任何一样，这个接口在生产上都用不住。Agent 不会自己放弃，只会一直等下去，把整条链路的时间预算耗光，最后以一个看不出原因的结果收场。&lt;/p&gt;
&lt;p&gt;覆盖的顺序我按反馈速度排：构建、单测、类型检查这些秒级返回的先做，集成和契约测试紧随其后，部署状态与日志查询排在后段。监控还要更靠后，因为它返回的是统计值，Agent 直接读容易把一次抖动当成一次回归。完整拆开是三层：&lt;/p&gt;
&lt;p&gt;| 层 | 典型环节 | 挡住什么 |
| --- | --- | --- |
| 秒级 | 编译、格式、类型、单测 | 语法与结构错误 |
| 分钟级 | 集成、契约、浏览器、真实接口数据 | 跨模块与真实环境行为 |
| 人工 | 业务价值、体验、伦理 | 规则判不了的部分 |&lt;/p&gt;
&lt;p&gt;三层不能互相替代。只有秒级检查，Agent 会写出能通过类型检查、却完全走错业务路径的代码；只有人工验收，人的时间会变成唯一的吞吐瓶颈。&lt;/p&gt;
&lt;p&gt;便宜的信号先回来，省的不只是时间。同一个错误在秒级被发现，修复成本是几秒钟；拖到人工验收才发现，修复成本是一次完整的上下文重建——把链路重新组装一遍的时间，往往比改代码本身长一个数量级。&lt;/p&gt;
&lt;p&gt;非功能验证要单独占一格。功能测试回答「能不能用」，非功能验证回答「敢不敢发」。产物校验、性能退化、安全边界这三项，在一次 AI 生成的大改里最容易丢掉——代码看着对，构建产物却是旧的，或者压根没生成。&lt;/p&gt;
&lt;p&gt;安全这一块要左移到生成阶段，提前到评审之前做完。跳过预览直接生成代码、把未验证的改动直接推到主干，这两件事在 AI 提效之后发生频率高了一个量级，因为生成的速度让人失去了逐条看的耐心。浏览器这一块有个额外约束：UI 改动的功能验证必须真的打开浏览器看，光靠单测判不了「页面能不能用」。但截图和 DOM 快照非常占上下文，我的处理方式是按需取、用完即弃，不做成默认采集。&lt;/p&gt;
&lt;h2&gt;跑通了不等于真的能用&lt;/h2&gt;
&lt;p&gt;这一层有个路线上的分歧值得说清楚。规范驱动这条路的问题是规格会过时，写得越细，跟实际系统的偏差越大；做法是先把意图写成详细规格，再让 Agent 照着做。&lt;/p&gt;
&lt;p&gt;规范驱动和环境验证驱动这两条路并行，环境验证驱动这条该优先投入，因为它会复利，规格那条不会。环境与验证驱动只求一件事：让环境能给出真实的判断，不追求把意图写全。规格写三行、环境能验证，就够了；规格写三十页、环境不说话，照样是猜。&lt;/p&gt;
&lt;p&gt;小米零售那条 AI 问数线上有个很能说明问题的对照。早期把指标口径、维度、过滤条件写成详细规范交给模型，「达成率」这类问句的指标选择准确率停在 65% 上下，口径是同一批问句里选对指标的比例。&lt;/p&gt;
&lt;p&gt;同一套知识，写三十页规范不如让它跑一次。规范的正确用法是定义接口，接口的活儿交给能执行的东西。后来把同样的信息做成可执行的取数接口，让模型自己构造查询、自己执行、自己看返回结果对不对，准确率提到接近 98%。&lt;/p&gt;
&lt;p&gt;内部循环是 Agent 自己那一圈：写码、跑测试、看失败、改。内环的目标是速度，不是可信度。&lt;/p&gt;
&lt;p&gt;顺序上有个反直觉的做法值得试：先写测试或先写类型定义，再让 Agent 去实现。先立判据，后要实现，它就没有空间用「差不多对」的东西交差。我自己更常用另一种写法——让它先给出方案，我确认之后再落码，这一步省下的大头是返工。&lt;/p&gt;
&lt;p&gt;把产出直接铺在它面前，省掉人转述这一层，这个习惯值得养成。直接把数据集、文档、配置文件放在它能访问的位置，它会自己检索、自己比对、自己发现矛盾。人做中间层转述，信息在传递中已经损过一遍。&lt;/p&gt;
&lt;p&gt;能力本身也要分层。我按使用频率和风险分四处放：长期稳定的行为约束放进系统提示，可复用的操作流程做成按需加载的能力，单次动作交给工具，而展示形态单独抽出来。分层的意义是把「每次都带着的东西」压到最小，把「偶尔才用的东西」放到检索得到的位置。&lt;/p&gt;
&lt;p&gt;测试由谁写，也值得定清楚。让 Agent 自己写测试，速度快，但它会照着自己的实现写，等于用同一个思路验证同一个思路。我的做法是让它写，人再审一遍断言——重点看断言有没有真的约束住行为，覆盖率那一项排在后面。&lt;/p&gt;
&lt;p&gt;后台执行和并行是内环里最实用的两个开关。长任务丢到后台跑，主线程继续干别的；互不依赖的探查任务并行发起。但要看住输出量——几千行的构建日志原样回灌，会把上下文吃干。我的做法是让命令只输出结论和关键行，不回显全文。&lt;/p&gt;
&lt;p&gt;内环里有个常被忽略的做法：失败立刻修，不要攒着。攒三个失败一起改，等于让它在错误的基础上继续推理三层。&lt;/p&gt;
&lt;p&gt;外环的目标是可信度，它的前提是&lt;strong&gt;不信任内环的结论&lt;/strong&gt;。做法很机械：在一个干净容器里重新克隆、重新构建、重新跑测试，由独立的检查者评审，通过后入库。外环不复用内环的任何中间状态，因为它要验的就是「换一个环境还能不能成」。&lt;/p&gt;
&lt;p&gt;两个环之间有一条硬规则：&lt;strong&gt;只传事实，不传声明&lt;/strong&gt;。内环不能把「我改好了」传过来，只能把「改了哪些文件、跑过哪些命令、结果是什么」传过去。声明可以错，事实不会错。落到实践里就是一句话：把复现路径写清楚，让每个接手的人照着跑一遍，不用别人转述「我验证过了」。&lt;/p&gt;
&lt;p&gt;失败必须有名字，这是另一条硬要求。合并失败、推送失败、冲突失败是三种不同的失败，需要的处理完全不同。把它们都记成「失败」，重启流程时会从错误的分支开始。&lt;/p&gt;
&lt;p&gt;交付链路上新出现两个旧流程里没有的角色，它们都不需要人在场。一个跑在后台执行：由事件触发，产出直接进代码库或工单；另一个嵌在持续集成里：读失败日志、定位到具体改动、给出候选修复。这两个角色撞上的失败，程序必须能读出来，人不用去翻日志。&lt;/p&gt;
&lt;p&gt;跑得起来却没人用，是发布分层要拦住的那种失败。我给发布划了四段：可预览的内部版本、内部真实用一段时间、放给愿意尝鲜的外部用户、全面放开。让一个改动跑起来，和让它真正进入使用，这两件事的失败方式完全不同：跑不起来一眼看得见。&lt;/p&gt;
&lt;p&gt;不分四段发布，平均成功率会盖住降级率这个数，直到全面放开那天才一起爆出来。分层的价值还有一个更硬的读数：降级率。降级只是让整体成功率好看一点，不算失败。阿里全球化商品中心那条智能答疑 Agent，把感知层当成独立指标来测——用户的问题超出所有 Skill 处理范围时，Agent 有没有触发知识库检索兜底。&lt;/p&gt;
&lt;p&gt;| 阶段 | 谁在用 | 这一阶段主要在找什么 |
| --- | --- | --- |
| 预览 | 开发者自己 | 功能是否跑通 |
| 内部使用 | 团队内部 | 真实工作流里会不会卡住 |
| 小范围外部 | 愿意尝鲜的用户 | 边界场景与预期落差 |
| 全面放开 | 全部用户 | 稳定性与成本 |&lt;/p&gt;
&lt;p&gt;错误码本身就是常被漏掉的一种事实来源。一次调用失败，返回体里往往已经写明了是排队、限频还是参数错，只是没有人把它提取成结构。把这些分类做成可读的字段再交给 Agent，它就不用靠猜去重试。系统里已经有的信息，不需要模型去推断。&lt;/p&gt;
&lt;h2&gt;该由框架拿走一整类错误&lt;/h2&gt;
&lt;p&gt;把规则下沉到框架层的时候，判据只有一条：&lt;strong&gt;这是事实还是代理指标？&lt;/strong&gt; 禁止读取某个路径是事实，可以硬拦截；「编辑之前必须读过规范」只是代理指标，只能做提醒，不能做拦截。读过不等于遵守，这一点在模型身上和人身上一样。&lt;/p&gt;
&lt;p&gt;误报还会反向逼出更差的实现。我见过为了满足「读过规范」这个提醒，Agent 去读一遍文件就立刻关掉——形式合规，实质没变。把代理指标当事实用，拿到的就是这个。&lt;/p&gt;
&lt;p&gt;顺着这条判据往下走，可以消掉一整类错误：有些错误不该靠 Agent 记住，该让框架直接拿走。凡是在框架层能被确定性消掉的判断，都不该以规则的形式挂在 Agent 的上下文里。&lt;/p&gt;
&lt;p&gt;声明式 Mock 是最能说明问题的一个例子。传统写法要求开发者在测试里显式清理状态，漏掉清理是我观察到的一类高频错误。同样高频的还有把测试数据伪造得过于规整、把真实边界掩盖掉。漏清理这一类问题，在改成声明式声明加自动还原之后从结构上消失了，Agent 不需要记任何规则；测试数据伪造得过整是另一类，只能靠断言自己守住。&lt;/p&gt;
&lt;p&gt;排超时这类问题，框架层也能直接拿走。以前排查一次调用超时，要在日志里人工判断是排队、限频还是根本没回包；现在直接把分类结果、对应的处置动作和代码路径一起返回给 Agent，一次就定位了。声明式 Mock 和超时分类这两个例子指向同一件事：错误的结构信息已经存在于系统里，只是散在各处没人提取。框架层要做的不是约束 Agent，是把这些信息交给它。&lt;/p&gt;
&lt;h2&gt;题集和判据才是验收核心&lt;/h2&gt;
&lt;p&gt;这里有一组对照，口径是同一个人负责的 7 个服务、统计窗口 3 个月：1800+ 次提交，覆盖生产代码、测试代码和前端三类改动。产出规模是够大的，同期事故并没有同比例下降。&lt;/p&gt;
&lt;p&gt;原因是一个乘法关系：单次错误率 × 产出规模 = 事故数量。单次错误率降到一半，产出规模涨到十倍，事故是原来的五倍。低错误率乘以高产出，不等于安全。&lt;/p&gt;
&lt;p&gt;人工审查抓不到两种失效。一种是编码损坏：中文文档里成片出现乱码替换字符，逐行看代码完全看不出来。另一种是空覆盖：覆盖率数字在涨，但有人把断言写松了，实际什么都没验证。这两种都得靠机器查，人眼扫一遍是扫不出来的。&lt;/p&gt;
&lt;p&gt;产出规模本身也会制造新的失效。我见过一次：让模型写三份分析文档，它干了两周多，交回一份只有长度没有内容的报告，篇幅是够了，一半内容在重复同一件事。换成把任务拆成几个可验证的单元、每个单元单独验收，一周就做完了。大产出带来的满足感会掩盖一件事——没有人定义过什么叫做完。&lt;/p&gt;
&lt;p&gt;判据缺失才是质量侧更常见的失效：输出越来越长、往代码里塞无关符号和表情、评审里漏掉的严重问题。一批评审意见里，最要紧的几条始终没有人处理。这几样都出在判据上，缺的正是判据：没有人定义「什么叫做完了」，于是「跑通了」就成了终点。&lt;/p&gt;
&lt;p&gt;规模上来之后，回答「测试到底能不能发现 bug」的不再是更多的测试，而是题集和判据。一个只堆平台工程量、不动题集判据的项目做了 107 天，改动量与前面那组 7 个服务的对照相当，整条链路只留下两次可复现的跑数。同期一个轻量做法只做了 16 组配置对比，每组跑一遍关键子集，直接改写了检索策略。&lt;/p&gt;
&lt;p&gt;后来换成 16 道题各跑 3 遍，48 次完整跑合计约 19 小时机时，单次约 24 分钟（19×60÷48≈24）。184 个变异体里 12 个是等价变异体，改动不改变语义，永远杀不掉，不进分母；剩下 172 个里杀死 105 个，105÷172≈61%。&lt;/p&gt;
&lt;p&gt;宏平均变异击杀率也是约 61%，口径是先算每题击杀率再取平均，跟 105÷172 这个合计比互为印证。两个数字用的是同一批跑数，只是聚合方式不同。&lt;/p&gt;
&lt;p&gt;变异算子全部取自真实评审里见过的失效模式：比较符翻转、and 与 or 互换、删掉兜底的 &lt;code&gt;or 0&lt;/code&gt;、把状态写入注释掉。判据也换了：只有测试真的失败，才算杀死一个变异体，跑通不算。这条判据把「看起来在测」和「真的在测」区分开了。&lt;/p&gt;
&lt;p&gt;变异体也不是一次性定案。三级验证跑下来：模型初审先剔掉明显等价的那些，测试执行定生死，人工只复核两边结论不一致的，终裁以人工那层为准。等价变异最后落两条价值判断——日志差异不算可观测，可杀性以自然构造为准。&lt;/p&gt;
&lt;p&gt;回到开头那个问题。Agent 能接管哪一段，看环境里有多少是真的、可读的、可调用的。缺一样，它就退回猜。&lt;/p&gt;
&lt;p&gt;可验证性落在自己这一侧，好处是边界不在别人手里。每多做一个带 schema 和超时的接口，每多写一条能杀死变异体的判据，边界就往外推一点。按开头那条判据，这些都落在获益一侧，不会因为模型换代而作废。&lt;/p&gt;
&lt;p&gt;判据齐了只是把边界画出来，能把手放出去多少还看另一件事：这次动作能不能撤销。改一行代码能回滚，发一条消息不能。&lt;/p&gt;
&lt;p&gt;落点很具体：写失败的测试让它改到通过，把描述换成能直接跑的脚本，把证据铺在它面前让它自己检索验证，把复现路径写清楚让人照着跑一遍。让环境先有判断，再让模型动手。&lt;/p&gt;</content:encoded></item><item><title>给上下文定预算：Multi-Agent 的钱到底花在哪</title><link>https://your_domain/blog/20260818-context-budget-multiagent-cost</link><guid isPermaLink="true">https://your_domain/blog/20260818-context-budget-multiagent-cost</guid><description>多 Agent 拆分不天然省钱——并行意味着多份常驻上下文和初始化开销。真正把账单顶上去的是三类东西：常驻上下文、重复打包的历史，以及每次工具调用要付的四份固定开销。</description><pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;讨论 Multi-Agent 贵不贵的时候，最容易被忽略的一件事是：拆分本身不省钱。多个 Agent 并行，就意味着多份系统提示词、多份初始化上下文和多份工具清单。把任务拆得越细，账单也跟着复制一份。&lt;/p&gt;
&lt;p&gt;把该显式化的知识显式出来同样要付费，它长期占着上下文，越是当成常识写进提示词的东西，每一轮都要反复付费。这篇算的就是这笔账。&lt;/p&gt;
&lt;p&gt;我的主张是&lt;strong&gt;先给上下文定预算，再决定怎么拆&lt;/strong&gt;。预算不到位的并行，只是把一条贵链路拆成几条同样贵的链路。拆分、摘要化、脚本化这三条我真正用过的路径，我会分别写清每一条省的是哪一块 token，以及这个数是在什么口径下算出来的。&lt;/p&gt;
&lt;h2&gt;没看账单就动手，是最顺手的错&lt;/h2&gt;
&lt;p&gt;成本优化最容易走岔的地方，是直接跳过账单挑熟悉的手段：换个便宜模型、压一压提示词、少跑两轮。挑手段顺手，看账单要先做基建，所以大多数人会跳过这一步。&lt;/p&gt;
&lt;p&gt;我记账时按调用链把一段任务拆开：链路自上而下分成任务层、并行批次层、子 Agent 层、工具层。每层再按输入 token、输出 token、缓存命中、轮次分开计。不拆到这一层，看到的只有一个总数，而总数会骗人：输入降了输出可能没降，某一轮特别贵、摊平了完全看不出来。&lt;/p&gt;
&lt;p&gt;六处来源里，最便宜的是用户自己输入的那一句，大头是工具定义、原始返回和滚雪球一样的历史。按来源分，token 大致落在六处：系统提示词、工具返回、文件内容、长期记忆、历史消息、用户输入。这六处的价钱差别很大，摊到几十轮上，比用户那句话贵几个数量级。不清是谁在花钱，优化就会挑最显眼的那个下手，最贵的那个反而没人管。&lt;/p&gt;
&lt;p&gt;换便宜模型算不算止损，要看总账。主力模型换成便宜一档，账算下来往往更贵：一次贵调用变成多次便宜调用，轮次翻倍，总数跟着上去。&lt;/p&gt;
&lt;p&gt;缓存命中率要单独拎出来看，它是整张账单里最容易被忽略的一项。命中率掉了，先看前缀里有没有东西在漂：时间戳、随机 ID、每次顺序不同的工具清单，都会让前面的稳定段失效。&lt;/p&gt;
&lt;p&gt;前缀怎么排是有讲究的：把全局稳定、会话稳定、易变三段依次排好，稳定段全量命中，易变段每次都在变。次序定死之后，命中率只剩一个变量——易变段有多长。&lt;/p&gt;
&lt;p&gt;缓存读取只收大约一成的价格，这一项因此值得单独拎出来算一遍。前提是这一段前缀跟上一次请求逐字一致，完全一致才复用上次的 KV 矩阵，差一个字符这一段就得按原价重算。算这一项的账时，命中的那部分按一折算，没命中的按原价折算，别拿一个命中率数字直接当总账。&lt;/p&gt;
&lt;h2&gt;拆分不会天然省钱&lt;/h2&gt;
&lt;p&gt;一个反直觉的事实是：把任务拆给多个 Agent，很多时候比一个 Agent 从头做到尾更贵。原因是每个子 Agent 都要重新付一遍启动成本——系统提示词、角色定义、工具清单、记忆加载，这些跟任务难不难无关，跟开了几个头有关。六个 Agent 并行跑，等于同时有六份系统提示词在计费。&lt;/p&gt;
&lt;p&gt;所以分流要有依据。我按任务体量分成小、中、大三档：小任务单 Agent 直做，省掉的就是那份重复的启动成本；中等任务才拆，取的是并行带来的隔离收益。大任务必须拆，因为单条历史会滚到装不下，装不下就跑不完，这一关排在钱的前面。&lt;/p&gt;
&lt;p&gt;想知道该不该拆，去算两笔账：&lt;strong&gt;并行省下的时间乘以单次成本&lt;/strong&gt;，对比&lt;strong&gt;多出来的启动成本乘以并行度&lt;/strong&gt;。这个算式不复杂，但它要求你先知道一份启动成本是多少，而这一步恰恰是大多数人没做的。&lt;/p&gt;
&lt;p&gt;并行度有个够用的上限，往上加未必划算。子 Agent 开多了，协调它们本身要消耗轮次，而协调用的上下文同样是钱。判断并行度该停在哪，看并发再往上加之后单任务成本还往下不往下，跑到第几个子 Agent 只是这个判据的结果。这一条口径要先说死：同一任务重复跑多次，取单轮成本的中位数，均值会被一次偶发的高开销带偏。&lt;/p&gt;
&lt;p&gt;主 Agent 端到端 token 从 708,783 降到 315,266，降幅 55.5%，口径是主 Agent 的端到端总量。同一条链路上的轮次从 17 降到 9，降幅 47%。&lt;/p&gt;
&lt;p&gt;账单里还有一项极易算漏：子 Agent 单轮的固定开销。改造前单个子 Agent 起跑那一轮常驻几十万 token，改造后单次少掉约 20,000 token，口径是同一角色子 Agent 起跑轮次的常驻 token 差值。轮次砍掉近一半之后，这份固定开销要在两个地方各算一遍——开得少，每一份也薄。&lt;/p&gt;
&lt;p&gt;该不该拆开，我只看两个子任务之间要不要交换大段内容：要交换的该放一起，我按领域拆而不用步骤拆。按步骤拆出来的子 Agent 往往要共享同一段历史，历史跟着复制一份；按领域拆则各自持有自己的上下文，重复的部分少。&lt;/p&gt;
&lt;h2&gt;三样东西把账单顶上去&lt;/h2&gt;
&lt;p&gt;按我拆出来的账，把账单顶上去的是三类东西：常驻上下文、每轮重复打包的历史、每次工具调用的四份固定开销。这三类跟模型贵不贵关系不大，改的是组织方式。&lt;/p&gt;
&lt;p&gt;三类里最难压的是第三类。前两类改的是上下文怎么组织，组织方式一变，后面每一轮都跟着变便宜；第三类只由工具清单和调用次数决定，跟组织方式没有关系，能靠单点优化解决的只有前两类。分不清这三类，优化动作就会全打在同一处。&lt;/p&gt;
&lt;p&gt;| 成本项 | 谁把它拉高 | 典型症状 |
| --- | --- | --- |
| 常驻上下文 | 系统提示词、工具清单、全量加载的记忆 | 从开跑那一刻就贵，之后每一轮都带着它 |
| 历史消息 | 滚雪球式累积、每轮完整重打包 | 越到后面越贵，跟任务难度无关 |
| 工具调用 | Schema、决策轮次、返回结果、下一轮上下文 | 单次最贵，且随调用次数线性增长 |&lt;/p&gt;
&lt;p&gt;工具调用这一项要单独解释一下。一次调用其实要付四份钱——工具定义本身占的 token、决定要不要调用的那轮推理、返回的结果，以及结果塞进下一轮的上下文。前三份是一次性的，第四份会一直跟着往下滚。所以「删掉不用的工具」和「压缩工具返回」看似两件小事，差出来的是一整档成本。&lt;/p&gt;
&lt;p&gt;压历史的办法要往摘要上找，截断只会丢掉中间的约束，约束一丢，模型在后面会重新犯一遍已经纠过的错。我按层摘要：每过若干轮把那段已经完成的对话压成一段要点，要点里只留结论、约束和待办，丢掉过程，再配一个检查点接上，省掉从头重放那一步。&lt;/p&gt;
&lt;p&gt;历史这一项有个特点值得记住：它的增长跟任务难度无关，只跟轮次有关。同一个任务，模型更聪明、轮次更少，历史反而更便宜。这就是为什么「换更贵的模型」在某些任务上总成本会下降——它压缩的是轮次，而轮次才是历史的乘数。&lt;/p&gt;
&lt;p&gt;轮次上限是轮次这一项里最省钱的配置，写出来只一行，省下的是一整档。轮次这一项能贵到什么程度，看一个极端样本就够：有个 Agent 拿着一件本该很快收工的事一直空转下去，每一轮都要把历史重新打包一遍，直到人出手才停。模型够用，缺的是有人给它写一条停止条件。轮次上限因此不该被当成安全护栏，少写这一行，账单就往上翻一整档，零头谈不上。&lt;/p&gt;
&lt;p&gt;工具清单既是成本项，也是安全边界，算账时这一点常常没人算进去。角色专属的工具白名单是一举两得的做法——一个只做数据分析的 Agent，不需要看到写库和删除的接口。&lt;/p&gt;
&lt;p&gt;把工具数砍半，省掉的就是每轮都要付一遍的 Schema 成本。一个挂了 40 个工具的 MCP Server，光工具定义每轮约 10 到 15KB，砍半就是每轮省下 5 到 7KB，顺带的好处是模型不会误调用它本来不该碰的东西。降本和安全在这里是同一个动作，也是这套做法值得优先做的原因——它不用先做测量就能开始。&lt;/p&gt;
&lt;p&gt;工具描述本身也占 token，而且每一轮都带着。写工具说明我只按「够用来决定要不要调用」这个标准控长度，详细参数语义放到按需加载那一层。一份几十个工具的清单，说明每段多写一行，这一轮就多付一行的钱，乘上整条链路的轮次不是小数目。&lt;/p&gt;
&lt;p&gt;选模型要先定线再挑模型，顺序反了就在质量和延迟上反复返工。我的做法是先定质量下限、p50 与 p99 延迟、单次成本预算三条线，再拿生产查询的分布去扫模型和推理档位，三条线同时过线才入选。&lt;/p&gt;
&lt;p&gt;换模型我只在这种情况下做：把规则性强、轮次又多的子 Agent 换成单价更低的一档。自动化测试、视觉还原对比这两个角色就是这么处理的，替换之后它们的模型成本降了约 64%，口径是同一工作流下替换前后的模型成本，省下的幅度随修复轮次倍增。前提是先把角色切干净：只有当某个 Agent 的职责足够窄，判断用不上来回翻上下文，才敢给它配便宜模型。&lt;/p&gt;
&lt;p&gt;高德那条经营分析线上也有一组可对照的量级，它量的东西跟 token 不一样，是引用来源条数和最大引用深度。同样是只改上下文的组织方式，这一组也能压下来。&lt;/p&gt;
&lt;p&gt;高德本地生活分析 Agent 的批量交付里，来源从 731 条收敛到 179 条，口径是一次返修实际携带的引用来源条数，从改动之前的全部来源，收敛到改动范围内的引用来源。同时把共享引用压平，最大引用深度从 13 层降到 4 层，指的是一条引用最多还能往下追几层。&lt;/p&gt;
&lt;p&gt;两项压下去之后，批量效率约为人工的 22 倍，这个倍数是折算出来的。一轮全行业报告的产出时间压进了 1 小时，人工侧按每个业务单元约 1 小时、一轮约 22 个业务单元折算，等于 22 人时，分母是人工单单元时长乘单元数。&lt;/p&gt;
&lt;p&gt;常驻上下文那一栏乘在轮次上，压它比压单轮那一块划算，来源收敛靠的正是这一条。省掉的是每一轮都要重复携带的那部分材料，摊到几十轮上不是小数目。&lt;/p&gt;
&lt;p&gt;| 优化动作 | 它省的是哪一块 |
| --- | --- |
| 渐进式披露 | 常驻上下文 |
| 子 Agent 摘要化 | 后续轮次的重复计费 |
| 代码图谱先行 | 盲搜带来的反复重打包 |
| 确定性操作脚本化 | 推理轮次与串行时间 |
| 工具白名单与模型分层 | Schema 成本与模型单价 |
| 无依赖调用并行 | 历史重复打包与等待 |&lt;/p&gt;
&lt;h2&gt;上下文要先有预算，才有加载策略&lt;/h2&gt;
&lt;p&gt;知道贵在哪之后，加载策略可以定得很机械：&lt;strong&gt;任何东西进上下文，都要先有预算，再看它有没有用。&lt;/strong&gt; 渐进式披露是这条原则的直接推论：安装二十个 Skill，不等于初始化的时候把二十份正文都读完。&lt;/p&gt;
&lt;p&gt;落到具体写法就是：能力正文只留骨架——触发条件、输入输出、关键约束；规则模板、示例和长篇说明放进按需加载的那一层。骨架短了，常驻成本就低，细节还在，需要的时候能取到。&lt;/p&gt;
&lt;p&gt;发现层、入口层、执行资源层要分开。初始化只加载能标识「我有什么能力」的那层元数据，正文和规则压到真要用某个 Skill 时才进来。Skill 的个数因此不再和启动成本绑定，这是我后来把 Skill 拆得越来越细的底气。&lt;/p&gt;
&lt;p&gt;预算必须写成数字，否则等于没定。我给 Skill 这一类定的额度是：装 20 个 Skill，初始化那一次只放进来 1000 到 2000 token，约为单体式提示词的一到两成，比全量常驻少约 90%。这个数留的是可算的余地，它让「这一次初始化有多重」随时能算出来，算得出来才知道还能往里放什么。&lt;/p&gt;
&lt;p&gt;一条规则在多少个任务里用得上，是决定它进不进正文的唯一标准。用得少的写进正文，代价是它在每个任务里都要被加载一次。规则越多、越只适用于少数任务，这一笔浪费越明显。&lt;/p&gt;
&lt;p&gt;长期记忆按同一套逻辑走，只是多一层。先读几十行的 INDEX——标题、标签、摘要——再按相关度取命中条目里最靠前的几篇读正文，原始证据不进上下文，需要时按路径单独取。这样走下来，记忆的价钱跟文档总数脱钩，跟回源路径本身挂钩。&lt;/p&gt;
&lt;p&gt;SQL 场景里那组数字挺能说明问题：候选的表结构与取值样例合计约 3 万行，实际进上下文的是按相关度排在前 200 到 400 行的切片。选得准不准比模型强不强更决定结果，全塞进去注意力就摊薄了，结果反而更差。&lt;/p&gt;
&lt;h2&gt;大 payload 不要待在最长的生命周期里&lt;/h2&gt;
&lt;p&gt;另一类成本来自 payload 的生命周期错配。一个大体积的返回值不该落在生命周期最长的一层，那层是主 Agent 的历史，后面几十轮都要为它重复付费，错位的代价一路滚下去。&lt;/p&gt;
&lt;p&gt;处理办法是给取数类操作配短生命周期的子 Agent，让它在自己那一层里消化原始 payload，只把结构化摘要交回上层。我手上有一条可参照的对照：某个拉取外部系统数据的链路，优化前单轮输入 1,030,000 token，优化后 634,905 token，降幅 38.4%。&lt;/p&gt;
&lt;p&gt;1,030,000 是常态，它来自把需求描述、设计稿节点树这些原始 payload 全程留在主 Agent 上下文里。换成短生命周期子 Agent 消化之后，这一轮只剩几万 token。口径也要说清：首次调用两种方式花的基本一样，38.4% 全部来自后续轮次不再携带原始 payload。&lt;/p&gt;
&lt;p&gt;摘要会压缩掉事实，所以配套一条硬规则：摘要必须带上原始证据的访问路径。省下来的是常驻成本，丢掉的东西要能按路径取回来。丢关键事实的摘要比不摘要更贵，它会用一次返工把省下的钱全还回去；同一份信息在最上游收集一次、通过文档传给下游，也比让每个 Agent 各自重新取一遍便宜。&lt;/p&gt;
&lt;p&gt;判断一个 payload 该不该摘要，我只看一件事：它后面还要用上几次。只用来判断「有没有数据」的返回值，摘要成一句结论就够；后面还要逐条处理的，反而要付两次钱，一次压缩，一次重新取。这类内容整体外置、按需取，是最省的一档。&lt;/p&gt;
&lt;p&gt;稳定前缀解决的是每轮开头都一样的那一段。进度同样不该留在上下文里：主 Agent 每轮先去读进度文件，不回放历史，阶段切换只输出一行状态；会话中断之后能直接读文件恢复现场。&lt;/p&gt;
&lt;h2&gt;能被脚本拿走的，别让它占推理轮次&lt;/h2&gt;
&lt;p&gt;有一类钱花得非常不值：让 Agent 干脚本早就能干的活。判据只有一条：这段活是确定性的，还是需要判断。迁移、编译、批量重命名、跑测试，这些写成脚本的执行成本和正确性都远好过让模型一轮轮地按步骤做。&lt;/p&gt;
&lt;p&gt;确定性操作脚本化还有一个隐藏收益：它把「做没做对」变成可验证的。脚本的退出码是一个硬信号，模型自己一步步做，做完之后没人知道它到底做全了没有。把这一类动作移出模型，等于同时买到成本、速度和确定性。&lt;/p&gt;
&lt;p&gt;代码检索是这一类的典型。让 Agent 在仓库里盲搜，代价是反复读取和反复重打包；换成先用代码图谱锁定文件范围再读那几行，一次到位。&lt;/p&gt;
&lt;p&gt;我量过一次同任务的前后对照。总 token 从 875,352 降到 676,987，降幅 22.7%，口径是同一任务改造前后的总量；输入侧从 868,544 降到 670,281，降 22.8%，口径相同。缓存命中那一段从 820,175 降到 609,903，未命中反而从 48,369 升到 60,378，命中率从 94.4% 掉到 91.0%。输出基本不动，这一点说明省下的钱来自路径，少走的正是那一段没必要的检索路径。&lt;/p&gt;
&lt;p&gt;并行是整条链路上最便宜的一条。没有依赖关系的工具调用放进同一轮执行，它降低的不只是等待时间，更主要的是历史重复打包的次数。判断依赖的办法是问「后面的调用要不要用前面的输出」，流程习惯只能当参考，很多看起来有先后关系的调用其实只是习惯。&lt;/p&gt;
&lt;p&gt;脚本化还有个副作用要提前防：脚本的输出往往比模型需要的大得多。我的习惯是让脚本默认只回结论和失败明细，成功时静默。这一条改动很小，但在调用频繁的链路上，省下来的量级跟换模型差不多。&lt;/p&gt;
&lt;p&gt;命令行输出也要压。进程列表、仓库状态、测试回显原样丢回去极占上下文，压过再给模型能省一整块。我实测的两个点：进程列表压缩掉约 98.9%，仓库状态压缩掉约 31%，口径都是压缩后的字符数除以压缩前的字符数。命令之间差异极大，按各自实测值分别记账，别信统一数字。&lt;/p&gt;
&lt;p&gt;上下文里只留判断要用的那一部分，其他都外置到文件，这是最便宜的一档优化。大段中间产物、检索到的原始片段、过程中的日志，都写成文件留个路径，需要时再取。&lt;/p&gt;
&lt;p&gt;| 数字 | 口径 | 能用来做什么 |
| --- | --- | --- |
| 单轮输入降 38.4% | 同一条取数链路改造前后的一轮 | 判断该不该做摘要化 |
| 总 token 降 22.7% | 同一任务、同一版本的前后对比 | 判断该不该上代码图谱 |
| 整体降 50% 到 65% | 分项降幅代入批次消耗分布反推 | 排优先级 |&lt;/p&gt;
&lt;p&gt;所以我的习惯是：降幅先分证据等级，再决定它能被用来做什么。单点明确的对照可以直接拍板，前后时间的对比用来看趋势，反推估算只用来排优先级。&lt;/p&gt;
&lt;p&gt;预算定住之后，真正卡住生产的是谁来判定这次做对了没有，构建过没过、测试过没过，那是环境与验证要解决的。成本数字要带着口径才比得出结果：工具栈、任务分布、模型档位都不一样，跨团队对比没有意义。能迁移的只有那句判断——先定预算，再谈加载。预算立住之后，常驻上下文、历史重打包、工具 Schema 这三处的裁法就都有依据了。&lt;/p&gt;</content:encoded></item><item><title>代码不是真相：给 Agent 补上仓库里没有的几层</title><link>https://your_domain/blog/20260811-code-is-not-the-truth</link><guid isPermaLink="true">https://your_domain/blog/20260811-code-is-not-the-truth</guid><description>Agent 读得懂每个函数，却判断不了这次改动会影响谁。缺的不是代码注释，而是业务语义、隐式约定、运行时事实和历史决策——它们不在仓库里，也不该被塞进一个大而全的知识库。</description><pubDate>Tue, 11 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;真正决定这次改动能不能做的那些知识，大多不在代码里。一个 Agent 可以把仓库里的每个函数都读明白，仍然会做出一次错误的改动。&lt;/p&gt;
&lt;p&gt;我现在的判断是：&lt;strong&gt;代码只是水面上的那一层，显式化出来的知识才是资产，代码不是真相&lt;/strong&gt;。这部分知识没有别的补齐办法，只能把团队脑子里的东西显式化。停在「代码写得清楚一点」这种层面是不够的，它只能解决能不能读懂局部代码，解决不了在复杂系统里做出正确的工程判断。&lt;/p&gt;
&lt;p&gt;显式化要占上下文，这笔账得单独算：这些知识在一次任务里到底占多少、预算该怎么切。每多写一条约束、每多落一块知识，就要多占一点模型读到的上下文。&lt;/p&gt;
&lt;h2&gt;读得懂代码，不等于知道能不能改&lt;/h2&gt;
&lt;p&gt;举个具体的例子。模型知道 &lt;code&gt;refund&lt;/code&gt; 是退款，却不知道在这个团队里，退款到底牵扯订单状态、支付单状态、履约状态、财务对账、客服工单还是风控策略。这类信息是这个团队对业务的定义，注释补不上它。&lt;/p&gt;
&lt;p&gt;难处是这些东西压根没地方落，注释写得再多也装不下它。把缺的东西摊开，就是这几类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;业务语义&lt;/strong&gt;：这个概念在本团队里到底涵盖哪些环节，边界画在哪。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;隐式约定&lt;/strong&gt;：某个看起来没人用的字段，其实是离线任务每天凌晨要扫的；某个消费分支不能删，因为还有历史服务在消费老格式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运行时事实&lt;/strong&gt;：超时、重试、熔断降级、限流、灰度策略、告警口径，以及出事之后该找谁。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;历史决策&lt;/strong&gt;：为什么留着这层兼容，为什么当年选了这个方案，哪些是业务妥协而不是技术最优。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;约束与规范&lt;/strong&gt;：哪些字段只能新增不能改语义，哪些状态流转必须审批，核心链路上不许新增强依赖。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这几类东西有个共同点：它们都是从代码里推不出来的。业务语义是团队定义的，隐式约定是历史留下的，运行时事实在线上配置里，历史决策只存在于当事人脑子里，约束来自事故与合规。指望模型读代码读出来，等于指望它在没有输入的情况下输出结果。&lt;/p&gt;
&lt;p&gt;Agent 没有组织记忆，它只能读取你明确给它的东西，这一条是整个问题的根。人类工程师正是靠长期经验、团队沟通和事故记忆把这些补全的。&lt;/p&gt;
&lt;p&gt;补哪些、不补哪些得有判据，不然缺口清单会把人淹掉。我的认定条件得同时成立：属于应该被覆盖的领域，当前版本确实没有覆盖，现有的引用里找不到有效答案，并且能指到一个明确的落点（文档 / 校验脚本 / 测试 / 接口）。只满足一两条的先放着，它们多半是长尾，还凑不成一条缺口。&lt;/p&gt;
&lt;p&gt;这笔账得先算清楚：&lt;strong&gt;技术方案一旦错了，后面所有高效执行都会变成高效返工&lt;/strong&gt;。模型生成代码越快，越会把一个错误的方案执行到底，这正是显式化要排在前面的原因。&lt;/p&gt;
&lt;h2&gt;知识不是越全越好，是角色不同&lt;/h2&gt;
&lt;p&gt;不同问题对应不同的知识形态。一个库想装下所有问题的答案，等于放弃了按问题挑形态的机会；面对这个缺口，最自然的反应是建一个大而全的知识库，我不认同这个做法。把它们倒进同一个库里，每类知识都以最不适合它的方式存在：事实该自动更新却靠人维护，约束该人工确认却被机器生成，验证规则该逐条可执行却写成散文。&lt;/p&gt;
&lt;p&gt;更麻烦的是另一层风险：&lt;strong&gt;知识库会退化成一份看起来完整、实际上过期的文档，而 Agent 最怕的不是没有上下文，是拿到了错误的上下文&lt;/strong&gt;。没有上下文它会停下来问，拿到错误上下文它会信心十足地往错的方向走。一份结构完整、方向错误的方案，比起没有方案更容易制造返工。&lt;/p&gt;
&lt;p&gt;大而全的知识库会以最快速度同时犯上这几样，坏法都跟「全」有关：过期、冲突、不可执行。过期是内容没跟上系统变化，冲突是同一个事实在两处写法不同让模型只能随机挑一个，不可执行是写成了描述性文字、机器没法据此做判断。&lt;/p&gt;
&lt;p&gt;我按角色把知识分成四类，各自独立，各自过期之后的症状完全不一样：&lt;/p&gt;
&lt;p&gt;| 角色 | 回答什么问题 | 过期之后的症状 |
| --- | --- | --- |
| 事实 | 系统现在长什么样 | 改动落到一个早就下线的依赖上 |
| 映射 | 这次需求落在哪条链路上 | 跨系统需求被当成单服务改动 |
| 约束 | 什么不能改、为什么不能 | 代码能跑，但违反了不能改语义的规矩 |
| 验证 | 怎么证明这次改动是安全的 | 跑几个单测就报完成 |&lt;/p&gt;
&lt;p&gt;这张表里缺掉一类，其余几类的价值都会大打折扣。这张表同时也是工作的顺序：知道系统事实才知道怎么改，知道映射才知道动哪条链路，知道约束才知道不能怎么改，知道验证方式才知道怎么证明安全。&lt;/p&gt;
&lt;p&gt;按角色切知识决定它以什么形态存在，按认知半径切视野决定一次任务读多大范围。两把尺子各管一件事，混用的结果是一层里塞进形态完全不同的知识，治理方式也就跟着打架。&lt;/p&gt;
&lt;h2&gt;认知半径要分层，链路要钉到链路上&lt;/h2&gt;
&lt;p&gt;纵向再切一刀，按认知半径分成四层。之所以叫认知半径，是因为每一层决定了 Agent 应该把视野放到多大。回答「为什么改」的时候不需要知道某个服务的目录结构，回答「这个服务内部怎么改才安全」的时候也不需要读全公司的架构图。&lt;/p&gt;
&lt;p&gt;| 层 | 回答什么问题 | 形态 | 更新方式 |
| --- | --- | --- | --- |
| 业务层 | 为什么改，这次业务落在哪 | 按概念、场景、链路组织的文档 | 以人写为主，分领域各自维护 |
| 架构层 | 系统之间怎么协作 | 服务级知识加调用边 | 从服务治理信息自动生成 |
| 系统层 | 这个服务内部怎么改才安全 | 目录级结构化描述 | 工具生成，人工确认关键点 |
| 基建层 | 底座规则是什么 | 团队级规范条目 | 低频变更，集中维护 |&lt;/p&gt;
&lt;p&gt;混在一起的结果通常是两头不讨好，分层的收益是能分别治理。业务层允许主观、允许写得散，因为它的读者需要理解背景；系统层必须结构化、必须可执行，因为它是要给 Agent 读的。&lt;/p&gt;
&lt;p&gt;业务层的一份文档我按五段组织：元信息与归属、这个领域的原则、典型场景、可复用实践、历史变更。实践和历史必须分开，历史是推导过程，实践是当下结论，混在一起之后没人敢改，也就没人再维护。业务层真正值钱的是从场景一路落到消息的那条映射链。这里面还有一条要单独回答的问题：这条知识有没有经过确认、能不能直接拿去让 Agent 动手。&lt;/p&gt;
&lt;p&gt;系统层要按机器能读的方式组织：这个服务是干什么的、有哪些核心对象、对外接口是什么、依赖哪些下游。跑在什么基础设施上、主流程怎么走、怎么验证、有哪些硬约束，这几样也得写清，缺任何一样 Agent 在这个服务里改代码就是盲改。服务还得声明自己不负责什么，否则 Agent 会把没归口的部分也当成可以改的。&lt;/p&gt;
&lt;p&gt;粒度上有个容易被忽略的判断：业务层要按概念、场景、链路组织，按服务切会把跨服务链路切碎。按链路组织，一次改动影响哪几个服务是看得见的。&lt;/p&gt;
&lt;p&gt;基建层看起来最不起眼，却是最该先写的一层：键的命名、慢查询阈值、发布流程、回滚策略，这些规则变化极慢，写一次能吃很久，而且它们天然是结构化的。把这一层做扎实，性价比高过上面任何一层。&lt;/p&gt;
&lt;p&gt;架构层的做法是把跨服务关系收进一份可查的入口：谁调我、我调谁、走什么协议、哪个接口、超时多久。先挑链路清晰的服务做知识化治理，剩下的靠持续补。做出来之前，改一个接口要在群里问一圈；做出来之后，影响分析不再完全依赖人肉问同事。&lt;/p&gt;
&lt;p&gt;知识从哪来，要分两头想。业务层和基建层主要靠人写，因为它们的来源是判断和事故；架构层和系统层主要靠工具生成，因为它们的来源是配置和代码结构。指望工具生成业务判断，等于让机器去猜人的决定；指望人维护调用关系，等于让人去追机器的变化。约束虽然不是一层，来源上却和业务层同源，同样得由人确认。&lt;/p&gt;
&lt;p&gt;四类角色里，映射这一类最该单独拎出来，因为它的作用点在动手之前，这一次改动的范围画错了，后面每一步都在错的范围里打转。事实、约束、验证回答的都是「画定的范围里怎么判」，映射决定的是那个范围本身画在哪。&lt;/p&gt;
&lt;p&gt;很多技术方案设计最怕的，是不知道改完影响谁。一个听着像单服务改动的需求，顺着链路走下去往往是跨好几个系统的改动：页面操作触发业务语义，语义落到客户端接口。接口过网关，网关转领域服务，领域服务再碰下游系统和消息。不在开头把这条链路画出来，方案就会按单服务改来做，做到一半才发现漏掉整段链路。&lt;/p&gt;
&lt;p&gt;所以我把「场景到链路」的映射当成一等公民来维护：页面操作、业务语义、客户端 API、网关、领域服务、下游系统或消息，一层层钉下去。这条映射链的价值是让 Agent 在动手之前就知道这次改动的半径有多大。&lt;/p&gt;
&lt;p&gt;映射的维护要有明确的归属，我把它挂在领域负责人身上，落笔的人不承担链路变化。维护时机也固定：接口变更、下游替换、消息格式调整发生时同步改，不做定期盘点。映射这一类知识还有个副作用：它把 PRD 到技术方案之间的转换显式化出来。那段转换最容易出错，以前靠人脑补，现在能对照。&lt;/p&gt;
&lt;p&gt;知识生成本身要落成一项服务，能被调用、能订阅：把生成拆成一支独立的服务，把知识库做成可检索、可订阅的实体，中间是一条明确的写入管道。这么拆的好处是知识的新陈代谢有了固定执行者，更新不再看谁今天有空去补文档。生成和知识库糊在一起时，每有一处结构变化都要人手动对一遍，对到第三天就没人跟了。&lt;/p&gt;
&lt;h2&gt;约束和验证规则，都要能指到落点&lt;/h2&gt;
&lt;p&gt;四类角色里最容易被忽略的是约束，而约束恰恰是杠杆最大的一类。它最容易漏，是因为漏掉不报错，改完照样能跑。&lt;/p&gt;
&lt;p&gt;模型非常擅长告诉你怎么写，它不擅长告诉你哪样不能写。因为「不能」是从一次线上事故、一次合规审查、一次已经谈过的业务妥协里推出来的。一个新人工程师问「这个字段能不能删」，答案大概率不在代码里。&lt;/p&gt;
&lt;p&gt;所以约束必须由人确认。我一直坚持的做法是：事实用工具生成，约束走人工确认，两者分开存放，连存放方式也刻意区分开。自动生成带来的自信感很危险：人会默认一份机器列出来的禁止项已经核对过，其实没有核对过。没经过人确认的那条知识要显式标成待确认，不能让 Agent 拿它当硬约束用。&lt;/p&gt;
&lt;p&gt;约束要落在能拦住的位置，指不到检查点的那条等于没写。写在文档里的约束只能靠模型自觉，落在校验脚本里的约束才是真的。我要求每一条约束都能指到一个具体的检查点，静态检查、评审清单上的一项、一条测试都算。&lt;/p&gt;
&lt;p&gt;约束的形态得结构化。写成散文的约束，模型读完之后要自己再做一次判断，等于没写。写成「这类改动禁止什么、哪些字段只能新增不能改语义、哪些状态流转必须审批」的条目，机器才能拿它做机械检查。判断一次改动到没到位，要看这次改动对应的验证方式有没有被执行，验证方式本身也要当成资产写下来。&lt;/p&gt;
&lt;p&gt;写下来之后，「跑几个单测就报完成」这种弱验证就有了一个可对照的标尺。每一类改动——加接口、改表结构、修缺陷——都明确写下它的验证组合，包含要跑哪层测试、要观察哪个指标、要在什么环境里验。按变更类型分开写更清楚：加接口要过契约测试，改数据库要过迁移验证和回归测试，改状态机要过核心流程测试，改消息 schema 要同时验生产端和消费端的兼容。&lt;/p&gt;
&lt;p&gt;验证规则跟约束是同一个道理：&lt;strong&gt;反馈要靠制度保证，不能靠自觉&lt;/strong&gt;。有了这张对照表，「做完了」这三个字才有一个可检查的定义。&lt;/p&gt;
&lt;p&gt;验证规则还是四类知识里最容易自证的一类：事实可能过期，约束可能有例外，验证规则拿当前这次改动跑一遍就知道还对不对。所以它值得先做，排在别的知识前面。凡是能反复执行的知识，都可以当成一轮回归的入口：拿当前改动跑一遍，跑通说明这条规则还成立，跑挂了说明规则和实践已经分家。这类知识自己会告诉你它过期没有。&lt;/p&gt;
&lt;p&gt;验收没过的时候要有确定动作，把「需要人工确认」换成一件能派活的事。我的处理是：能自动修的交给工具，需要判断的生成一条明确的待办并挂到责任人，涉及业务取舍的才升级到人。含糊的「待确认」会一直堆在列表里，直到某天没人再看。&lt;/p&gt;
&lt;h2&gt;加载有协议，更新有分工&lt;/h2&gt;
&lt;p&gt;知识分完角色和层级之后还剩一件事要定：一次具体任务该读哪一些。这个问题不定下来，前面分好的几层就落不到具体任务上，所以还有两件事要处理——加载怎么组织，更新谁负责。&lt;/p&gt;
&lt;p&gt;我用的做法是把加载本身写成协议。一个很短的入口文件负责引导，后面挂一张按任务类型组织的路由表：加接口该读哪些、改库该读哪些、修缺陷该读哪些，各自列清必读清单。知识由此从一堆资料变成一份可审查的加载清单，审查看的是这张路由表有没有漏。&lt;/p&gt;
&lt;p&gt;加载清单也得短。按任务类型分别列必读项：加接口必读接口契约、兼容性规则、测试和约束，改库必读库结构、测试和约束，修缺陷必读主流程和约束。清单之外的一律不进这一次任务的上下文。清单短，模型反而好判断；堆一堆候选让它自己挑，等于把选择成本转嫁给了它。&lt;/p&gt;
&lt;p&gt;粒度也得控。一段内容要不要再往下拆，看它本身：文件有多大、内容有多杂、更新频率高不高、别人会不会单独引用里面的片段。这几条里有答不上来的，先别急着拆。&lt;/p&gt;
&lt;p&gt;规模也得算进去：把几百个服务的知识全量同步一遍不现实，所以要按领域切分、各自维护，并且让入口只暴露跟当前任务相关的那一部分。规模上来之后，能不能只加载相关的那一点，才是决定成败的地方。&lt;/p&gt;
&lt;p&gt;更新上按可自动化程度分工，这是让知识不过期的关键：&lt;/p&gt;
&lt;p&gt;| 内容 | 谁生成 | 什么时候更新 |
| --- | --- | --- |
| 系统事实 | 工具自动 | 每次结构变更 |
| 约束与策略 | 人工确认 | 规则发生变化时 |
| 过程记录 | 自动生成 | 每次评审与事故 |&lt;/p&gt;
&lt;p&gt;能自动核对的事实每天重新生成，需要判断的约束走人工确认、变更才动。两者混在一个文件里，工具每天覆盖事实，人工维护的那部分就没人盯了，这是我见过最常见的腐化路径。结论和推导过程也必须分开：某些知识本身的论证和审核记录，要跟可复用的结论分开放。堆在一起的结果，是半年后没人分得清哪段是现在有效的规则、哪段是当初讨论时被推翻的想法。&lt;/p&gt;
&lt;p&gt;反向沉淀的口子得留着，这条路径要通。每次方案评审遗漏的东西、每次评审里提出的风险、每次线上暴露的隐性依赖、每次为兼容做的特殊处理，都要有回灌的入口。这条路径不通，知识库只会越用越薄，变成一份只在刚建起来那几天有用的文档。&lt;/p&gt;
&lt;p&gt;走完这一圈，值得留在链路上的知识长成一个统一的形状：它属于哪一层、由谁确认、在哪个环节真正查它。其余那些写得很全、读着也顺、却指不到落点的部分，最后都要靠人定期回头维护，这才是显式化真正的成本所在。&lt;/p&gt;</content:encoded></item></channel></rss>