先给结论
这篇论文做了一件很少有人做的事:不看你最终得了多少分,而是拆开进化搜索的全过程,看 LLM 驱动的编码代理到底在改什么。
一句话总结:进化式编码代理的大部分分数提升来自超参微调 + 短周期代码循环,而非真正的算法结构创新。真正有效的编辑类型(External dependency、Efficiency、Architectural change)在搜索分布中反而很稀少。Benchmark 分数不能区分"发现了新结构"和"反复调参+过拟合"。
研究动机
LLM + 进化搜索的范式(FunSearch, AlphaEvolve 等)在数学发现和算法设计中取得了亮眼成绩。但一个根本问题始终没有被回答:
这些系统到底在进化什么? 最终分数的提升可以来自完全不同的机制:
- 新算法结构:真正发现了新的程序逻辑
- 超参微调:只是在已有策略上改数字
- 知识重组:把 LLM 内部已有的知识重新拼装
- 过拟合:针对评估器漏洞的 hack
现有工作通常只报告最终最优分数,但这个数字掩盖了改进的路径和机制。而且这些系统相对于独立采样、贪心修正等 baseline 的优势高度敏感——取决于任务设计、初始化、评估器配置和模型选择。
论文的核心问题:What do evolutionary coding agents evolve, and how do their search dynamics produce improvements?
数学表示及建模
进化式编码代理的形式定义
论文定义了一个 evolutionary coding agent 为具备以下组件的系统:
- 任务规范 + 可执行评估器
- 候选程序种群/归档(population/archive)
- 一个或多个 LLM 生成代码变异、重组或精炼
- 搜索过程选择哪些程序和上下文进入下一代
一个 search trace 是该系统产生的完整记录:程序、分数、执行反馈、parent-child 关系、prompt、模型选择和中间产物。
程序的结构-参数分解
论文将程序 $p$ 分解为结构 $s$ 和超参向量 $\theta \in \Theta_s$,即 $p = s(\theta)$。固定结构 $s_0$,对 $\theta$ 做贝叶斯优化得到调参上界:
$$f^{\star}_{\mathrm{BO}}(s_0) = \max_{\theta} f(s_0(\theta))$$
调参间隙(tuning gap)衡量进化增益中多少来自结构发现而非参数搜索:
$$\Delta(s_0) = f^{\star}_{\mathrm{evo}} - f^{\star}_{\mathrm{BO}}(s_0)$$
如果 $\Delta(s_0)$ 很小,说明进化运行的大部分增益可以通过对单个中间程序做超参优化来替代——进化搜索做的事情和简单调参没太大区别。
EvoTrace:统一 trace 模式
不同框架记录的搜索状态各不相同,直接跨系统比较很困难。EvoTrace 将每次运行规范化为统一 JSONL schema,覆盖:
- 运行级元数据
- 候选程序(完整源码,byte-identical)
- 评估器输出(原始执行日志、错误、时间、任务指标)
- Parent-child 边 + 操作符标签
- LLM 生成时看到的 prompt 和上下文
- 重放环境(可对原始评估器重新运行)
记录完整源码(而非仅分数日志)是关键设计选择——它使得 BO baseline 的 literal 提取、cycling 分类器和同 prompt 重放都成为可能。
EvoReplay:四大能力
(a) 静态分析
将不同后端规范化为统一的 per-edit 表(parent, child, prompt, score, diff)。LOC、超参数量、谱系深度、best-so-far 轨迹——所有框架一套代码路径。
(b) LLM-as-judge 标注
对每个 parent-child diff 请求 LLM judge 返回编辑类别 + 驱动分数变化的行标签。支持批处理、重试、schema 验证、缓存。换 judge 模型不需重跑搜索。
(c) BO 调参基线
一次 LLM 调用识别可调常数 → 自动改写为 PARAMS 块 →
gp_minimize 24 次评估。隔离结构 vs. 参数成分。
(d) 突破稳定性分析
对任何候选程序,用原始或替换模型重新执行其保存的生成 prompt,$n=10$ 次重采样。失败模式是双峰分布而非高斯——因此用 (parse success) × (eval success) × (score conditional on success) 三元组来总结。
9 种编辑类型分类法
作者通过手动检查跨框架、语言和模型采样的 parent-child 编辑,归纳出 9 种反复出现的编辑类型,迭代直到不再出现新类别:
修改数值常量,如学习率、迭代次数、阈值
小范围局部修改,非数值
改变算法结构,如 14-gon → 2×7-gon
引入新库/依赖
优化计算效率
组合多个策略/组件
修复错误
删除冗余代码/逻辑
重构,不改变行为
算法流程 / 方法
EvoReplay 工作流
EvoReplay 的核心思想是把被动日志变成实验对象:搜索图中的任意一点都可以被重新执行、扰动、调参或重新评判。
数据收集流程:
- 选择任务(6 个数学构造 + 10 个 C++ 竞赛编程)
- 选择框架(OpenEvolve / GEPA / EvoX / ShinkaEvolve)
- 选择 LLM(deepseek-reasoner / claude-sonnet-4-6 / claude-haiku-4-5 / gemini-3-flash / deepseek-chat)
- 运行 100 次搜索迭代
- 记录完整 trace → 规范化为统一 JSONL schema
- 用 EvoReplay 做静态分析、LLM-as-judge 标注、BO 调参、重放稳定性测试
BO 调参基线流程
-
Knob 识别:一次
deepseek-reasoner调用,识别目标程序中的可调数值常量,提议每个 knob 的 log/linear 区间 -
自动改写:将程序改写为顶层
PARAMS块 -
BO 循环:
gp_minimize24 次调用(8 次随机 + 16 次 BO 采集),使用相同的评估器 harness
Cycling 检测器
对每个 parent-child diff,确定性检查:新增的行中,有多少是同一谱系之前已删除过的 byte-identical 行? 这是一个纯确定性、可复现的检测器,不依赖 LLM。
实验设计
四个维度
| 维度 | 配置 | 说明 |
|---|---|---|
| 框架 | OpenEvolve, GEPA, EvoX, ShinkaEvolve | Archive-based / 反思式 prompt 进化 / Meta-evolution / Bandit 搜索 |
| 模型 | deepseek-reasoner, claude-sonnet-4-6, claude-haiku-4-5, gemini-3-flash, deepseek-chat | 覆盖 reasoning/non-reasoning、多供应商 |
| 任务 | 6 个 Python 数学 + 10 个 C++ ALE-bench | 数学构造(circle packing, Heilbronn, autocorrelation...)+ 竞赛编程(ahc008–ahc046) |
| 迭代 | 100 次/run | 有/无 diff-based generation 两种模式 |
四类诊断实验
§5.1 静态分析
LOC/超参数量随时间的变化、谱系深度、预算利用率、编辑分类法的频率 vs. 效用视图、ALE 公私分泛化
§5.2 Cycling 检测
确定性检测:新增行中有多少是之前删过的?span 长度分布、跨框架/语言/模型稳定性
§5.3 重放稳定性
36 个 best-so-far 事件,每个用原始 prompt 重放 10 次:parse/eval/exact-match/score 四问
§5.4 调参间隙
36 个中间程序,每个做 24 次 BO 调参,比较 BO 上界 vs. 进化运行最终最优
实验结果
1. 程序形态变化:数学任务增长,ALE 任务原地修改
谱系深度短:最终最优回到种子的 parent 链——ALE 中位数 4,数学中位数 6。"Jackpot-then-flat" 模式主导:大部分迭代预算花在不贡献最终最优的死分支上。数学任务中 best-so-far 在 75% 预算时达到,ALE 更早(49%)。
2. 公私分泛化:ALE 公开分数不可信
关键发现:在 ALE-bench 上重新评估公开 best-so-far
链在 AtCoder 私有测试集上的表现,四个框架中有两个在至少 30% 的问题上过拟合。同一问题可以跨框架翻转泛化符号:在
ahc024 上,OpenEvolve 私有增益 +1,606,而 ShinkaEvolve
在同一问题上损失了 1,610 分——尽管公开分数变化为正。
3. 编辑分类法:频率 ≠ 效用
最常改善单次编辑的类别(External dependency, Efficiency, Architectural change)不是进化搜索花最多精力做的类别(Hyperparameter tuning, Local refinement)。大部分分数增益来自一小撮编辑类型,而那一小撮在搜索分布中很稀少。
LLM-as-judge 标注与人类盲标的一致性:macro $\kappa = 0.77$,micro-$F_1 = 0.90$,exact-match 74.5%。编辑通常多标签(67.4% 有 ≥2 个标签),最常见组合是 Hyperparameter tuning + Local refinement 和 Composition + Hyperparameter tuning。
4. Cycling:~30% 的新增代码是之前删过的
进化搜索中约 30% 的新增代码行是与同一谱系之前删除行 byte-identical 的重新引入。该比率在 121 次运行中的 118 次中单调增长(中位数 per-iteration 斜率 +0.0030)。这不是晚期病态——在几乎所有运行的整个轨迹中都存在。中位数 span 仅 5 次迭代(短周期 churn)。跨全部四个框架、两种语言、五个模型稳定。
5. 重放可复现性:结构可复现,词法不可复现
| Target | Parse | Eval | Exact | Replay/Orig. | Pattern |
|---|---|---|---|---|---|
| 中位数(36 targets) | 1.00 | 1.00 | 0.00 | 0.76 | — |
circle_packing_iter68_improve |
1.00 | 1.00 | ≥0 | ≈1.00 | 紧密复现 |
second_autocorr_iter79_improve |
1.00 | 1.00 | 0.00 | 0.96 | parent-revert |
circle_packing_iter32_neutral |
0.50 | 0.50 | 0.00 | — | 双峰失败 |
heilbronn_convex_iter100_regress |
1.00 | 1.00 | 0.00 | 1.11 | 重放超越退化 |
重放几乎总能产生可运行的程序(parse 和 eval 成功率中位数 1.00),但几乎从不产生原始程序(exact-match 中位数 0.00)。然而它们从不同程序中恢复了中位数 0.76 的原始分数:分数增益从同一 prompt 上下文广泛可复现,但具体程序只是更宽分布中的一次采样。
6. 调参间隙:BO 24 次就能匹配进化 100 次的最终最优
| BO 结果 | # targets |
|---|---|
| BO 改善原始分数 | 22 |
| 无变化 | 8 |
| BO 退化 | 6 |
| 总计 | 36 |
与进化运行的最终最优比较时,BO 在 15 个中间程序中的
13 个上匹配或超越(中位数 delta +0.025)。最大个案:heilbronn_tri_dsr_nodiff
上进化达到 0.521,而 BO 从同一运行的中间程序达到
0.886(1.70× 进化最终最优)。
在数学任务上,对单个中间程序做 24 次 BO 调参就能在 13/15 的中间程序上匹配或超越进化运行 100 次迭代的最终最优。晚期进化迭代在数学上很大程度上可以被事后超参调优替代。
我的评论
亮点
- 问题定位精准:在所有人追逐"进化编码代理又刷了新高"的时候,这篇论文问了一个更本质的问题——你到底在进化什么?这种 diagnostic 视角在当前 LLM+进化搜索热潮中非常稀缺。
- EvoTrace 数据集本身有独立价值:121 次运行、10,672 个程序、完整 parent-child 图、prompt、分数——这不是另一个 benchmark,而是一个可重放的分析基础设施。未来研究进化编码的论文都应该在这个数据集上报告 trace 级指标。
- Cycling 发现非常 striking:30% 的代码行是删了又加回来的,而且 118/121 次运行中单调增长。这是一个确定性、可复现的信号,不依赖任何 LLM 判断。这个发现让人质疑"进化"这个隐喻是否准确——更像是"带遗忘的随机游走"。
- 频率≠效用的分离分析是论文最精彩的洞察之一:搜索花最多时间做的事情(超参微调)恰恰是每编辑效用最低的,而真正有效的编辑类型(引入新依赖、效率优化、架构变更)在搜索分布中很稀少。这对搜索策略设计有直接指导意义。
- LLM-as-judge 的验证很扎实:200 个编辑的盲人类标注,macro κ=0.77,并诚实报告了 external_dependency 的失败案例。
局限与疑问
- 任务覆盖有限:只有数学构造和竞赛编程两类。GPU kernel 优化、编译器启发式、科学发现等更复杂的场景是否会展现不同动态? Cycling 率在更复杂代码上是否一样高?
- 100 次迭代是否足够?论文承认谱系深度短(4-6),大部分预算花在死分支上。如果给 1000 次迭代,structural discovery 的比例是否会上升?当前结论可能低估了长期搜索中结构创新的潜力。
- BO 基线的设计选择:24 次 gp_minimize 调用、用 deepseek-reasoner 识别 knobs——这些选择本身可能影响 $f^{\star}_{\mathrm{BO}}$ 的估计。更激进的 BO(更多调用、更好的 knob 识别)可能进一步压缩 tuning gap。
- Cycling 的因果机制不明:论文检测到了 cycling 现象并量化了其普遍性,但没有深入解释为什么 LLM 会反复引入和删除相同代码。是因为 prompt 中不包含删除历史?还是 LLM 本身的生成偏差?论文建议了 "deletion-aware novelty filters",但没有实验验证。
- ALE 过拟合的结论基于 30 个 run/problem 对,部分问题只有少量框架运行。过拟合率的置信区间可能比较宽。
对实践者的启示
- 报告数学 benchmark 分数时,应同时报告单程序调参上界 $f^{\star}_{\mathrm{BO}}(s_0)$,让结构 vs. 参数的分解可见
- ALE 上公开分数必须配对私有测试重评,否则过拟合不可见
- 搜索策略应考虑 lineage-aware credit assignment、deletion-aware novelty filters、向 prompt 暴露 parent 的删除历史——防止搜索重做已丢弃的工作
- 不要只看最终分数;trace 级指标(cycling 率、编辑类型分布、谱系深度)才是诊断搜索健康度的正确工具
One More Thing
论文中一个容易被忽略但很有深意的观察:重放几乎从不产生原始程序,但通常恢复大部分分数(中位数 0.76)。这意味着 LLM 驱动的进化搜索中的"突破"不是一个程序,而是一个结构概念在程序空间中的多次采样。突破的是 prompt + context 对应的结构邻域,不是具体的代码实例。
这暗示了一个有趣的方向:如果我们接受"程序只是结构概念的一次采样",那么进化搜索的真正单位应该是结构概念的转移而非程序的继承。当前的 parent-child 图可能不是搜索动力学的正确描述——我们需要的是 concept-level lineage 而非 program-level lineage。这与程序感知多样性/相似性度量(论文引用的 Vendi Score、code similarity 工作)形成呼应,但走得更远:搜索空间不是程序空间,而是程序背后的策略/概念空间。
Reference / Evidence
arXiv:2605.20086 — What Do Evolutionary Coding Agents Evolve?
arXiv HTML — 实验性全文 HTML 版本
ZIB-IOL/EvoReplay — 开源分析与重放工具包
HuggingFace: ZIB-IOL/EvoTrace — 121 次进化搜索运行 trace
arXiv PDF — 28 pages, 12 figures, 12 tables
arXiv TeX Source — CC BY 4.0 许可