На днях в одном вирусном твите утверждалось, что те, кто сейчас говорит о медленном и раздутом коде, написанном с помощью LLM, ещё пожалеют об этом, когда всё придётся переписывать на «супероптимизированном» ассемблере. До момента, когда захочется писать всё на ассемблере, дело пока не дошло, но применительно к производительности всё больше подтверждается тезис, который Нолан Лоусон сформулировал про тестирование: теперь можно самому выбирать, сколько багов вы готовы терпеть — примерно то же самое, только менее изящно, отмечалось и здесь.
В комментарии к предыдущему посту прозвучал тезис о том, что стоимость ранее специализированной работы по оптимизации производительности упала на много порядков, и то, что раньше требовало команды с редким набором навыков, теперь способен сделать любой, кто умеет набрать пару предложений1. Это означает, что стали доступны всевозможные оптимизации, которые раньше были слишком дороги для чего-либо, кроме проектов самого крупного масштаба или самых прибыльных. На это откликнулся Марк Брукер:
Полностью согласен с финальным тезисом. Динамическое кастомное ПО, подогнанное под конкретную нагрузку, а не под класс нагрузок в целом, выглядит очень вероятным исходом. (Со всеми сопутствующими забавными рисками и возможностями). Напоминает FFTW. А ещё — кучу странных старых demoscene-техник, заточенных на максимальную скорость и компактность под очень конкретную задачу (и часто под очень конкретное железо). Например, помню демо, которое использовало собственный код в качестве текстур ради отличной локальности кэша.
Майкл Малис добавил:
Ходит мем о том, что ИИ не помогает, потому что «код никогда не был сложной частью». Думаю, в каких-то областях это верно, но в других написание кода как раз и было самой сложной частью. JIT-компиляторы — отличный пример. Для многих программ JIT-компилятор сильно ускорил бы код. Редкость JIT-компиляторов заставляет думать, что исторически их реализация была слишком сложной, чтобы окупаться. LLM снизили порог входа и сильно упростили написание JIT-компилятора. Это и есть тезис, лежащий в основе pgrust. Базы данных исторически были самым сложным видом ПО для разработки именно из-за этого ограничения. Теперь, с ИИ, можно быть куда амбициознее в том, какое ПО мы строим.
Оптимизация под класс нагрузок
Проверить это можно на FRE — регекс-движке из предыдущего поста. Его создал агент, месяц крутившийся в цикле улучшения производительности регекс-движка с доступом к набору бенчмарков rebar. В результате FRE сильно переобучился под rebar, пока агенту не сообщили о наличии отложенного (holdout) набора бенчмарков — после этого он обобщил оптимизации настолько, что результат на holdout стал более-менее приемлемым. Особого смысла использовать «фабричный» регекс-движок, который не превосходит хорошо протестированные движки на holdout-бенчмарках, нет, но одна вещь в FRE заслуживает внимания: нативно AOT-скомпилированная версия неплохо показывала себя на длинных поисках. Логично было бы запускать компилятор в нативный код в отдельном потоке, пока ripgrep работает со своим обычным матчером, а затем переключаться на нативный код по завершении компиляции — и в целом получать лучшую производительность. Разумеется, для коротких запросов это обычно приведёт к худшему результату, поскольку один поток уходит на компиляцию, но гораздо важнее время выполнения ripgrep при работе много секунд или минут, чем при работе пару секунд, так что этот компромисс вполне приемлем.
Точно так же, как регекс-движок был построен за несколько минут человеческого времени, этот эксперимент тоже можно провести за несколько минут. Набралось несколько предложений — и агент сделал всю работу, которая для человека вылилась бы в приличный объём хирургии над кодом, а затем прогнал бенчмарк на реальных запросах ripgrep, взятых из истории вызовов codex. На более длинных запросах здесь виден прирост производительности в 2-4 раза для нескольких очень простых запросов. Но большинство запросов сложнее, и при прогоне на представительном holdout-наборе, для запросов, где AOT должен быть включён2, получается прирост около 7%. Не оглушительный результат, но и неплохой итог для нескольких минут набора текста в codex (и он всё ещё продолжает оптимизацию, судя по всему, дальше будет только быстрее).
Построить индекс?
Пожалуй, это звучит странновато: если задача — многократный поиск текста на компьютере, очевидное решение для ускорения — не писать компилятор нативного кода для сопоставления регулярных выражений, а построить индекс. Но суть в том, что подобная техническая работа, которая раньше требовала немалого времени и экспертизы, теперь делается почти тривиально. И если уж строить текстовый индекс, то так вышло, что была работа над BitFunnel — поисковым индексом Bing, специализированным на постоянном и быстром приёме текста, получившим Best Paper Award на SIGIR, так что несколько экспериментов на тему быстрого локального индекса всей машины напрашиваются сами собой (виденные проекты, судя по всему, нацелены на индексацию директорий с кодом, но по-настоящему убивает производительность машины ситуация, когда codex решает прогнать ripgrep по огромным временным директориям с кучей сгенерированных файлов, а затем при промахе расширяет поиск на всю машину — так что нужен индекс всего диска, а не только кода отдельных проектов).
Если бы речь шла о работе в AI-лаборатории с доступом к SOTA-моделям на чипах Cerebras или других ускорителях, кратно увеличивающих tok/s и, соответственно, нагрузку на поиск, имело бы смысл сначала посмотреть на существующие индексаторы — достаточно ли они быстры, или стоит писать своё. Open source версия BitFunnel содержит «всего лишь» байткод-интерпретатор и один JIT, тогда как версия для Bing содержит несколько JIT-компиляторов. Проект такого уровня оптимизации раньше был крупным предприятием, но фраза «я бы сделал это за выходные» теперь действительно верна для некоторых подобных проектов. При скромном аккаунте за $200/мес чуть более быстрого ripgrep плюс любого готового индекса вполне достаточно, так что проект быстро индексируемого индекса всей машины можно оставить как «упражнение для читателя (который работает в AI-лаборатории)».
Оптимизации стали дешёвыми
Резкое падение стоимости оптимизаций справедливо начиная с ноября 2025 года, а возможно, и раньше — с публичными моделями (и наверняка ещё раньше с тем, что было доступно людям в AI-лабораториях). В качестве примера времён GPT-5.1 или 5.2, не имея никаких знаний об игровых ИИ, была предпринята попытка построить ИИ для игры Azul. В итоге получился сильнейший в мире ИИ для этой игры с довольно большим отрывом. Судя по диссертации, описывающей второй по силе ИИ, по части собственно «ИИ» тот, возможно, немного лучше, но главное преимущество здесь — оптимизация. Например, тот другой ИИ однопоточный, а этот — многопоточный. Поскольку существует и нативная версия, и жуткая версия на wasm с shared memory и javascript, а также две разные поисковые архитектуры для двух версий, которые «требуют» совершенно разных алгоритмов многопоточности (minimax для очень маленькой и быстрой сети и MCTS для более крупной), вручную это было бы довольно масштабным предприятием. А поскольку LLM пару раз позволили самой выбрать алгоритм многопоточности на основе собственных (ошибочных) рассуждений, прежде чем потратить 30 минут на самостоятельное чтение об алгоритмах многопоточности для игровых ИИ, алгоритм многопоточности пришлось переписывать (силами codex) несколько раз.
Есть набор стандартных вещей, которые имеет смысл сделать для отладки и верификации алгоритма многопоточности вроде этого — например, реализовать воспроизведение по отладочным логам, способное повторить баг несмотря на недетерминированность алгоритма. Сделай это вручную — ушли бы дни, а то и неделя работы, но это именно та задача, с которой агент тривиально справляется в цикле (просто заставляешь его пытаться воспроизвести логи и вставлять логирование недетерминизма каждый раз, когда точное воспроизведение не получается). Значительная часть рутины, которая раньше требовалась для отладки такой хитрой оптимизации, исчезла.
То же самое применимо и ко многим другим сложным оптимизациям. Опыт написания микрокода CPU, верификации CPU, оптимизации индекса поисковой системы и так далее приучил смотреть на оптимизацию и думать: «так, это даст прирост производительности на 2%, но потребует N человеко-дней на верификацию того, что эта хитрая оптимизация действительно работает» — и принимать решение, стоит ли овчинка выделки. Теперь, когда это N сократилось на колоссальный множитель (варьируется, но в терминах человеческого времени часто в 1000/10000/1000000 раз, а в терминах денежных затрат, вероятно, ближе к 1000x, если сравнивать стоимость токенов по тарифным ставкам со стоимостью работы инженера Bing, писавшего компиляторы для JIT в поисковом индексе), количество оптимизаций, которые имеет смысл делать, резко растёт. То же касается оптимизаций с неочевидным результатом. Раньше не всегда было понятно, стоит ли пробовать оптимизацию, эффект от которой неясен: «на это уйдёт M часов, чтобы получить достаточно хорошее измерение и прикинуть влияние на производительность». Гораздо больше таких оптимизаций теперь стоит пробовать.
Возвращаясь к случаю с игровым ИИ: как минимум для испытанного варианта, каждое удвоение скорости даёт около 100 Эло (больше, чем в шахматах, вероятно, потому что ничьи здесь очень редки). Одно только добавление многопоточности достаточно, чтобы разгромить сопоставимый по прочим параметрам ИИ на мощной машине. Если добавить сверху 10-20 оптимизаций, которые большинству людей слишком муторно делать вручную, разница в силе становится колоссальной, и тягаться с написанным вручную ИИ уже не особо реалистично3.
Случай с игровым ИИ немного сложнее, чем для большинства ПО, потому что многие желаемые оптимизации фактически меняют результат игры, и нет дешёвого тривиального способа понять, даёт ли прирост скорости в сочетании с изменением результата в итоге лучший или худший практический исход. И, как уже отмечалось ранее, доступные сейчас публичные SOTA-модели довольно слабы в проектировании экспериментов, так что пришлось самостоятельно настраивать фреймворк для определения качества оптимизации, но после этого задача сводится к обычной оптимизационной проблеме. Видимо, людям, работающим над оптимизациями самих LLM, тоже приходится сталкиваться с такого рода сложностями, но большинство оптимизационных задач куда более прямолинейны.
Ещё один пример: готовясь к собеседованиям по производительности, Джейми Брэндон попробовал теперь уже публичное тестовое задание Anthropic по перформансу. Попробовав самостоятельно, он дал Claude продолжить с того места, где остановился, и модель получила заметно лучший результат. Разбирая, что сделал Claude, чего не сделал он сам, Брэндон отметил, что многие оптимизации приходили ему в голову, но руки до них не дошли, а «[д]ругие были просто безумной дичью, которую я бы никогда не попробовал, если бы не работал над этим неделями»4. Он вполне толковый performance-инженер и получил предложение о работе на желаемую позицию, но на чётко определённой оптимизационной задаче у него нет шансов против приличной модели.
Оптимизация под конкретную нагрузку
Возвращаясь к той части комментария Марка Брукера:
Динамическое кастомное ПО, подогнанное под конкретную нагрузку, а не под класс нагрузок, выглядит очень вероятным исходом.
Это выглядит вполне неизбежным. В другом отклике на предыдущий пост Майкл Малис из pgrust сказал нечто похожее:
[обсуждение оптимизаций pgrust] ... думаю, создавать такие оптимизации достаточно просто, чтобы можно было смотреть на нагрузку клиента и добавлять их по мере необходимости
Без какого-либо специального фреймворка или подготовки, буквально перед началом работы над этим постом, агент занялся оптимизацией под конкретную нагрузку для запросов ripgrep (не переключением на компилятор в нативный код, а оптимизацией общего движка FRE на основе набора бенчмарков) — запуск занял около 2 минут. Оптимизации прогоняются на одном наборе запросов, а затем есть отложенный набор запросов для проверки. Процесс всё ещё идёт, но первые результаты обнадёживают. После одного прохода оптимизации версия, подогнанная под нагрузку, на 2% быстрее стандартного ripgrep на holdout-наборе, и скорость продолжает расти. 2% — не бог весть какой выигрыш для локального использования ripgrep, но учитывая, что это заняло считаные минуты и оптимизации начались одновременно с написанием этого абзаца и продолжают улучшаться, такой результат вполне устраивает (это без учёта компилятора в нативный код, который при правильном сочетании дал бы больший общий выигрыш). Стоит напомнить, что речь о движке FRE5, который заметно уступал регекс-движку Rust на holdout-бенчмарках и застрял на медленном прогрессе, поскольку при полном незнании регекс-нагрузок и недостаточной способности SOTA LLM к проектированию экспериментов для неуправляемых открытых самоулучшающихся циклов не было хорошего способа улучшить производительность на holdout. Но если важна производительность именно на своих нагрузках, данных достаточно и они продолжают накапливаться. Как отмечал выше Марк Брукер, нужно быть осторожным с переобучением при смене режима работы, которого нет в старых данных, и так далее, но ситуация всё равно лучше, чем была раньше.
В более общем случае, если речь идёт о ком-то вроде Марка Брукера в Amazon или Майкла Малиса, работающего над pgrust, есть смысл не ограничиваться разовым экспериментом, а работать с клиентами над пилотной программой, использующей их данные для оптимизации под них, а затем масштабировать это на клиентов в целом. Не всякая компания — то место, где это лучшее применение времени6, но удивительно уже то, что это явно приближается для крупных компаний с большим масштабом, и, учитывая, что на прогон таких экспериментов для личных рабочих процессов уходят считаные минуты, вполне разумно поэкспериментировать с этим и в личных проектах.
Благодарности Джейми Брэндону, Майклу Малису и Максу Биттекеру за комментарии, поправки и обсуждение.
P.S. Как уже отмечалось в предыдущих постах, с кодинг-агентами время на постановку эксперимента и получение результата, достаточного для удовлетворения любопытства, сильно сократилось, а время, нужное для доведения результата до по-настоящему строгого вида, не изменилось или даже выросло — так что описывать всё по старинке означало бы проводить очень мало экспериментов относительно доступной пропускной способности. В итоге эксперименты просто проводятся, а результатами делились с парой друзей. В качестве эксперимента предпринята попытка описывать это быстро и не слишком строго, вместо того чтобы годами держать такие результаты известными лишь узкому кругу друзей. Как и в прошлый раз, была поставлена цель уложиться в написание поста и всю чистку за полчаса — время не засекалось, но, вероятно, цель была немного превышена.
Даже при таком подходе описание результатов занимает достаточно времени, чтобы отставать от публикации свежих результатов, но переход на посты, написанные LLM (пока?), не рассматривается, и вряд ли реалистично довести очистку данных и написание такого поста до менее чем получаса. Уже по длине этого поста видно, что набор текста должен занимать порядка 20-30 минут, включая паузы на обдумывание, а иногда при взгляде на данные что-то выглядит настолько неправильно, что требуется более пристальное изучение вопроса (здесь так случалось несколько раз, и вероятно, из-за нехватки времени на дополнительную проверку в данных остались и другие незамеченные проблемы).
Мнения об этих быстрых (и наверняка более ошибочных) заметках приветствуются (X, Bsky, Mastodon)!
Приложение: больше нет причин, чтобы софт был медленным
Давно и открыто высказывалось несогласие с общим настроем в духе «разработчики X плохие и должны стыдиться за медленный код», потому что существует множество разных видов программистской экспертизы, и дело не только в том, что у большинства программистов нет экспертизы в производительности — им, вероятно, вообще не имеет смысла её развивать (с точки зрения того, что важно бизнесу, как выглядит рынок труда и так далее), поэтому, разумеется, у большинства проектов производительность будет сильно уступать тому, чего добился бы эксперт по производительности.
В примере выше Джейми Брэндон получил предложение от Anthropic, и позволить себе его или подобного ему специалиста может не каждая компания, если только это не OpenAI, — но позволить себе использовать кодинг-агента, способного превзойти его на ограниченной оптимизационной задаче, может практически кто угодно. У агента нет присущего человеку чутья, и на открытой задаче он справится хуже (стоит вспомнить, что при попытке построить оптимизированный регекс-движок и просто сказать агенту не переобучаться, результат был более чем на порядок хуже лучших регекс-движков на holdout-бенчмарках, но также стоит вспомнить, что после сообщения агенту о наличии holdout, на котором результат плох, движок ускорился достаточно, чтобы в целом сравняться по производительности с регекс-движками второго эшелона — что всё ещё крайне неплохо на фоне общего уровня оптимизации производительности в большей части сегодняшнего кода). Этого более чем достаточно для достижения разумной производительности на самых разных задачах. Пост в основном касался проблем производительности бэкенда, но у агентов, похоже, не хуже получается и с фронтенд-производительностью, если нужно снизить набор метрик вроде LCP, INP и подобных.
Приложение: как codex запускает ripgrep
Немного данных о распределении запросов ripgrep на локальной машине — без каких-либо претензий на репрезентативность где-либо ещё. Распределение длины искомого паттерна содержит гораздо больше длинных паттернов, чем можно было бы ожидать. Медиана (p50) — 55 юникод-кодпоинтов (для простоты будем называть их символами), что уже длиннее того, что обычно ищется вручную через grep, а p90 составляет целых 119!
Можно также посмотреть на число веток альтернации (|) в регулярных выражениях — они тоже заметно сложнее того, что делается вручную.
Ещё один взгляд — на корреляцию этих величин. Растёт ли число веток альтернации по мере удлинения регулярного выражения? Да.
Что же представляют собой эти очень длинные регулярные выражения? При ближайшем рассмотрении большинство из самых длинных оказываются длинными альтернациями по именам функций или тестов — вот пример, судя по всему, связанный с разработкой FRE.
fn (hot_byte_compiler_is_generic_only_and_anonymous_count_uses_auto_count|
one_pattern_count_spans_uses_the_retained_complete_span_session|
formal_compact_state_byte_visitors_coexist_with_native_count|
fixed_boundary_record_visit_matches_line_relative_reference_and_is_atomic|
unbounded_languages_refuse_finite_extraction_before_allocation|
formal_single_raw_span_sweep_preflight|
assert_exact_fixture_uses_formal_large_continuation_sweep|
url_only_compile_identity_binds_language_and_owner_mode|
url_only_compile_exact_limits_and_runtime_refusals_close|
url_only_compile_post_plan_allocation_faults_close|
url_only_owner_discriminator_is_stable_and_precharged|
url_only_compile_owner_is_strategy_and_operation_scoped|
formal_rebar_url_owner_is_compile_only_and_matches_oracle|
formal_rebar_url_exact_fixture_uses_certified_execution|
formal_fixed_schema_materialization_matches_both_record_oracles_and_controls|
formal_single_count_selects_compact_state_byte_complete_bound_visitors|
authenticated_bound_line_total_lf_free_domain_opportunity_exceeds_five_percent|
prepared_absolute_onepass_fuses_slots_and_preserves_pre_source_fallback|
authenticated_word_boundary_russian_compact_lowering_public_canary|
ordered_nfa_x86_epsilon_edges_bypass_the_assertion_call|
ordered_nfa_aarch64_epsilon_edges_bypass_the_assertion_call|
ordered_edge_dispatch_v2_is_target_neutral_deterministic_and_relocation_free|
ordered_edge_dispatch_v2_copies_canonical_tables_and_cap_falls_back_to_v1|
ordered_nfa_v3_composes_terminal_range_and_dispatch_without_data_relocations|
ordered_nfa_x86_terminal_range_emits_authenticated_reverse_scan|
ordered_nfa_aarch64_terminal_range_emits_authenticated_reverse_scan|
ordered_nfa_x86_boundary_assertion_cache_is_lazy_and_boundary_scoped|
ordered_nfa_aarch64_caches_repeated_assertions_once_per_boundary|
boundary_assertion_cache_requires_dense_exact_kind_reuse|
boundary_assertion_cache_selection_is_compiler_only_and_deterministic)
А некоторые — забавные числовые конструкции, например:
:(13[0-9]|14[0-9]|15[0-9]|16[0-9]|17[0-9]|18[0-9]|19[0-9]|20[0-9]|21[0-9]|22[0-9]|23[0-9]|24[0-9]|25[0-9]|26[0-9]|27[0-9]|28[0-9]|29[0-9]|30[0-9]|31[0-9]|32[0-9]|33[0-9]|34[0-9]|35[0-9]|36[0-9]|37[0-9]|38[0-9]|39[0-9]|40[0-9]|41[0-9]|42[0-9]|43[0-9]|44[0-9]|45[0-9]|46[0-9]|47[0-9]|48[0-9]|49[0-9]|50[0-9]|51[0-9]|52[0-9]|53[0-9]|54[0-9]|55[0-9]|56[0-9]|57[0-9]|58[0-9]|59[0-9]|60[0-9]|61[0-9]|62[0-9]|63[0-9]|64[0-9]|65[0-9]|66[0-9]|67[0-9]|68[0-9]|69[0-9]|70[0-9]|71[0-9]|72[0-9]|73[0-9]|74[0-9]|75[0-9]|76[0-9]|77[0-9]|78[0-9]|79[0-9]|80[0-9]|81[0-9]|82[0-9]|83[0-9]|84[0-9]|85[0-9]|86[0-9]|87[0-9]|88[0-9]|89[0-9]|90[0-9]|91[0-9]|92[0-9]|93[0-9]|94[0-9]|95[0-9]|96[0-9]|97[0-9]|98[0-9]|99[0-9])[0-9]:
Это эквивалентно :(?:1[3-9]|[2-9][0-9])[0-9]{2}: (что при прогоне через ripgrep на исходных данных даёт примерно ту же производительность). Весь пайплайн, приведший к этому, выглядел так:
cargo clippy … | rg 'crates/fre-aot-regex/src/module.rs:' | rg NUMBER_REGEX | head -250
что может показаться странной вещью для человека, но агенты, похоже, делают подобное постоянно.
Что касается длительности выполнения запросов ripgrep, среди них встречается немало медленных: например, p99 составляет почти минуту! А p999 — почти 10 минут! Максимальный запрос за этот период (около месяца на одном ноутбуке; на AWS-хостах, где запускаются агенты, распределение запросов, вероятно, отличается, но это не проверялось) приближается к 2 часам!
Что касается опций командной строки, картина следующая. Возможно, неудивительно, что codex часто запрашивает номера строк, а по каким-то причинам изредка использует регулярные выражения PCRE2.
Графиков и таблиц для следующего наблюдения не будет, но стоит отметить довольно низкую локальность искомых паттернов (около 94% паттернов встретились лишь однократно), что вполне объяснимо с учётом длины многих запросов. При этом локальность искомых файлов заметно выше, и файл, который уже искался, с относительно высокой вероятностью будет искаться снова в ближайшее время — что указывает на вероятность (для достаточно небольших файлов) поиска прямо в памяти.
Также 99% запросов были регулярными выражениями (1% — обычным строковым поиском без регекспов), а 99,9% поисковых запросов состояли только из ASCII, но среди искомых файлов лишь около 45% были только ASCII, а 55% содержали Unicode — доля выше ожидаемой.
В черновике предыдущего поста Питер Геогэн отметил:
Реализация регулярных выражений также может быть быстрее за счёт поддержки меньшего числа возможностей. Некоторые реализации не поддерживают обратные ссылки и так далее.
Это тоже справедливо и здесь. Проведённые оптимизации под конкретную нагрузку были довольно поверхностными, поскольку codex получил лишь короткие инструкции и полную свободу действий (что в целом не самый эффективный способ использования codex), но при более детальном плане и более прицельных оптимизациях под типичные сценарии запросов можно было бы ожидать большего выигрыша.
- хотя, как обсуждалось в том посте, а также ранее, навыков бенчмаркинга и проектирования экспериментов у SOTA-моделей недостаточно, чтобы делать это в общем случае без участия человека (или готового «скилла»), настраивающего среду бенчмаркинга для агента.
- по старым бенчмаркам видно, что даже с учётом времени на компиляцию во многих случаях версия, скомпилированная в нативный код, оказывается медленнее крейта regex для Rust. При ближайшем рассмотрении это, как правило, более сложные запросы, где regex-крейт Rust применяет какую-то алгоритмическую оптимизацию, а компилятор нативного кода FRE откатывается к чему-то наивному (агент, создававший FRE, потратил на компилятор в нативный код гораздо меньше времени, чем на «обычный» регекс-движок).
- нет никаких сомнений, что написанный вручную ИИ от кого-то с реальной экспертизой в области ИИ, например от автора одного из топовых движков для го или шахмат, мог бы превзойти этот ИИ по силе собственно «интеллектуальной» части — она заведомо лучше того, что получается у человека без знаний в области ИИ. Но при сопоставимом уровне экспертизы LLM-версия будет доминировать при любом заданном объёме затраченного времени.
- можно возразить, что сравнивать результат агента, продолжающего чужую работу, не вполне честно, поскольку она даёт агенту стартовую точку, позволяющую справиться значительно лучше, чем с нуля — поэтому задача была дана и «свежему» агенту, который получил очень похожий результат на то, что вышло при продолжении чужой работы (а беглая проверка другим агентом не выявила признаков жульничества).
- результат, вероятно, был бы лучше, если бы агент напрямую модифицировал форк ripgrep, но было интересно, можно ли таким образом заодно решить проблему переобучения FRE применительно к своим запросам.
- в свое время размер страницы в процессе регистрации был сокращён с 50 МБ до 5 МБ, и A/B-тест по выручке показал прирост примерно на 0,5%. В целом простые и лёгкие победы вроде этой стоит делать в первую очередь, и здесь, вероятно, есть немало решений с более высоким ROI, чем создание кастомных компиляторов или другая узкоспециализированная техническая работа.