Skip to content

第 19 章 受控自进化:从存储到体验 ​

一家做自动化测试的团队在 2026 年初给自己的 Agent 加了经验库。三个月里积累了两百多条「有效做法」,其中一条是:「遇到前端元素定位失败时,改用 XPath 全路径定位」。这条经验在一个用 React 的项目里反复奏效,被标注为高置信度。第四个月,团队接入了一个用 Canvas 渲染的项目,Agent 按经验改用 XPath,而 Canvas 里的元素根本没有 DOM 节点。它在这个方向上连续尝试了十一次,把整个任务的预算耗在定位上,最终超时失败。

问题不在经验本身——那条经验在原来的场景里是对的。问题在于它被存下来时没有记录适用条件,于是从「在 React 项目里有效」变成了「定位失败时都该这么做」。经验从具体方法退化成了通用教条,而退化过程没有任何一步是错的。

这个案例说明自进化系统的核心矛盾:从轨迹中提炼经验能显著提升效率,但提炼过程本身会丢失上下文。丢失的是最关键的适用条件,而适用条件恰恰决定了经验是否可用。一条没有前置条件的经验,比没有经验更危险——它会让 Agent 在错误的方向上更自信。

2026 年 5 月,Luo 等人在 ACL 2026 Findings 的综述中把记忆机制的演进形式化为三个阶段(arXiv:2605.06716,2026-05-07):存储(trajectory preservation)→ 反思(trajectory refinement)→ 体验(trajectory abstraction)。这个框架的价值在于它把「记忆」从单一动作拆成了三种不同性质的操作,每种操作有不同的失效模式。存储层的失效是丢失,反思层的失效是错误合并,体验层的失效是过度泛化。

三个阶段的技术门槛递增,可商品化程度递减。存储层已经是标准能力,任何记忆系统都提供写入与召回;反思层需要判断力,多数系统只做摘要;体验层需要前置条件建模,目前只有少数系统提供。

本章沿这个三阶段展开。19.2 到 19.4 分别说明每一层的机制与边界,19.5 用具体案例说明为什么前置条件是体验层的必要条件,19.6 给出受控自进化的发布约束,19.7 讨论三个失效模式。

19.1 三阶段框架 ​

19.1.1 三个阶段的分工 ​

存储层(trajectory preservation) 解决的是「把发生过的事留下来」。这一层的操作是写入与召回,判据是保真度与可检索性。

反思层(trajectory refinement) 解决的是「把发生过的事整理成更有用的形式」。这一层的操作是摘要、冲突消解、合并、巩固,判据是信息密度与一致性。

体验层(trajectory abstraction) 解决的是「从发生过的事里抽出可复用的方法」。这一层的操作是经验沉淀与前置条件校验,判据是迁移正确率——不仅在新场景有效,而且在不适用的场景不触发。

三层的递进关系不是替代关系。体验层不能取代存储层,因为抽象会丢失细节,而细节在排障时不可替代;反思层也不能跳过,因为未经整理的原始轨迹无法支撑抽象。

19.1.2 每层的失效模式不同 ​

阶段核心操作判据主要失效模式
存储写入、召回保真度、可检索性丢失、写入噪声累积
反思摘要、冲突消解、合并、巩固信息密度、一致性错误合并、摘要漂移
体验经验沉淀、前置条件校验迁移正确率过度泛化、教条化

表 19-1 三阶段框架的操作、判据与失效模式

这张表的用法是:当系统表现异常时,先判断失效发生在哪一层。如果正确信息根本没被存下来,是存储层问题,改摘要或改经验都无用;如果信息存了但被错误合并,是反思层问题,加经验只会放大错误;如果经验在错误场景被触发,是体验层问题,改检索阈值无效。

19.2 存储层:轨迹保存 ​

存储层的能力是 retain、recall 与客户端兼容的 add_memory。这一层的设计目标是让「发生过的事」不丢失,且能被找回。

Mnemosyne 在这一层的两个设计决定值得说明。第一是单遍 ADD-only 提取:一次写入一次模型调用,只增不改不删。这个决定的收益是坏提取只引入噪声,永远不会销毁真实事实——因为没有覆盖操作,就没有「用错误内容替换正确内容」这条路径。代价是库会随时间累积冗余,需要靠后续的去重与巩固来收敛。

第二是双时间轴:observation_date 与写入时间分离。收益是能区分「事实何时成立」与「何时被记下」,这是时效正确率的基础。代价是写入方必须正确提供观察时间,缺省时退化为写入时间,而退化是静默的。

这一层已经商品化。任何记忆系统都提供写入与召回,能力差异主要在检索质量而不在存储语义。这意味着存储层不是差异化点——选型时把它当作必要条件而非选择依据。

代价在这里同样明确:ADD-only 让库只增不减,长期运行必然面对容量与噪声问题;双时间轴要求调用方配合,不配合时优势消失。

19.3 反思层:轨迹精炼 ​

反思层把原始轨迹整理成信息密度更高的形式。它包含四类操作,各自处理不同的问题。

19.3.1 session_summarize:七要素摘要 ​

session_summarize 生成会话摘要,包含七要素:目标、约束、决策、未决、产物、失败、偏好。三个设计细节决定它是否可用。

逐字锚点。 摘要中的关键结论保留原始表述,而不是全部改写成概括。这解决了摘要漂移问题——当摘要与原文冲突时,锚点让人能判断是摘要错了还是记忆错了。

未决事项独立成条。 未决项不从属于摘要,而是作为独立条目存在。原因是未决项的使用方式不同:摘要是被召回的背景,未决项是下一次对话的起点,需要主动追问而不是被动检索。

增量更新与重建分离。 摘要支持增量更新以节省成本,也支持 rebuild=true 丢弃旧摘要从原文重建以抗漂移。两者的取舍是成本与准确性的直接交换。

代价是摘要本身占用存储与计算资源,且七要素在短会话中多数为空,产生大量低价值摘要。

19.3.2 conflict_resolve:六类冲突与四操作 ​

conflict_resolve 判定六类冲突:时间更新、偏好变更、作用域差异、精度差异、逻辑矛盾、来源冲突。对应四种操作:ADD、NOOP、UPDATE、KEEP_BOTH。

六类判定的价值在于它把「新事实与旧事实矛盾」这个模糊问题拆成了可分别处理的情形。时间更新是同一事实的新版本,应当 UPDATE 并把旧条目标记为被取代;作用域差异是两条事实在不同 scope 下都成立,应当 KEEP_BOTH 而不是判为冲突;精度差异是一条比另一条更具体,两者可以共存。

scope=audit 模式做全库扫描,只报真冲突——共享实体且共享谓词。这个约束是针对一个具体缺陷的:早期实现把实体共现误判为冲突,导致大量正常记忆被标记。

代价是六类判定需要模型参与,全库扫描的成本随库规模线性上升;dry_run 默认开启意味着它不会自动修复,需要人工或流程确认。

19.3.3 consolidate 与 memory_consolidate:合并与巩固 ​

consolidate 把高度相似或同义的记忆聚合并成一条代表性记忆,原记忆标记为已合并而非删除。memory_consolidate 走三条巩固路径:情景→语义(同一事实在多个会话出现,提升为语义记忆)、情景→程序性(同类任务成功两次以上,归纳为带前置条件的做法)、失败→负记忆(失败或被回滚的轨迹转成禁忌条目)。

三条路径的关键设计是幂等:同一批源不会重复生成。这个约束的必要性在于巩固是周期性任务,非幂等会导致每跑一次就产生一批重复条目,库反而膨胀。

代价是合并会丢失细节。两条相似记忆被合成一条代表性记忆后,差异部分不再可检索。缓解方式是原记忆保留为已合并状态而非删除,但这只是把成本转移到存储上。

19.4 体验层:轨迹抽象 ​

体验层从轨迹中抽出可复用的方法,并记录它何时适用。 playbook_save 与 playbook_recall 处理经验,code_change_record 处理代码变更,code_archaeology 处理历史陷阱。

19.4.1 playbook_save:前置条件必填 ​

playbook_save 保存可复用的做法,preconditions 是必填字段,包含三件套:must(必须满足的条件)、must_not(必须不满足的条件)、typical_env(典型环境)。

必填这个约束是这一层最重要的设计决定。它把「经验」与「建议」区分开:建议可以无条件给出,经验必须声明适用范围。缺了它,系统就只能存下本章开头那种「定位失败时改用 XPath」的教条。

配套的 failure_modes 记录已知失效场景,anti_patterns 记录反模式,evidence 记录支撑证据。四者合起来构成一条可审查的经验条目。

代价是写入成本显著提高。一条带完整前置条件的经验,需要写作者明确回答「在什么条件下不该用」,而这个问题的答案往往要等到出过事故才知道。实践中多数条目在首次写入时前置条件不完整,需要靠后续回写补全。

19.4.2 playbook_recall:前置条件校验 ​

playbook_recall 检索候选经验并做前置条件校验,返回项带 applicable 与 blocked_by。只有 applicable=true 的条目应当被注入上下文,其余丢弃。

这个设计防的是负迁移:一条在 A 场景有效的经验被无差别套用到 B 场景。校验的依据是调用方提供的当前环境描述与条目的 must / must_not 比对。

代价是校验依赖调用方如实描述环境。若调用方只传一句「在改前端代码」,校验无法判断是否满足「项目使用 DOM 渲染」这个条件,applicable 会退化为默认真。

19.4.3 code_change_record 与 code_archaeology ​

code_change_record 记录一次代码变更的意图、约束、影响面、被拒绝的方案与结果。它存的是版本控制系统不记录的东西:为什么这样改、当时有什么限制、哪些方案被否掉以及为什么。

code_archaeology 在改动前查历史:某个文件或符号的变更链、最近几次意图、是否被回滚过、已知约束。传入 intent 时转为坑位预警,返回历史失败与放弃方案。

这两个工具的价值在长期项目中显现:一个被回滚过两次的方案,如果不记录,第三次还会有人尝试。代价是记录依赖开发者主动写入,而最需要记录的正是那些忙到没时间记录的变更。

19.5 为什么前置条件决定了经验能否使用 ​

回到本章开头的案例。那条「定位失败改用 XPath」的经验,如果写入时带上了前置条件,形态会是这样:

json
{
  "pattern": "元素定位失败时改用 XPath 全路径定位",
  "preconditions": {
    "must": ["页面元素由 DOM 渲染", "元素在 DOM 树中有稳定路径"],
    "must_not": ["页面由 Canvas 或 WebGL 渲染"],
    "typical_env": "React / Vue 等 DOM 框架项目"
  },
  "failure_modes": [
    {"when": "Canvas 渲染的页面", "why": "元素无 DOM 节点,XPath 必然失败"}
  ]
}

差别不在内容多少,而在检索时能否被排除。带前置条件的条目在 Canvas 项目里会被 playbook_recall 判定为 blocked_by: ["页面由 Canvas 或 WebGL 渲染"],从而不被注入;不带前置条件的条目会被当作通用方法注入,Agent 于是在错误方向上连续尝试。

这个差别有一个量化后果值得注意:负迁移的代价不是一次失败,而是失败后的连锁尝试。Agent 相信这条经验有效,于是在失败后不会怀疑方法,而会怀疑参数——它换 XPath 写法、加等待、改选择器,把预算消耗在错误的维度上。案例中十一次尝试全部无效,就是因为每一次失败都被解释为「执行不对」而不是「方法不对」。

负迁移的另一个特征是它在日志里看起来像正常失败。检索正常、注入正常、执行有报错,没有任何一个环节显示「用错了经验」。要发现它,必须有一条记录说明「这条经验在当前环境不适用」,而这正是前置条件的作用。

代价是维护前置条件需要持续投入。经验条目会随环境变化失效——一个项目从 DOM 迁移到 Canvas,原来的前置条件需要更新。没有定期复核机制时,前置条件会变成历史陈述,校验也随之失效。

19.6 受控自进化的边界 ​

任何由模型生成的 Memory、Skill 或补丁,都应视为候选变更,而不是已生效的规则。这个定位包含五项要求。

第一,可复现评估。 候选变更必须在一批固定 case 上跑出前后对照,且 judge 版本固定。没有对照的变更无法判断是改进还是噪声。

第二,安全检查。 候选内容需要过写入前检查:是否含凭据、是否含不可见字符、是否含注入片段。模型生成的内容与用户输入的风险等级相同,不能因为它来自系统内部就跳过检查。

第三,版本化。 每次变更记录原版本、候选差异、评估结果、采用范围。目的是让「三个月前为什么采用这条」在需要时能回答。

第四,灰度。 候选先在部分流量或部分任务类型上生效,观察一段时间再全量。记忆类变更的副作用往往延迟显现——一条错误的经验可能要等到特定场景出现才暴露。

第五,可回滚。 回滚路径必须在采用前就存在,而不是出问题后临时设计。对经验库而言,回滚意味着停用某条条目并恢复其旧版本,而不是删除——删除会丢失它曾经生效的证据。

这五项要求可以压缩成一条原则:不得让模型推测直接写成组织规则。 模型可以提议,可以生成候选,可以自己评估,但不能跳过人的采用决策。原因不是不信任模型,而是「组织规则」这个层级的影响面太大——一条错误规则会影响所有后续任务,而它的错误往往在很久之后才显现。

代价是自进化的速度被人为限制。一个完全自动的闭环可以在一夜之间把两百条经验全部更新,而受控流程可能一周只能处理十条。这个速度差在快速变化的业务里是真实成本,团队需要在「快」与「可回退」之间做明确取舍,而不是默认选择快。

19.7 三个失效模式 ​

经验库变成教条库。 表现是条目数量持续增长但触发率下降,Agent 越来越依赖少数几条高频经验,遇到新场景时不再探索。机制是正向反馈:一条经验被用过且成功,置信度上升,下次更容易被召回,形成自我强化。检测方法是看经验触发后的成功率是否随时间下降——若下降,说明它在被过度套用。缓解方式是给经验设有效期与触发频率上限。

抽象过度丢失细节。 表现是经验描述正确但无法执行。例如「处理超时应当重试」这条经验在抽象层面无错,但它没有说明重试间隔、重试上限、以及哪些错误不该重试。机制是抽象过程天然丢弃具体参数,而参数往往决定成败。检测方法是让另一个 Agent 只看经验条目执行任务,看它能否复现原效果。缓解方式是在经验中保留一个可指认的成功案例作为参照。

评估缺失导致退化不可见。 表现是系统持续「学习」但质量不升反降,且无人察觉。机制是自进化的变更没有对照评估,每次变更看起来都合理,累积效果却是退化。这是三个失效模式中最危险的一个,因为它不产生任何异常信号。缓解方式是把第 18 章的 Badcase 闭环接入自进化流程:每次候选变更必须在同一批 case 上跑前后对照,退化超过阈值时自动拒绝。

失效模式表现检测方法缓解方式
教条化条目增长但触发率下降触发后成功率的时间趋势有效期与触发频率上限
抽象过度描述正确但无法执行另一 Agent 仅凭条目复现保留可指认的成功案例
评估缺失持续学习但质量下降变更前后对照评估接入 Badcase 闭环,退化即拒绝

表 19-2 自进化的三个失效模式

19.8 本章小结 ​

本章确立三条判断。第一,记忆机制的演进是存储、反思、体验三个阶段,三者的失效模式不同(丢失、错误合并、过度泛化),因此排障时必须先定位失效发生在哪一层;改错层的修复不会有效果。第二,存储层已经商品化,不是选型依据;真正的差异在反思层的判断力与体验层的前置条件建模,而后者的核心是 preconditions 必填这一约束——它把经验与建议区分开。第三,任何模型生成的记忆、技能或补丁都是候选变更,必须经过可复现评估、安全检查、版本化、灰度与可回滚发布才能进生产;不得让模型推测直接写成组织规则。

三条判断各有成立条件。三阶段框架描述的是能力演进的方向,不是每个系统都必须依次实现——一个只做存储层但检索极强的系统,在特定场景下可能优于三层都做但每层都浅的系统。前置条件必填的代价是写入成本高,在快速试错阶段会显著拖慢积累速度,此时更合理的做法是先以低置信度记录、在首次失效后补全条件。受控流程的代价是速度,当业务变化快于一周十条经验的处理速度时,团队需要重新设计流程而不是放弃控制。

本章与第 18 章共同构成了调优篇的闭环:第 18 章处理已知问题的发现与修复,本章处理能力的沉淀与复用。两者的连接点是评估——没有固定的 case 集与 judge,Badcase 无法回归,候选变更也无法对照。

调优篇到此结束,但它留下的问题指向实践篇。本章反复出现的判断是「这个方案在什么条件下有效」,而条件判断最终要落到具体系统的对照上:不同系统在三层上的完成度不同,同一层内部的实现取舍也不同。第 20 章进入第一梯队系统的深度对照,把这些判断换算成可比较的具体设计。


Copyright © 2026 胡景堃(Hu Jingkun). 采用 CC BY-NC-ND 4.0 许可。未经授权禁止传播、复制或用于商业化。