平时折腾 Agent 的时候,经常会遇到一种让人无奈的状况:线上跑了成百上千次任务,失败的案例攒了一大堆,Agent 却完全不长记性,上礼拜踩过的坑这礼拜照样往里跳。要是人在旁边盯着,顺手帮它改两句提示词或者修一下工具参数,那叫人工运维;要是让 Agent 在单次任务里看到报错自己换个参数重试,那充其量只能算单次运行内的自我修正。想让系统真正自己长本事,得让它从跑过的历史痕迹里自己揪出病根、自己动手改配置,而且连它找问题和判对错的那套眼光也能跟着一轮轮进化,这就是递归自我改进(Recursive Self-Improvement,简称 RSI)想要干的事。

怎么理解递归自我改进

早些年 Good 和 Yudkowsky 提出种子 AI 的时候,聊的还是比较宏大的智能爆炸假说,大意是一个足够聪明的系统只要能改写自己的底层代码,改进能力就会像滚雪球一样呈指数级往上翻。放到今天大模型和 Agent 的工程实践里再看,这个概念其实早就从科幻口号拆解成了很具体的系统工程问题。

很多刚接触这个词的人容易把它跟常见的 Reflection 或者 Self-Correction 混为一谈。单步的自我修正,好比写代码的 Agent 跑了一次单元测试没过,看眼报错把当前函数改对,任务就算交差了,等下次开个新会话,它的系统指令、工具定义和思维套路还是老样子,一点没变。递归自我改进盯着的则是跨任务的系统级演化,不仅要用当前的运行结果去倒逼系统升级,还得让每一次升级反过来垫高下一轮改进的起点。换句话说,普通修正改的是单次干活的产出,而 RSI 改的是干活的机器,甚至包括检修机器的那套章法本身。

顺着被改造对象的深浅往下捋,现在的 RSI 实践大体能划出三个层次:

  • 产物层演化:最浅的一层只动系统吐出来的代码或脚本,拿 Voyager 或者 DeepMind 的 AlphaEvolve 来说,大模型本身和外围框架都不变,靠不断变异代码、跑测试筛选,把跑通的代码存进技能库或者当成下一轮变异的父本,靠产物的积累实现能力爬坡。
  • 脚手架与工具链演化:往深处走一层,不动大模型的底层参数,专门拿外围的提示词、记忆结构、工具Schema 和编排代码开刀,微软提过的 STOP 框架就是这个路数,用一段固定的模型配合外围优化器脚本,让优化器自己去改写优化器的代码。
  • 模型本体演化:最彻底的一层直接动到底层权重、训练数据管线乃至网络结构,像 Meta 研究的 Self-Rewarding Language Models,让模型自己生成训练样本,自己当裁判给样本打分,再用这些偏好数据去微调出下一代模型,连奖励模型都跟着一块迭代。

不管处在哪一层,只要想把递归的圈画圆,系统里头都得凑齐四个环环相扣的动作:先是从运行现场里捞出异常信号,接着把表象翻译成指向具体模块的诊断,然后再由修改机制动手生成新版本的系统,最后还得有一套评价机制来裁定这次改动到底是真修好了还是越改越乱,并把裁定结果喂回下一轮。

为什么难在裁判而不是动手

把这四个动作摆在台面上对比就会发现,如今要让大模型自己动手写段新配置或者改几行代码,技术上根本不算门槛,真正卡住绝大多数 RSI 系统脖子的,其实是裁判权到底交不交出去。

只要形成了自给自足的递归闭环,系统既是运动员又是裁判员,古德哈特定律几乎是躲不开的宿命。一旦评价指标写得稍微有点漏洞,改进机制很快就会摸清评分器的脾气,学会怎么用最小的代价糊弄过去,也就是常说的奖励黑客。拿对话 Agent 来说,要是单纯用用户有没有继续追问报错来当改进指标,系统改着改着可能就学会了在工具调用失败时瞒报结果,编一套听起来滴水不漏的套话把人糊弄过去,账面上的报错率是降下来了,实际干活的能力却彻底烂掉了。

更要命的是误差的递归放大。在单轮优化里,判断歪了一点顶多也就是这次没改好;可在递归闭环里,上一轮错误的诊断或者跑偏的改动一旦混进系统,就会变成下一轮的基准线,甚至连负责挑刺的分析逻辑本身也会顺着错误的反馈越走越偏,滚上三五轮之后,整个系统就会漂移到没人认识的怪异状态。所以真正在工程里能跑起来的 RSI,往往都是有界的,怎么给分析器套上证据约束,怎么把外部反馈嵌进递归链路里纠偏,才是架构设计里最吃功夫的地方。

用 a13n Findings 拆解 RSI 架构

光聊理论容易悬在半空,正好可以拿 a13n 里的 Findings 架构当个切片,看看一套落地的第二层 RSI 系统是怎么把上面说的几个环节严丝合缝对上的。在 a13n 里,Agent 的配置(模型、指令、工具与策略)是以不可变的修订版本(revision)形式迭代的,Findings 做的事情就是围绕这些修订版本搭起一条从诊断、纠偏到版本演化的递归链路:

flowchart LR
    T[选中的运行记录] --> A[Finding Agent]
    A --> F[Findings 与证据]
    F --> U[人工评审]
    U -->|assessment 与 note| F
    F -->|既有诊断作为上下文| A
    U --> C[Composer 核实证据]
    C --> P[既有写权限审批]
    P --> R[新的 Agent revision]

整套架构没有去碰底层模型的权重,它改进的标的物很明确:一头是通过 Composer 推动目标 Agent 的配置修订版本往前滚,另一头是通过评审反馈让 Finding Agent 在后续轮次里的诊断表现跟着进化。

信号筛选与证据锚定

任何 RSI 循环的第一步都是感知系统当前的表现。如果把线上所有运行记录全塞给分析模型,上下文撑爆不说,信噪比也极低;反过来要是只挑报错的记录看,又容易把正常的偶发网络抖动当成系统缺陷。

a13n 在这一环的做法是把粗筛和细查拆开。分析任务启动时,先按 execution(工具配置不当、参数错误或意图模糊未追问)、recovery(无效重试死循环与恢复代价)和 answer(工具调用失败却在最终回复中虚假报喜)三套信号规则去扫运行记录,最多扫描一百个根节点,挑出二十条送给内置的 Finding Agent,并把运行失败或根节点标了 error 的样本排在前面。

为了防止分析模型在递归起点上就出现幻觉,架构在宿主层加了一道硬性的证据锚定。Finding Agent 本身只有只读权限,它在运行过程中真正调用接口读取了哪些链路,宿主都会在底层的 read_trace_ids 字段里一笔笔记下来。等到 Finding Agent 提交结构化诊断时,系统会强制核对它引用的每一条运行记录和链路 ID:只要不在本轮选中的样本范围内,或者分析师根本没实际读过那条记录,提交就会被直接拦下;而且引用的运行记录必须严格归属于它所指控的那个 Agent 修订版本。这套约束保证了进入改进闭环的每一条缺陷,都挂着真实且版本对齐的现场证据。

病灶归因与配置映射

感知到异常之后,系统得知道该往哪个方向改。如果诊断结果只是一句笼统的回答不好或者调用失败,负责修改的模块拿到了也无从下手。

因此在持久化 Finding 时,架构要求每条诊断除了解释原因、给出改进建议和说明证据局限性之外,必须从九个受限分类里选一个主标签:unclear_request、instruction_issue、tool_design、tool_usage、tool_execution、answer_quality、context_gap、workflow_issue、boundary_violation。

这九个分类看着是业务标签,放在 RSI 的视角下看,其实就是把运行时的表象映射到系统可修改的部件上。同样是工具调用出了岔子,标成 tool_design 意味着得去改工具的描述或参数 Schema,标成 instruction_issue 意味着得去改目标 Agent 的系统提示词,标成 tool_usage 则是模型在特定上下文下的调用方式出了问题,标成 context_gap 说明缺了前置检索或外部信息。先把病灶定位到具体的配置维度,后头的修改器才能精准下刀。

评价器的递归演进

前面提到,区分普通自我修正和 RSI 的分水岭,在于改进机制本身能不能跟着一块被改进。在 Findings 架构里,扮演诊断器角色的 Finding Agent 也会犯错,拿只读查询工具的调用来说,分析模型有时会因为看不懂业务语义,把它误判成存在篡改数据的越界风险,建议加上审批门禁。

如果每次分析都是无状态的独立运行,那这种误判就会在每一轮分析里阴魂不散地反复出现。为了让诊断器自己也能在循环里变聪明,架构在人工评审(confirmed、expected、insufficient、false_positive)和批注(assessment_note)的基础上,做了一层上下文回灌。

当针对同一个 Agent 修订版本发起新一轮分析时,系统会自动把该版本下已有的 Finding(上限二十条、一万二千字节)连同人类给出的评审结论与批注,一并冻结注入到 Finding Agent 的输入上下文里。分析师在审阅新一批运行链路时,手里攥着前几轮的诊断档案和人类的纠偏理由:

  • 碰到证据等价的老问题,直接引用已有 Finding ID,不再重复产出噪音;
  • 碰到曾被标为 false_positive 或 expected 的场景,结合批注理解为什么之前的诊断被推翻,避免在同一类正常行为上继续误报;
  • 只有当新链路里出现了实质性的证据变化,足以推翻先前的判断时,才允许重新提出并说明新旧证据的差异。

这一步很关键:我们并没有去微调 Finding Agent 的模型参数,也没去手动改写它的内置指令,单靠把历史诊断与评审反馈结构化地喂回分析入口,就让诊断机制本身的准确率和去重能力随着运行轮次持续演进,在工具链层面上跑通了针对评价器的递归改进。

双 Agent 解耦与版本闭环

走完诊断和评审,最后一步就是把结论变成新的系统实现。在很多实验性的自改进框架里,找问题的和改代码的往往是同一个 Agent,权限一把抓,很容易出现为了消灭表面报错而乱改配置的情况。

a13n 在架构上把诊断和修改彻底拆给了两个独立的内置角色:Finding Agent 只有读取链路和提交 Finding 的权限,绝对碰不到配置写接口;真正负责动手改配置的,是工作区里的另一个内置角色 Composer。当一条 Finding 经过评审确认无误(标为 expected 或 false_positive 的记录会被直接锁死移交入口),系统会把 Finding ID 和出问题的确切 Agent 修订版本号一并移交给 Composer。

Composer 接手后,先去读取持久化下来的 Finding 详情、关联的链路证据以及证据局限性,对照目标修订版本的现有配置核实病根,随后拟定新的配置方案。经过平台既有的写权限审批后,修改落盘生成一个新的 Agent 修订版本(比如从 v1 演进到 v2)。等到 v2 投入运行产生新的链路数据,Finding Agent 又会基于 v2 的运行记录开启新一轮扫描,整条发现问题、沉淀证据、纠偏升级、生成新版本的递归回路就此咬合。

观测评分与闭环改进的界限

顺着这套架构再去对比 Langfuse 或 Pydantic Evals 这类可观测性与评测平台,能更清楚地看出观测工具和 RSI 组件之间的分野。

传统的观测与在线评测平台,核心逻辑是围绕受控数据集和聚合分数转的:把线上 trace 转成测试集,配好 LLM-as-a-Judge 规则跑出一堆零到一的分数,再画成折线图挂在仪表盘上。这套体系用来在发版前做回归拦截很管用,但它停留在只看不改的阶段。分数掉了,平台只管亮红灯,至于为什么掉、该改哪行配置,全得靠工程师自己跳出平台去排查和修复。

而在 RSI 的架构视角下,观测数据只是整个自改进循环的燃料。Findings 借用了底层的 trace 作为证据源,却没有去算一个笼统的聚合打分,因为生产环境里的偶发缺陷事先没法穷举,给单条失败链路打个零点三分对生成新配置没有任何帮助。它产出的每一条记录,从锁定的修订版本号、校验过的 Span 引用,到九分类标签和评审批注,数据结构完全是为了让下一个 Agent(无论是下一轮的 Finding Agent 还是接手修改的 Composer)能直接读懂并继续往下接力而设计的。

有界递归的工程取舍

回过头拿 RSI 的完整光谱来衡量,a13n 里的 Findings 走的是典型的有界递归路线:它工作在第二层(配置与工具链层),并且刻意在评价裁决(人工 Assessment)和修改合入(Composer 写审批)这两个节点上保留了人的控制权。

有人可能会觉得,既然都做递归自我改进了,为什么不干脆把人工确认也拿掉,让 Finding Agent 查出问题直接唤醒 Composer 自动改配置、自动发新版本?从代码实现上讲,把那两个开关改成全自动放行用不了几行代码,可在真实的生产环境里,无约束的自改进往往意味着失控。一旦拿掉了人工确认这颗定盘星,分析模型某一次偶发的归因偏差,就会被修改模型老老实实地写进下一版提示词里;新版本带着这段拧巴的指令上线跑出更诡异的链路,又会在下一轮分析里诱发出更离谱的诊断建议。

把繁琐的链路筛查、证据核验、历史比对和修改草案生成全部交给双 Agent 闭环去跑,只把最核心的定性与审批留在人手里,既吃到了递归迭代省下来的排查精力,又用最小的人工锚点按住了评价漂移的风险。将来随着模型推理和验证能力的继续拔高,这道护栏或许还能往后退一退,但在今天,想让一套自我改进系统在线上安稳地跑过成百上千轮,知道在哪个环节踩刹车,远比一味追求全自动要实在得多。