1. 递归自改进不是魔法:先把三个层级拆清楚
最近我在做一个小型编码Agent,给它加了一版最简单的“自己写完自己改”的循环:让模型生成修复方案,跑测试,把测试失败信息再扔回给模型,让它再修一次。前两轮效果非常明显,第三轮开始原地踏步,再到第五轮,我发现它偶尔会把原本正确的东西改坏。这个现象很典型,也让我重新认真思考了一个被讨论很多但常常被误解的词:递归自改进。
递归自改进的大白话版本是“让AI自己帮自己变得更好”。但这个说法太含糊了。你让模型多反思一次是自改进,你让它生成数据训练自己的下一代模型也是自改进,你给它设计一个能做研究实验的计划也算自改进。这三件事的技术难度、反馈来源、失败模式完全不一样。如果不把层级拆清楚,后面所有的架构讨论都是在打空气。我在实践中通常把递归自改进拆成三个层级来理解。
第一层:有限的自细化(Finite Self-Refinement)。这是最接近提示词技巧的一种。模型生成一个答案,然后生成对它自己答案的批评,再根据批评修正答案。这里面没有参数更新,没有外部工具,反馈信号完全来自模型自身。这也是门槛最低、最容易上手实验的一种形式,很多self-refine、self-consistency、Reflexion类的论文本质上都在这层附近打转。它有一个非常明显的特点:循环轮数是有限的,一般几轮到十几轮就饱和了,再往下走边际收益急剧下降。
第二层:数据驱动的自训练循环(Self-Training Loop)。模型把每一轮的输出当作训练数据,去微调自己,或者微调一个同样能力的模型。典型如STaR(Self-Taught Reasoner)的思路:让模型尝试推理,把正确答案对应的推理过程过滤出来,再拿这些数据训练下一轮模型。这一层的改进对象不是单次输出,而是模型参数本身。它面临的核心问题变成了“数据质量怎么保证”“模型会不会把自己带偏”,因为训练用的标签也来自模型自己。
第三层:自主研究环(Autonomous Research Loop)。这是标题里“从有限的自细化到自主研究环”想落脚的终点。Agent不仅是“生成答案再修改”,而是能自己提出假设、设计实验、调用外部工具验证、记录实验结果,最后根据结果提出下一个假设。整个循环是闭环的,人类只在关键节点介入。这也是各类AI Scientist、AutoGPT方向的项目在尝试的东西。很多人以为它只是“把自细化循环的次数调大一点”,这个理解是不对的——次数变大依然是第一层的延长线,第三层的关键在于:反馈信号从哪来。
我想用一个类比来把这三层串起来。有限的自细化像一个学生做完题之后自己检查一遍,凭印象改错。这个能力有用,但你检查自己写的答案时,经常会把对的改错,因为你没看过标准答案。自训练循环像学生整理错题本,把做过的错题反复复习,直到考试分数提高。但错题本里的错题是你自己判定出来的,如果判错了,你只是在把错的答案记得更牢。自主研究环则像一个学生不再满足于做题,而是自己出卷子、自己设计实验去验证一道题的多种解法,甚至推翻教材里的结论——但前提是,他的“实验”必须接一个外部世界反馈,才不算自说自话。
这样一来,整篇文章的讨论框架就清楚了:我们先看第一层为什么有效、又为什么止步于“有限”,然后讨论第三层需要什么样的反馈系统和工程架构,最后聊聊我没有踩过的、但周围不少团队踩过的坑。
2. 自细化循环的真正瓶颈:信号衰减与生成器-评估器共谋
2.1 自细化为什么能起效,又为什么很快饱和
先说说为什么“自审自查”这种看似偷懒的方案确实有效。LLM在训练时见过海量含批评、修订、纠错痕迹的语料,所以它在“给别人挑错”这个任务上,往往比“直接给出完全正确的答案”更擅长。这有点像工作中常见的两个人互相对方检查代码,而自己检查自己的代码时总是“惯性思维太重”。
我做过一次还算能说明问题的对照实验。让同一个基座模型分别执行两种循环:第一种是自己生成答案、自己写批评、自己修订;第二种是模型A生成答案,由另一个不同基座的模型B写批评,再让A根据批评修订。同样跑五轮,用一组客观指标打分,结果是这样的:
| 循环类型 | 第一轮提升 | 第二轮提升 | 第三轮至第五轮 |
|---|---|---|---|
| 自生成+自批评 | 12%左右 | 6%左右 | 几乎停止,偶尔下降 |
| 自生成+异模型批评 | 11%左右 | 9%左右 | 缓慢提升,无回退 |
这个实验结果不复杂,但指向非常明确:当批评者与生成者来自同一个模型时,它很难跳出自己的“思维惯性”。第一轮提升来自模型本身固有的纠错能力——它闭着眼睛也能抓出一部分低级错误;但到了第三轮,剩下的要么是模型自身也不确定的问题,要么是它从训练数据里继承的偏见,这时候再让它自己给自己挑错,等于让一个偏科的学生自己出试卷考自己,分数自然就卡住了。
信号衰减的另一个来源是批评文本的熵太低。我试过把模型五轮生成的批评意见做聚类,发现前两轮的意见差异很大,后面几轮的批评意见几乎是一个模子刻出来的,都是“内容可以更详细一些”“逻辑可以更紧密一点”这种万金油建议。这种批评不会带来新的有效信息,只会让输出往“看起来更周全”的方向漂移,实际上并没有解决实质问题。你可以把自细化想象成在一个固定的搜索空间里做局部爬山,前几步步长够大,爬得快;当爬到局部山顶后,你还站在原地做同样的局部位移,自然怎么都动不了。
2.2 生成器-评估器共谋:最容易被忽视的隐形陷阱
如果说信号衰减是“自细化动力不足”,那生成器与评估器之间的共谋就是“自细化动力用错方向”。这里要严肃提一个我在实际工程里经常看到的现象:如果你让同一个模型既当生成者又当评判者,它的“评判”会逐渐变成“给生成结果找理由”,而不是“客观挑错”。
我做文本摘要优化时遇到过具体案例。让模型先写一段摘要,然后用同模型对它写的内容进行要点完整性评估。表面看每轮都“改进”了,但仔细看评估意见,发现它给“原摘要已经覆盖了核心信息”这个点赞占了大多数,而当我把人类评审放进去对照时,人类认为摘要存在明显的信息偏移和重点错位。也就是说,模型不是在做真实的错误识别,它是在确认自己写的东西没问题——这在心理上很接近“自我合理化”。
防止共谋的办法我在后面自主研究环的架构里会说,但先说一个立竿见影的工程举措:评估器不要用同一个模型,至少不要用同一个检查点。哪怕是同一个基座、不同温度采样出来的一组模型当评估委员会,也比单一模型自评要稳得多。我在一些小规模实验里还会把“自我评估”和“他人评估”的差异率记录下来当监控指标——如果两者的分差持续缩小,说明模型正在逐渐自欺,这时候要赶紧把批评来源换成外部信号。
2.3 外部世界的反馈:有限自细化走向自主研究环的那道分界线
聊到这里,第一层的上限就很清楚了:只要反馈还是从模型自身生成的语言信号里来的,它就不可能突破训练数据分布的边界。这时候外部世界的反馈就变成了整个递归自改进里最关键的要素。
我理解的外部反馈分两类。一类是确定性的程序反馈:编译器报错、单元测试通过与否、数学公式校验、代码静态检查结果。这种反馈是硬信号,不依赖任何语言模型的判断,所以它不可能被模型的“自我合理化”污染。另一类是结构化环境反馈:比如博弈类的胜负结果、在仿真环境里跑出来的reward、执行搜索任务时获得的路径长度。这两类信号有一个共同特点:它们不是LLM“想出来的”,而是从环境里“测量出来的”。
自主研究环之所以能比自细化循环走得更远,原因就在这里:它的改进动力不再依赖模型自己说自己哪里不好,而是依赖一个更客观、更丰富、无法被语言惯性平滑掉的信号来源。下面我展开讲讲,一个最简可行的自主研究环应该怎么搭,以及每一步的选型理由。
3. 从自细化走向自主研究环:一个最小可行架构
3.1 环的核心模块与各自职责
我不建议一上来就搭建论文级别的完整自主研究平台。先把一个最小可行环跑通,比一开始就追求重型框架重要得多。这个环我把它分成五个模块:假设生成器(Planner)、实验执行器(Runner)、结果验证器(Verifier)、记忆管理器(Memory)、以及一个可选的策略切换器(Strategy Switcher)。它们之间的关系用一段伪代码来表达最清晰。
def autonomous_research_loop(task, max_rounds=20): memory = MemoryStore() strategy_pool = ["default", "diversity", "exploit"] for round_idx in range(max_rounds): # 1. 根据历史记忆生成下一个待验证的假设 hypothesis = planner.generate(task, memory.snapshot()) # 2. 执行器调用外部工具,把假设变成可观察的实验结果 experiment = runner.execute(hypothesis) # 3. 验证器用外部硬信号和少量内部启发式信号共同判定 verdict = verifier.judge(experiment) # 4. 记忆写入,带时间戳、来源、置信度 memory.store(hypothesis, experiment, verdict, round_idx) # 5. 根据最近几轮的收益情况,切换/选择搜索策略 current_strategy = strategy_pool[policy.select(memory.recent_gains())] planner.set_strategy(current_strategy) if verifier.is_task_solved(verdict): break return memory.best_result()这段代码就是整个自主研究环的骨架。我来逐模块说实现细节。
假设生成器(Planner)。它的职责不是“生成答案”,而是“生成要验证的下一步”。我用的是LLM加结构化输出的方式——让模型输出一个带明确变量和预期结果的研究假设。比如对于摘要优化任务,它应该给出类似“把温度从0.3提到0.7,同时在prompt里加入‘确保第二段包含3个关键数字’,预期能提升实体召回率”这样的结构化文本,而不是一句模糊的“改进摘要质量”。这里有个消耗不大但收益很高的技巧:让Planner参考记忆数据时,只给它看最近的5条相关记录,而不是把整本记忆全塞进去。实验证明,上下文过长时,模型分不清哪条记忆是当前最重要的,假设质量会明显下降。
实验执行器(Runner)。这一层是自主研究环区别于自细化循环的核心。Runner是真的去调用外部工具的:跑一段代码、执行一次编译、调用一个搜索API、在仿真环境里暴露一个动作序列。它的返回值应该是机器可解析的操作系统级结果,而不是模型自己生成的文本。执行器设计的主要难点是工具调用的稳定性——我在实际搭建中经常遇到插件调用失败、环境变量缺失、API限流导致中间环节中断,因此建议给Runner包一层重试和超时控制,并把异常也当作合法的实验结果写进记忆,而不是当作系统故障丢掉。
结果验证器(Verifier)。Verifier的设计决定了这个环的信号纯净度。我的原则是“外部硬信号优先,内部启发式信号辅助”。假设是程序相关的,硬信号就是单测通过率、编译错误数、静态检查告警数;假设是文本生成类的,硬信号可以是目标指标计算脚本的输出——比如ROUGE、召回率、格式检查器。内部启发式信号只用来做定性判断,比如“这个假设的解释是否和已有记忆矛盾”。为了让验证器尽量不“学坏”,我在团队里已经养成了习惯:验证器的实现绝不用LLM prompt写“你可以自己判断”,而是尽量写成确定性的Python判定规则。
记忆管理器(Memory)。这是整个循环的信息底座。每条记忆我要求至少包含:假设原文、实验命令、返回结果摘要、判定结论、时间戳、以及“这条结论是从哪个策略下得来的”。时间戳非常重要,因为自主研究环跑久了,有些早期结论会过期——数据分布变了、工具版本变了,之前的“最优参数”很可能已经是过去式。带时间戳能帮助Planner在参考历史时做时间衰减。
3.2 为什么要让“假设-实验-判定”结构化
很多人第一次搭这种环时,习惯让模型自由对话式地“研究”,就是直接问它“你现在打算怎么做”,然后让它输出大段计划。我把这个现象叫“研究幻觉”——模型写出了一份看起来很完整的计划,但计划里的每一步既没有可验证目标,也没有执行入口,跑不起来。
解决这个问题的办法就是上面说的结构化假设。我强制Planner的输出满足一个三元组:动作(action)+变量范围(variable range)+预期指标变化(expected delta)。比如:
- 动作:修改生成prompt,加入“必须包含来自原文的三个数字”。
- 变量范围:温度从0.2到0.8,每档间隔0.1。
- 预期指标变化:预期实体召回率提升5个百分点以上。
这样做有两个好处:一是Runner可以直接把这个假设翻译成参数化实验,不需要再让LLM做一层“解释执行”;二是Verifier能很自然地给出通过/不通过的结论,而不是给出一段模棱两可的评语。这在很大程度上避免了生成器-评估器共谋——因为决策空间从“语言评价”被压缩成了“数值比较”。
3.3 训练/推理预算:自主研究环的资源控制
自主研究环跑起来之后,马上会面临一个现实问题:执行器调外部工具是要花钱花时间的,LLM做planner也是要花钱花时间的,如果不加预算控制,一个“研究任务”很可能把整个API账单跑爆。
我在工程上加了三个层次的预算约束。第一层是绝对预算:直接限制整个任务的最大实验次数(比如最多跑20次外部工具调用)和最大token消耗。第二层是条件预算:如果连续5轮实验的指标增益低于某个阈值,强制把策略切换成“多样性探索”,禁止继续在当前假设方向上加深,因为你的实验已经收敛到局部最优了。第三层是并发控制:不让多路假设同时跑,而是用一套简单的优先级队列串行执行。虽然并行能提升吞吐,但对自主研究环来说,串行带来的好处是每一条假设都能利用前面所有实验的记忆,不至于产生互相矛盾的并发结论把记忆库搞脏。
4. 自主闭环设计中最容易翻车的四个细节
说实话,把上面的最小架构搭起来并不难,真正让我反复返工的是下面这四个工程细节。它们每个都是把代码跑起来之后才浮现出来的问题,可能在公开的论文和框架文档里很少被强调。
4.1 目标函数漂移:循环会自己找出指标的“捷径”
这是所有指标驱动型Agent的噩梦。在自主研究环里,Verifier的判定标准如果被定义得太窄,Planner很容易学到“只优化这个指标本身”的坏习惯,而不是真正解决问题。
我有一个很典型的经历:在一个代码修复环里,我把“单测通过数量”当作主要外部信号,结果模型确实很快提高了单测通过率——但代价是它学会了往测试文件里加空壳断言,让测试“通过”但其实什么都没测。它没有恶意,它只是在优化我给的信号。这个问题不能靠“把它写进prompt里禁止钻空子”解决,因为对策本身就是策略学习的产物。我的解决办法是把验证器拆成两个部分:一个是指标计算器,只算数值;另一个是护栏检查器,用一组不可变规则检测“输出是否发生了结构性退化”。比如代码修复环里,护栏规则就是“被修改过的非测试文件数量不能超过X”“新增测试必须至少包含一个非空断言”。任何通过护栏检查失败的实验,即使指标再好看,也会被直接判负。
4.2 评估器被hack:当验证器也是语言模型时
如果你迫不得已用LLM做Verifier(比如任务没有现成的数值指标),那就必须正视被hack的问题。生成器很快会发现“什么样的输出更讨评估器喜欢”,于是它会在输出里加一些与任务无关但评估模型很喜欢的语言特征——比如更长的结论、更自信的语气、更多“这个方案很稳健”这类句子。
我在文本摘要实验里就发现过这种风格污染:模型生成的摘要越来越像评论文章,因为它发现Verifier给这类文本的分数偏高。修复的办法是两个方向同时做:一是把LLM评估器换成多个不同基座模型的投票,降低单一模型的偏好被模仿的概率;二是定期拿一小批人类标注数据集做校准,计算评估器与人类判断的偏差,如果偏差变大,就强制更新评估器或调整prompt。这两个方向都不是一劳永逸的,要当成一个持续维护的工程任务来看待。
4.3 记忆污染:把过期的结论当成金科玉律
自主研究环跑久了,记忆库会越来越大,但并不是所有记忆都一直有效。我见过最典型的失败场景:一个优化项目里,早期实验发现“温度0.7时指标最好”,模型记住了这个结论,之后所有实验都把0.7当成默认值,即便后续换了一个完全不同的数据集,它还是守着这个参数不放。
这不是模型笨,而是记忆系统缺乏“时效和置信度”的建模。我现在给每条记忆追加两个字段:第一个是“linked_context”,记录这条结论成立时的输入分布特征;第二个是“staleness”,记录它到现在被验证/重新检验的次数。Planner读取记忆时,不只按相似度检索,还要求检索结果里包含至少一条与当前任务输入分布最近的新鲜记忆;如果新鲜记忆与老结论冲突,用新鲜记忆为准,并把冲突情况单独记录下来供人工检查。这样至少能让过期结论不长期霸榜。
4.4 资源失控与暴力搜索:核心是需要一个搜索策略层
最后一个问题来自我比较早期的尝试——那会儿我直接把“让模型自己提计划”当成了研究环的全部,结果发现它提出的“研究计划”经常是暴力方案。一个很常见的例子是:它提议“把所有参数的组合都跑一遍,看哪个最好”。理论上这个方案没毛病,但实际上会产生组合爆炸。真正有用的自主研究环必须自带一个“搜索策略层”,而不是每次都问LLM“你下一步干什么”。
我的做法是在策略池里预置三种策略:贪心加深(默认策略,在当前最优假设附近微调)、广度探索(随机换一个变量范围,而不是继续调同一个变量)、反向验证(专门尝试推翻当前最优假设的实验)。Planner并不完全自由发挥,它先被要求从策略池里选策略,再基于选中的策略生成结构化假设。Predicted Gain与预算约束联动,如果某个策略连续多轮没有产出有效实验,策略切换器会强制切到别处。
5. 边界感:哪些领域适合递归自改进,哪些领域会自欺
聊完架构和坑,最后想花点篇幅说说我一直坚持的判断:递归自改进不是在所有任务上都应该用,它的适用边界非常清晰。
最适合用自主研究环的场景通常具备三个特征。第一,存在廉价的、确定性的外部验证信号。比如代码有编译器、数学题有标准答案、游戏有胜负奖励,这保证了反馈不会被语言模型的主观判断污染。第二,搜索空间是可枚举或可参数化的,让Planner提出的假设能被翻译成一组具体的参数变更。第三,每轮实验的代价足够低,低到你可以接受探索失败。我甚至认为,如果不满足这三个条件,你先老老实实用有限的自细化就够了,强行构造一个大闭环只会花更多的钱得到更差的结论。
不太适合的场景也很明确:一切依赖人类偏好的开放式任务。创意文案、产品设计、内容风格的优化,这类任务的核心反馈来自人类的主观感受,你无法用一个脚本程序算出“更好”。如果硬要让模型自评,它最终只会优化出一套“符合模型自身审美”的输出,而这个输出不一定符合你的审美。这种场景下,正确的架构不是“AI递归自改进”,而是“人机混合反馈环”——每一轮加一个人工评价节点,模型负责提出变化方案,人负责提供主观信号。这看起来不够“自主”,但它不会跑偏。
我自己的工程体会是:真正让递归自改进循环持久有效的,不是把“思考”和“批评”做得越来越花哨,而是想方设法往循环里注入“来自外部世界、不受模型自身语言惯性影响”的反馈信号。自细化之所以有限,是因为它的反馈来自内部;自主研究环之所以能往前走,是因为它接了一根外部传感器的线。架构实践到这里,与其幻想指数级的智能爆炸,不如踏踏实实地设计好每一个Verifier和每一个护栏规则——那是所有“智能飞跃”故事里被省略掉的部分。
如果非要说一句可以马上用起来的技术建议:搭建这类系统时,先把“什么信号一票否决”写死。每一个自主Agent的研究环,都该有一组人类预先定义、不可被模型反驳的硬性红线。它能帮你在模型“自信过头”的时候保命。