Что эволюционируют ИИ-агенты кода: разбор 121 запуска
FunSearch нашёл новые верхние границы для комбинаторных задач. AlphaEvolve улучшил алгоритмы матричного умножения. AIDE и OpenEvolve показывают всё лучшие результаты на соревнованиях по программированию. Заголовки впечатляют: LLM-агенты эволюционируют код, открывают алгоритмы и побеждают человека в математике. Но что происходит внутри этих запусков на самом деле?
Команда исследователей из Берлинского технического университета и DFG Cluster of Excellence MATH+ собрала EvoTrace — датасет из 121 полного эволюционного запуска, охватывающих четыре фреймворка (OpenEvolve, GEPA, ShinkaEvolve, EvoX), пять LLM и шестнадцать задач. Затем они построили EvoReplay — инфраструктуру, которая позволяет не просто смотреть на финальный счёт, а воспроизводить, перенастраивать и вмешиваться в любой момент поиска. Результат развенчивает несколько иллюзий об эволюционном программировании.
Что такое эволюционные агенты кода
Эволюционный агент кода — это система из четырёх компонентов: спецификация задачи и исполняемый оценщик, популяция или архив кандидатов, одна или несколько LLM, которые генерируют мутации, рекомбинации и уточнения программ, и поисковая процедура, которая выбирает, какие программы и контексты пойдут в следующее поколение. Поисковая траектория — это полная запись всего, что произошло: сгенерированные программы, оценки, обратная связь от исполнения, родительско-дочерние связи, промпты, выбор моделей и промежуточные артефакты.
Проблема в том, что существующие работы почти всегда сообщают только финальный лучший счёт, агрегированный процент успеха или пару иллюстративных траекторий. Такие конечные точки скрывают пути и механизмы, через которые возникают улучшения. Когда агент показывает +15% к baseline, это может означать новую алгоритмическую структуру, перенастройку существующей стратегии, рекомбинацию идей, уже присутствующих в знаниях модели, или переобучение под оценщик. Различать эти механизмы невозможно, не заглянув внутрь самого процесса поиска.
Масштаб эксперимента
EvoTrace охватывает 121 запуск, в ходе которых сгенерировано 10 672 программы, выполнено 10 479 редактирований и сделано 18 400 вызовов к языковым моделям. Совокупный объём промптов составил 274,7 миллиона токенов, а ответов — 80,3 миллиона. Медианное число программ на запуск — 101, вызовов LLM — 134, промпт-токенов — 1,7 миллиона. Это не игрушечный бенчмарк, а масштабная инфраструктура, способная уловить систематические паттерны.
Задачи разделены на два домена: математические конструкции на Python и соревновательное программирование на C++ через платформу ALE-bench (задачи ahc008–ahc046). Математические задачи поощряют новые алгоритмы поиска, тогда как соревновательные требуют, чтобы программы компилировались и проходили внешнее судейство с ограниченным доступом к оценщику. Разные фреймворки ведут разные логи, поэтому прямое межсистемное сравнение затруднено — EvoTrace решает это через унифицированную схему и воспроизводимые среды.
Как устроены EvoTrace и EvoReplay
EvoTrace нормализует каждый запуск в шесть типов объектов: сами запуски с метаданными, программы с родительскими связями, вызовы LLM с полными промптами и ответами, оценки от исполнения, логи выполнения и промежуточные артефакты. Это позволяет задавать вопросы, которые невозможно решить, имея только таблицу «итерация — счёт»: сколько поколений назад появился предок финальной программы, какие именно изменения привели к прорыву, воспроизводится ли результат при повторном запуске с тем же промптом.
EvoReplay превращает пассивный лог в экспериментальный объект. Любая точка поискового графа может быть переисполнена, возмущена, перенастроена или переоценена, а результат сравнен с оригинальным запуском. Исследователи используют это для четырёх типов анализа: статического анализа траекторий, аннотации типов изменений через LLM-as-judge, байесовской оптимизации для изучения роли гиперпараметров и стабильностного анализа прорывных событий.
Девять типов изменений и где они встречаются
Каждое изменение кода в EvoTrace аннотировано одним из девяти повторяющихся типов: перенастройка гиперпараметров, удаление компонентов, архитектурное изменение, локальное уточнение, композиция, исправление ошибки, оптимизация эффективности, добавление внешней зависимости и рефакторинг. Аннотация проводилась через LLM-as-judge с валидацией против слепой человеческой разметки — межаннотаторное согласие оказалось высоким.
Ключевой вывод: большинство прироста счёта приходит из малого подмножества этих типов. Не все изменения равнозначны, и эволюционный поиск не равномерно исследует пространство улучшений. Некоторые типы изменений — вроде локального уточнения или перенастройки констант — доминируют в траекториях, тогда как архитектурные изменения встречаются реже, но дают более значимые прорывы. Это означает, что эволюционный поиск часто «тащит» программу через множество мелких правок, вместо того чтобы сделать одно структурное изменение.
Циклический возврат: 30% кода — это дежавю
Самый неожиданный результат исследования — детерминированный циклический паттерн. Примерно 30% строк кода, добавленных в ходе поиска, являются байт-в-байт идентичными реинтродукциями ранее удалённых строк. Эта доля устойчиво растёт по траектории запуска и присутствует в 118 из 121 запусков. Эволюционный агент не просто исследует новое пространство — он регулярно возвращается к уже отвергнутым решениям.
Почему это происходит? LLM генерирует мутации на основе текущего контекста, и если контекст включает родительскую программу с определённой структурой, модель склонна воспроизводить знакомые паттерны даже после их удаления. Отсутствие долговременной памяти о том, что уже пробовалось и не сработало, приводит к повторному введению неудачных фрагментов. Это не случайный шум — это систематическая неэффективность, которая съедает треть поискового бюджета.
Интересно, что доля циклического возврата растёт по мере продвижения запуска. В начале поиска модель ещё исследует новые идеи, но по мере истощения «свежих» вариантов всё чаще возвращается к уже виденному. Это создаёт эффект «застревания» в локальном минимуме не на уровне параметров, а на уровне кода: агент кружит вокруг одних и тех же конструкций, добавляя и удаляя их в разных комбинациях.
Прорывы не воспроизводимы байт-в-байт, но структурно восстанавливаются
Когда исследователи пытались воспроизвести прорывные программы, повторно запуская тот же промпт с тем же контекстом, результат почти никогда не совпадал байт-в-байт с оригиналом. Однако структурный прирост счёта типично восстанавливался из другой программы. Траектория несёт структурный выигрыш, а конкретная программа — лишь одна выборка из более широкого распределения.
Это имеет важное методологическое следствие. Финальный лучший результат эволюционного запуска — не уникальный артефакт, а случайная реализация из класса эквивалентных по качеству программ. Сравнение двух фреймворков по одному запуску каждого статистически ненадёжно: разница в счёте может отражать не превосходство метода, а дисперсию сэмплирования. Чтобы сравнивать фреймворки корректно, нужно множество запусков и анализ распределений, а не точечные оценки.
Короткие родословные и мёртвые ветви
Цепочка родителей от финальной лучшей программы до начального семени коротка: медианная глубина родословной составляет около пяти поколений на математических задачах и ещё меньше на задачах ALE. При этом доминирующий паттерн — «джекпот-плато»: большая часть итерационного бюджета тратится на мёртвые ветви, которые не вносят вклад в финальный лучший результат. Эволюционный поиск эффективен в нахождении хороших решений, но крайне неэффективен в использовании вычислительного бюджета.
На математических задачах медианный лучший результат достигается примерно на 40% бюджета, а на ALE — ещё раньше, около 25%. Оставшиеся 60–75% итераций тратятся на эксперименты, которые не улучшают финальный результат. Это не означает, что они бесполезны — некоторые из них могли бы привести к ещё лучшему решению, если бы поиск продолжался. Но в рамках фиксированного бюджета большая часть вычислений оказывается «пустой» с точки зрения финального счёта.
Тюнинговый потолок: сколько прогресса — просто подбор параметров
На математических бенчмарках исследователи применили байесовскую оптимизацию к одной промежуточной программе из середины запуска, варьируя открытые гиперпараметры. BO достигла или превзошла финальный лучший счёт эволюционного запуска на большинстве промежуточных программ. На этих задачах поздние итерации эволюционного поиска в основном выполняют параметрическое уточнение, которое в значительной степени заменимо пост-хок настройкой.
Это предполагает естественную декомпозицию работы, которую выполняет эволюционный запуск: структурные изменения в начале запуска и параметрическое уточнение этих структур позже. Если параметрическую часть можно вынести в отдельный оптимизатор, эволюционный поиск может сосредоточиться на том, что он делает уникально — генерации новых алгоритмических идей. Такое разделение труда потенциально ускоряет поиск и снижает стоимость в токенах.
Переобучение на публичных оценках
На задачах ALE-bench публичные оценки не совпадают с финальным скрытым судейством. Два из четырёх фреймворков показали переобучение как минимум на четверти задач: публичный счёт рос, а приватный — падал. Это означает, что часть «успеха» эволюционного поиска на соревновательных платформах — артефакт утечки через публичный оценщик, а не реальное улучшение алгоритма.
Проблема усугубляется тем, что эволюционный поиск оптимизирует именно публичный счёт, поскольку только он доступен во время поиска. Агент учится эксплуатировать особенности публичного оценщика — например, конкретные тестовые случаи или паттерны входных данных — вместо развития обобщающейся стратегии. Это классическая проблема overfitting, перенесённая на уровень алгоритмического поиска.
Часто задаваемые вопросы
Почему 30% циклического возврата — это проблема, а не просто исследование пространства?
Потому что речь идёт о байт-в-байт идентичных строках, которые уже были удалены как неэффективные. Настоящее исследование пространства предполагает новые комбинации, а не повторное введение отвергнутых фрагментов. Это систематическая неэффективность, а не случайный шум.
Значит ли это, что эволюционные агенты бесполезны?
Нет. Они находят прорывные решения в задачах, где человеческий интуитивный поиск застопорился. Но их текущая реализация неэффективна: треть бюджета тратится впустую, прорывы не воспроизводимы, а часть успеха — переобучение. Понимание этих ограничений — первый шаг к улучшению.
Как можно улучшить эффективность эволюционного поиска?
Три направления: добавить память о ранее отвергнутых изменениях для предотвращения циклов, разделить структурную генерацию и параметрическую настройку на разные этапы, и использовать более надёжные оценщики для ранней фильтрации переобучения.
Итог
Эволюционные агенты кода произвели впечатляющие результаты, но их внутренняя динамика оказалась гораздо менее элегантной, чем финальные счёта. 30% поискового бюджета уходит на возврат уже удалённого кода. Прорывы невозможно воспроизвести байт-в-байт. Большая часть итераций — мёртвые ветви. А часть успеха на соревнованиях — переобучение под публичный оценщик.
Работа с EvoTrace и EvoReplay показывает, что диагностика эволюционного поиска требует не финальных счетов, а полных трасс. Только прозрачность внутренней динамики позволит отделить настоящие алгоритмические открытия от статистических артефактов и построить следующее поколение агентов, которые будут не просто удачливы, а по-настоящему эффективны.