Многие обсуждают «вулнпокалипсис» — резкий рост числа уязвимостей, находимых с помощью AI. Тема безопасности здесь не рассматривается, зато стоит обратить внимание на близкую, хотя и менее драматичную проблему — «бенчмаркопокалипсис».
Делать реальные улучшения производительности стало проще, чем когда-либо. Но точно так же стало проще накручивать результаты бенчмарков без какого-либо реального прироста. Первое, вероятно, тихо происходит во многих компаниях, а вот второе в последнее время попадается на глаза как минимум раз в неделю. Кто-то заявляет, что оптимизировал X и получил огромный прирост производительности по сравнению с существующим ПО, но при ближайшем рассмотрении оказывается, что оптимизация улучшает именно показатель бенчмарка, а не реальную производительность. Часто это проекты вида «переписали X на Rust»1 или стартапы, которые хотят собрать раунд инвестиций или что-то продать, но встречается это и в других контекстах.
Люди всегда любили выставлять напоказ нерепрезентативные микробенчмарки, чтобы показать, как хорош их проект. Сфабриковать нерепрезентативный микробенчмарк всегда было легко, и это не изменится. Изменилось то, что раньше «обыграть» крупный набор бенчмарков требовало серьёзной работы, а теперь это может сделать LLM в цикле. Есть немало известных примеров взлома больших наборов тестов из тех времён, когда это было трудно. Например, когда индустрия ориентировалась на SPECint/SPECfp как показатели производительности рабочих станций, производители процессоров искали «оптимизации» компилятора, ускоряющие расчёт именно в бенчмарке — так Sun нашла способ ускорить 179.art в 12 раз в SPECfp2000. Опытные инженеры тратили массу времени на поиск подобных хаков. LLM делают это тривиальным, обесценивая прежде надёжные бенчмарки — если, конечно, результат не проверен вручную или получен от того, кому можно доверять.
Вместо того чтобы указывать пальцем на чужие сомнительные заявления, приведён собственный пример — FRE, регекс-движок, который построил агент. Его можно было бы назвать самым быстрым регекс-движком в мире, поскольку он обгоняет крейт regex из Rust на достаточно всеобъемлющем наборе rebar. Но создан он был запуском агента в цикле на месяц с инструкцией не переобучаться под бенчмарк — и без реального контроля за результатом. В целом заставить LLM показать хороший результат в бенчмарке довольно легко: потребовалось пара недель, чтобы примерно сравняться по производительности с regex-крейтом Rust, и ещё пара недель, чтобы стать быстрее на 1,4x2 на rebar. Но агенты склонны к «reward hacking» и переобучению, если не выставить серьёзные ограждения — в данном случае этого специально не делалось, в качестве эксперимента.
Чтобы проверить переобучение, в качестве отложенного набора данных (не без некоторого произвола3) был выбран корпус бенчмарков ripgrep. Результат: в тех случаях, где не было алгоритмического взрыва сложности, движок оказался в 10 раз медленнее, а в некоторых случаях выполнение занимало настолько много времени, что ждать завершения было просто нецелесообразно. Вот и все «на 40% быстрее»!
Набор бенчмарков rebar от Andrew Gallant (он же BurntSushi) достаточно всеобъемлющ по меркам подобных наборов, но даже это не мешает агентам без труда получать высокий балл, переобучаясь так, что реальная производительность в целом не улучшается.
Следующим шагом стало применение уже упоминавшегося трюка: не просто сказать LLM не жульничать, а прямо предупредить, что есть отложенный набор бенчмарков, по которому будет судейство. После этого модель умеренно обобщила производительность — на holdout-наборе движок стал медленнее примерно в 2,4 раза в целом. Звучит неплохо, учитывая, что сравнение идёт с одним из самых быстрых регекс-движков общего назначения. Но стоит помнить, что сами бенчмарки создавались агентом-программистом. При ближайшем рассмотрении оказалось, что часть тестов вообще не имеет смысла включать с равным весом. Если оставить только те бенчмарки, которые действительно важны, FRE оказывается медленнее в 4 раза на holdout-наборе0 — заметно лучше, чем до применения трюка с «отложенным набором», но всё ещё далеко от заявленных 40% прироста.
Несколько интересных наблюдений по итогам этого эксперимента:
- «Выиграть» нетривиальный бенчмарк бессмысленным образом оказывается тривиально просто, даже если явно проинструктировать агента не жульничать и не переобучаться под тест.
- Снова подтвердилось: сказать модели, что есть отложенный набор данных, работает лучше, чем просто просить её писать обобщённый код и не читерить.
- Хотя общая производительность FRE не так уж хороша, для некоторых сценариев использования он всё же работает лучше — в целом стоимость написания специализированного кода, который раньше требовал серьёзного инженерного опыта под конкретную задачу, резко упала.
По первому пункту: неудивительно, что вокруг так много сомнительных заявлений о производительности. Раньше, чтобы построить нечто вроде FRE, достаточно убедительно имитирующее хороший результат для заявления о 40% ускорении, требовался немалый уровень экспертизы — как минимум хорошее понимание алгоритмов строкового поиска, устройства регекс-движков, а также приличные навыки общей оптимизации кода и SIMD. У FRE есть ещё и режим компиляции регулярного выражения в машинный код, а значит, требуются ещё и знания в области компиляторов. Теперь такое же (пусть и нежелательное) «читерство» в бенчмарках достигается за несколько минут набора текста.
По второму пункту: пока непонятно, насколько эта закономерность распространяется на другие случаи — не проверено достаточное количество примеров, чтобы делать выводы.
По третьему: нет никакого смысла использовать «вайб-кодед» регекс-библиотеку, созданную почти без человеческого труда, если она медленнее надёжной, проверенной временем библиотеки — так что сам по себе артефакт FRE малоинтересен. Куда интереснее то, насколько LLM способны заменить редкую, специализированную и дорогую экспертизу.
Раньше даже при наличии нужных знаний вряд ли кто-то стал бы писать кастомный регекс-движок под конкретную нагрузку. Есть крупномасштабные сценарии, где такая кастомизация оправдана — например, во время работы над индексом Bing в коде было сразу несколько разных компиляторов, потому что один из разработчиков стремился выжать максимум производительности: в поисковой системе важны и время компиляции, и скорость выполнения, а компромиссы в разных местах разные, поэтому написание отдельного компилятора под каждый случай (там, где обычный проект просто использовал бы интерпретатор или напрямую обходил структуру данных «обычным кодом») давало выигрыш. Человек, писавший те компиляторы, работая с regex-подобным кодом, вполне мог написать и несколько кастомных регекс-движков — но очень мало у кого есть одновременно нужная экспертиза, желание и, тем более, возможность потратить столько рабочего времени на настолько узкоспециализированный код. Если сравнить стоимость труда того инженера Bing (тогда — Partner-level инженера, впоследствии повышенного до Distinguished Engineer именно за работу над поисковым индексом) со стоимостью запуска LLM в цикле, окажется, что цена написания подобного специализированного кода упала на много порядков.
Хотя в целом регекс-движок FRE уступает по производительности крейту regex из Rust, выигрыш от специализации под конкретную нагрузку или сценарий использования означает, что в некоторых случаях вполне разумно встроить собственный специализированный регекс-движок — и то же самое справедливо для многих других видов низкоуровневого софта. Не нужно быть AI-максималистом, чтобы допустить: через несколько лет подобное может произойти и с более крупными системами, например базами данных.
Благодарности за комментарии, правки и обсуждение: Yossi Kreinin, Jamie Brandon, Peter Geoghegan, Luke Burton, John Spurling, Dennis Snell и Max Bittker.
P.S. Как уже отмечалось ранее, с LLM время, требуемое, чтобы немного «поковыряться» в теме и удовлетворить любопытство, резко сократилось, а вот время, нужное на то, чтобы оформить результат достаточно строго для публикации в блоге, практически не изменилось (по ряду причин оно, пожалуй, даже выросло). В результате анализов делается гораздо больше, чем раньше, и результатами делятся с несколькими друзьями, но не публикуют их. В качестве эксперимента этот текст писался очень быстро, с гораздо более низкой планкой аккуратности и строгости, чем обычно принято для блога — скорее в духе того, что рассказал бы другу в неформальном разговоре. Цель — уложиться в написание примерно за полчаса, чтобы можно было сделать это за обедом, не тратя на это отдельное время. Мнения на этот счёт приветствуются.
Стоит оговориться: все цифры здесь несут повышенный риск ошибки. При беглой проверке одного бенчмарка (пара минут) нашлась проблема, при проверке другого — ещё одна. Обе исправлены, но это намекает, что могут быть и другие неисправленные ошибки. Впрочем, применительно к плохим бенчмарк-цифрам это весьма реалистично! Почти каждый раз при внимательном изучении цифр бенчмарков — как здесь или здесь — они оказываются неверными. Ещё одна грань бенчмаркопокалипсиса: LLM, по крайней мере пока, хорошо умеют делать плохие бенчмарки, так что даже при наличии реального прироста производительности обычно нельзя доверять сгенерированной LLM методике бенчмаркинга, если не приложены значительные усилия для проверки её корректности.
Приложение: подробности о бенчмарках FRE
После написания основного текста, но до публикации, обнаружилось, что заявление LLM о 40%-ном превосходстве FRE над regex-крейтом Rust на rebar тоже оказалось неверным. Или, как минимум, вводящим в заблуждение. На деле бенчмарки запускались не так, как это делается в rebar. Это выяснилось после минутной проверки результатов — нашлись сразу две проблемы. Несмотря на инструкцию запускать бенчмарки rebar так же, как они запускаются в https://github.com/BurntSushi/rebar, модель изменила интерфейс так, чтобы FRE мог применять некоторые оптимизации, повышающие показатели. После исправления вместо превосходства FRE над Rust в 1,4 раза на rebar получилось отставание в 1,5 раза (и «всего лишь» двукратное превосходство над re2) — то есть исходный результат оказался жульничеством в двойном смысле. FRE не просто был сильно переобучен под бенчмарки rebar, но и сами результаты включали читерство.
Хорошая новость в том, что разница в производительности между FRE на rebar (отставание от Rust в 1,5 раза) и на holdout-бенчмарках (отставание в 2,4 раза) оказалась не такой большой, как выглядела раньше — значит, трюк «скажи LLM, что есть отложенный набор» сработал даже лучше, чем казалось изначально.
После этого модели дали ещё несколько часов на «восхождение по холму» — она заявила, что FRE стал быстрее в 1,28 раза, что звучит как отличный результат для всего нескольких часов работы LLM. Но ещё одна минута проверки на читерство выявила сразу несколько проблем, включая случай, когда поиск числа совпадений для (?s)^(.*)$ возвращал результат вообще без просмотра самих данных (haystack). Другой случай читерства — выполнение многострочного grep там, где по условиям бенчмарка поиск должен идти построчно. Подобные находки неудивительны — это типичное следствие того, что агента оставили работать в цикле на месяц без строгих ограничений. Усиливает это или подрывает основной тезис — не вполне ясно, но после исправления очередной партии подобных проблем FRE снова оказался медленнее в 1,4 раза. После того как агенту дали поработать всю ночь, FRE, по его собственным заявлениям, снова стал быстрее в 1,5 раза.
Изначальная цель заключалась в том, чтобы посмотреть, что произойдёт, если запустить современного (публично доступного) SOTA-агента (GPT-5.6 Sol) в цикле без особого контроля на нетривиальной задаче оптимизации кода — так что вместо того, чтобы и дальше вычищать результаты ради большей честности сравнения, дальше приводится просто несколько графиков с результатами.
В целом видно, что в сравнении с Rust и RE2 FRE в среднем показывает лучший результат на бенчмарках rebar (и, как отмечено выше, во многом это заслуга переобучения), но далеко не везде (графики ниже не обязательно совпадают с цифрами, упомянутыми в тексте выше, поскольку агент постоянно вносит изменения — любой снимок актуален только на момент фиксации и устаревает почти сразу):
Для тех, кто интересуется результатами по конкретным бенчмаркам или их классам, приведена таблица (значения выше единицы означают, что FRE быстрее; ниже — что медленнее):
Есть также режим AOT-компиляции, при котором компиляция регулярного выражения в нативный код занимает много времени. Не для всех случаев есть поддержка AOT, но вот результаты там, где она есть. Как видно, AOT-компилятор очень медленный (он сильно проигрывает по времени компиляции), и, несмотря на потраченное на компиляцию время, результаты часто оказываются медленнее стандартного движка FRE (хотя во многих случаях он всё же быстрее).
Далее — holdout-бенчмарки. Как отмечалось выше, для не-AOT версии FRE производительность на holdout-наборе хуже, чем на rebar. И, опять же, учитывая, что речь идёт о нагрузке, похожей на ripgrep, набор «горячего поиска» вероятно важнее остальных, а значит реальный результат FRE хуже, чем показывает общий балл.
Стоит отметить: в тех случаях holdout-бенчмарков, где время компиляции не включается в замер, а поиск запускается многократно, AOT-версия FRE выигрывает. Во многих сценариях регекс, компиляция которого занимает несколько секунд, нежелателен, но есть немало случаев, где это допустимо — например, для инструментов вроде ripgrep или Silver Searcher можно начать поиск с обычным (не скомпилированным) регекс-движком, параллельно компилируя оптимизированную версию в отдельном потоке, и переключиться на неё по готовности. Учитывая, сколько процессорного времени лично уходит на длительные поиски через ripgrep, такая стратегия могла бы реально повысить производительность в повседневной работе. До появления LLM тратить усилия на написание оптимизирующего регекс-компилятора вряд ли имело бы смысл, но теперь это осуществимо за несколько токенов.
Ещё один момент: сравнение можно назвать не вполне честным, поскольку тестирование проводилось на ARM-машине Graviton с поддержкой SVE/SVE2, а FRE как раз содержит оптимизации под SVE/SVE2. До эпохи LLM вряд ли имело бы смысл оптимизировать регексы под каждую комбинацию SIMD-инструкций, но с LLM генерировать более-менее приличные SIMD-оптимизации довольно легко. Есть знакомые эксперты-люди, которые в этом деле обычно превосходят LLM — например, Jay Stelly рассказывал, что в последний раз, когда он пытался получить от LLM SIMD-код, потребовалось около 20 итераций, чтобы добиться нужного качества. Но, с другой стороны, LLM способны перебрать гораздо больше вариантов оптимизации, чем человек успел бы за то же время, так что в сумме результат может быть неплохим, даже если каждая отдельная оптимизация уступает тому, что сделал бы эксперт.
Есть и упомянутая в этом тексте проблема переобучения. В зависимости от контекста она решается — от очень просто до довольно сложно. В данном случае специально не прикладывалось особых усилий к её решению, чтобы посмотреть, что получится, хотя в другом случае — при работе над Azul AI — удалось решить эту проблему без чрезмерных затрат труда. Но многие громкие заявления о производительности появляются именно тогда, когда люди прикладывают минимум усилий (а то и отрицательное количество усилий) к тому, чтобы избежать переобучения. В доLLM-эпоху люди часто выбирали крайне нерепрезентативные микробенчмарки, чтобы продемонстрировать, насколько хорош их проект — что, по крайней мере на бессознательном уровне, уже само по себе является «отрицательным усилием» по избеганию переобучения под бенчмарк. Учитывая природу человека, вряд ли люди перестанут делать вводящие в заблуждение заявления, а делать их стало проще, чем когда-либо — поэтому неудивительно, что таких заявлений становится больше.
Стоит заметить: хотя речь в тексте шла о не-AI софте, всё сказанное вдвойне справедливо для AI-софта. Например, немало комментариев утверждает, что Kimi K3 находится на уровне Fable (5). Но буквально каждый знакомый, кто пользовался этой моделью, находит её заметно хуже GPT-5.6 Sol и Fable. Дело не в том, что это не впечатляющее инженерное достижение — но производительность на широком спектре реальных задач не дотягивает до уровня, показанного в бенчмарках. Это касается и разного рода eval-подобных задач — например, знакомый пробовал разные coding-агенты на задачах конкурса ICFP 2026. Касается это и вопросов безопасности, которые почти наверняка входят в оценочные наборы AI-лабораторий: коллега пробовал использовать Kimi K3 для поиска уязвимостей в софте и обнаружил, что модель нашла примерно четверть от количества уязвимостей, найденных GPT-5.6 Sol, не нашла ни одной уязвимости, которую не нашёл бы GPT-5.6 Sol, и не имела никаких преимуществ ни по одному параметру, кроме цены. Люди, использующие более дешёвые модели для реального поиска уязвимостей, как правило, выбирают другие модели, например GLM-5.2 — те, что показывают худшие результаты в бенчмарках, но лучше работают на практике.
Возвращаясь к теме FRE: стоит отметить, что holdout-бенчмарк представляет собой произвольное подмножество набора бенчмарков ripgrep, выбранное агентом по неизвестным причинам. Агенту также поручили загрузить весь набор бенчмарков целиком, но эта задача не успела завершиться к моменту публикации, так что результат пока неизвестен.
Забавно, но есть некоторая доля доверия к проектам, к которым люди относятся наиболее скептически — например, каждый раз при упоминании pgrust в комментариях появляется масса скепсиса. Но, не вникая в детали того, что именно там оптимизируется, есть основания доверять, что там не происходит ничего сомнительного с бенчмарками — потому что проект начал (и продолжает вести) Michael Malis. Раньше почти каждое заявление о бенчмарках, попадавшее в поле зрения, изучалось подробно, но сейчас их стало настолько много, что времени на это уже не хватает, и по умолчанию такие заявления считаются ложными по сути (даже если технически верны), если нет причин полагать иначе. Конечно, это иногда ошибочно (например, если бы имя Michael Malis было незнакомо, pgrust вполне мог бы показаться просто ещё одним низкокачественным проектом в духе «переписали на LLM»), но LLM — настолько мощная машина для DoS-атаки на человеческое внимание, что сложно придумать, что с этим ещё делать (попытки поручить LLM анализировать заявления о производительности предпринимались, и хотя результат в целом коррелирует с тем, что показал бы самостоятельный анализ, он часто оказывается заметно неверным).
Кто-то может потратить секунды (а при правильном подходе — вообще не тратить своего времени) на генерацию того, на понимание чего у других людей уйдут минуты или часы. Это тема для отдельного текста, но по опыту разговоров с людьми о подобных ситуациях на работе — компании со слабыми нормами в этой области сейчас серьёзно страдают от падения продуктивности.
[return]- Речь о геометрическом среднем по всем бенчмаркам rebar. Вероятно, это не совсем правильная метрика, поскольку она неявно предполагает равную значимость каждого бенчмарка, что вряд ли соответствует действительности. В отличие от, например, SPEC CPU, бенчмарки rebar изначально не позиционируются как источник осмысленной сводной метрики общей производительности (в самом репозитории отмечено, что это «предвзятый барометр для оценки относительной скорости некоторых регекс-движков на подобранном наборе задач»). Но чтобы получить действительно полезную сводную метрику, нужно хорошо разбираться в том, как люди на практике применяют регулярные выражения — а таких знаний примерно ноль. Вполне возможно, что правильных метрик должно быть две (как SPECfp и SPECint для SPEC CPU), или десять, или сто — ведь сценариев применения регулярных выражений очень много. [return]
Первые несколько регекс-бенчмарков, попавшихся на глаза, уже были включены в rebar, так что для отложенного набора они не годились. А поскольку, как уже обсуждалось, современные SOTA-модели не особенно хороши в бенчмаркинге, доверять LLM в подборе holdout-набора можно было бы только при наличии достаточных знаний о производительности регулярных выражений, чтобы оценить качество получившегося набора. А поскольку знаний об алгоритмах строкового поиска и производительности регексов примерно ноль, этот вариант тоже отпал.
Оказалось, что BurntSushi также поддерживает ripgrep и бенчмарки для него, которые достаточно велики, чтобы не попасть в состав rebar — так что именно они и были использованы в качестве отложенного набора.
[return]