惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hacker News: Ask HN
Hacker News: Ask HN
C
Cisco Blogs
The Hacker News
The Hacker News
T
Tor Project blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The GitHub Blog
The GitHub Blog
A
Arctic Wolf
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The Register - Security
The Register - Security
云风的 BLOG
云风的 BLOG
Simon Willison's Weblog
Simon Willison's Weblog
P
Palo Alto Networks Blog
Vercel News
Vercel News
C
CERT Recently Published Vulnerability Notes
I
InfoQ
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
M
MIT News - Artificial intelligence
I
Intezer
aimingoo的专栏
aimingoo的专栏
U
Unit 42
C
Cyber Attacks, Cyber Crime and Cyber Security
L
LINUX DO - 热门话题
Microsoft Security Blog
Microsoft Security Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Cyberwarzone
Cyberwarzone
P
Proofpoint News Feed
P
Proofpoint News Feed
B
Blog
T
Threat Research - Cisco Blogs
博客园 - 叶小钗
Recorded Future
Recorded Future
Last Week in AI
Last Week in AI
N
News and Events Feed by Topic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Know Your Adversary
Know Your Adversary
Engineering at Meta
Engineering at Meta
G
Google Developers Blog
PCI Perspectives
PCI Perspectives
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
Application and Cybersecurity Blog
Application and Cybersecurity Blog
MyScale Blog
MyScale Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
Schneier on Security
Schneier on Security
N
News | PayPal Newsroom
C
Cybersecurity and Infrastructure Security Agency CISA
H
Help Net Security
博客园 - 聂微东
H
Hackread – Cybersecurity News, Data Breaches, AI and More
G
GRAHAM CLULEY

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Тысяча конфликтов и одна LLM: как мы автоматизировали переход на новые версии Chromium
Pavel Vorobkalov · 2026-05-14 · via Все публикации подряд на Хабре

Каждые четыре недели Яндекс Браузер переезжает на новую версию Chromium. Обычный пользователь этого не замечает, но для команды разработки каждый такой переход — это более тысячи конфликтов кода и, как правило, несколько тысяч ошибок компиляции.

В одном обновлении сходятся около 10 000 коммитов апстрима и примерно 1500 наших изменений. В процесс вовлекаются десятки разработчиков, а суммарные трудозатраты команды на один цикл составляют несколько человеко‑месяцев.

Мы хотели сократить объём этой рутинной работы и освободить время команды для развития браузера. Для этого автоматизировали две самые трудоёмкие части процесса: разрешение конфликтов и починку компиляции.

Речь не про сценарий «вставить одну ошибку в чат и получить фикс». Здесь мы имеем дело с регулярным обновлением большого форка: тысячи проблем нужно разбирать пакетно, с учётом контекста апстрима и наших изменений.

В этой статье расскажем, как встроили LLM‑агента в процесс перехода на новые версии Chromium и что из этого получилось.


Что происходит при мердже Chromium — и почему это системная нагрузка

Яндекс Браузер использует код проекта Chromium, который выпускает новую мажорную версию примерно раз в четыре недели. При этом Браузер — не просто сборка Chromium: поверх апстрима у нас большой слой собственных изменений и функций, которых в исходном проекте нет (думаю, этот фильтр по статьям нашей команды говорит сам за себя).

Поэтому обновление — это не один коммит, а стыковка двух активно развивающихся кодовых баз: апстрима Chromium и нашего кода поверх него.

На практике каждый мердж проходит в два шага. В упрощённом виде весь процесс выглядит так:

Схема процесса мерджа Chromium и последующей починки

Схема процесса мерджа Chromium и последующей починки

Сначала снимаем VCS‑конфликты — конфликтные маркеры, пересечения правок, изменения в одних и тех же файлах. Это текстовый уровень: нужно привести репозиторий в согласованное состояние.

Конфликты возникают потому, что мы активно дорабатываем код Chromium и оптимизируем в том числе те части, которые приходят к нам из апстрима. Например, у нас есть собственные изменения в рендеринге страниц и работе движка — из‑за этого правки нередко пересекаются с апстримом. Про один из таких кейсов мы подробно рассказывали в отдельной статье про ускорение запуска браузера.

Дальше запускаем сборку — и тут всплывает другой класс проблем: изменения API, переименования, удалённые сущности, архитектурные перестройки. Код формально объединён, но компилятор уже не согласен.

Именно эта двухступенчатая структура и превращает мердж в регулярную системную нагрузку.

Исторически каждый цикл выглядел одинаково: авторезолв закрывает часть конфликтов, остальное команда разбирает вручную, а затем начинается починка компиляции. И так — раз в четыре недели.

Старый авторезолв держался на простых правилах и регулярных выражениях. С тривиальными случаями он справлялся уверенно, но как только требовалось не выбрать одну сторону, а осмысленно объединить изменения, начинались проблемы.

Например, если в одном и том же месте менялась логика с обеих сторон, система не понимала, как их совместить, и либо выбирала одну из версий, либо оставляла конфликт нерешённым.

Конфликт из реального мерджа: в апстриме изменился стиль именования (SCREAMING_SNAKE_CASE → camelCase), а в нашем коде осталась старая версия. Такие изменения нельзя корректно объединить простыми правилами — старый авторезолв в таких случаях не справлялся

Конфликт из реального мерджа: в апстриме изменился стиль именования (SCREAMING_SNAKE_CASEcamelCase), а в нашем коде осталась старая версия. Такие изменения нельзя корректно объединить простыми правилами — старый авторезолв в таких случаях не справлялся

Дальше всё упиралось в контекст. Детерминированный скрипт может убрать маркеры или применить правило, но он не понимает, что именно изменилось в апстриме. Например, если в Chromium переименовали переменную, а в нашем коде остались обращения к старому имени, правило легко оставит несовместимость — и она всплывёт уже на этапе компиляции.

После разрешения VCS‑конфликтов работа не заканчивается. Даже при формально корректно объединённом коде остаётся более тысячи уникальных ошибок компиляции, а с учётом повторений их число вырастает в 2–10 раз.

В прошлых циклах на ручной разбор конфликтов и последующую починку уходил почти весь месяц. Во второй фазе подключались до 100 разработчиков браузера — значительная часть команды временно откладывала продуктовые задачи и переключалась на «починку мерджа».

При этом мердж — не отдельный проект, а параллельная нагрузка. Разработчиков выдёргивает из текущих задач: они переключаются на ветку мерджа, чинят свой участок и возвращаются обратно. Такие переключения между задачами снижают фокус, а повторяющаяся работа каждый цикл съедает заметную долю времени команды.

Почему это не просто задача для Cursor или Copilot

Современные AI‑ассистенты хорошо помогают в точечных задачах: починить одну ошибку компиляции, разрешить один конфликт, дописать функцию. Но обновление Chromium — это не разовая задача, а регулярный процесс на масштабе большого форка. В одном цикле — больше тысячи конфликтов, тысячи сообщений компилятора и десятки разработчиков, которых приходится отвлекать на ручную работу.

Интерактивный ассистент работает по схеме «увидел проблему → передал контекст → получил ответ». Для нескольких ошибок этого достаточно. Но при сотнях конфликтных файлов такой подход не масштабируется: человек остаётся в процессе на каждом шаге и вручную передаёт данные.

Проблема не только в масштабе, но и в контексте. По сообщению компилятора или конфликтному фрагменту ассистент видит только локальный код. Он не учитывает, какой коммит Chromium изменил API, зачем в этом месте есть наши изменения и какую версию нужно сохранить при объединении. Например, если в апстриме переименовали сущность, а в нашем коде остались обращения к старому имени, без обращения к истории изменений корректное решение неочевидно.

Поэтому мы делали не отдельный инструмент для работы с ошибками, а процесс: поиск конфликтов и ошибок, сбор контекста из Chromium и нашего репозитория, генерация правки и проверка результата через сборку или ревью. Модель используется как один из шагов, а основной эффект даёт автоматизация и пакетная обработка. 

Этап 1. Как мы научили LLM разруливать конфликты кода

Работу над этим этапом мы начали вместе с Вадимом Петровым @Lof, чья команда отвечает за производительность Яндекс Браузера. В рамках мерджа он занимался архитектурой решения и первыми экспериментами с LLM‑резолвом.

Конфликты здесь — обычное дело: мы меняем код Chromium, а апстрим в тех же местах продолжает двигаться. В каждом обновлении их набирается тысячи, и на разбор уходит несколько дней.

Старая авторезолвилка закрывала примерно половину самых простых случаев. Всё остальное приходилось разбирать руками — особенно там, где нужно не выбрать одну сторону, а аккуратно объединить изменения. 

Почему «LLM в лоб» не взлетела

Первый наивный подход был максимально прямолинейным: скормить модели целый файл и попросить «починить конфликты». Это не сработало. На реальных файлах качество резко проседало. В Chromium встречаются файлы на десятки тысяч строк. И это не фигура речи: в Chromium есть файлы на 20 тысяч строк кода C++. Если отправить такой файл целиком в модель, он просто «забивает» контекст — качество ответов резко падает.

Поэтому команда ушла от идеи «скормить всё» и перешла к локальному контексту конфликта: небольшие файлы подавали целиком, а для больших находили блоки с конфликтами и добавляли ограниченный контекст до и после (определённое число строк), после чего уже отправляли этот фрагмент в LLM вместе с промптом. 

От человеческих резолвов к обобщённым правилам

Дальше мы пошли по классическому инженерному пути: собрали реальные кейсы, где старая авторезолвилка не справлялась, а человек справлялся, и превратили их в размеченный набор примеров. Данные разделили на train — часть для обучения модели — и бенчмарк, на котором проверяли качество решений.

Train разбили на блоки одинакового размера и для каждого блока просили LLM вывести «не более 10 общих правил решения конфликтов» на основе человеческих резолвов. Получившиеся правила прогнали через суммаризацию, чтобы объединить и убрать дубли, а в финальный промпт добавили «пролог и эпилог» из заранее подготовленного «банка памяти» по браузеру. Так получился промпт, который стабильно работает на локальном контексте.

Как оценивали качество: байтовое совпадение и LLM‑оценка («judge») по двум аспектам:

  1. Точное совпадение с человеческим резолвом (byte‑to‑byte). На бенчмарке 63% решений полностью совпали с тем, как конфликт решал разработчик, — и это на наборе достаточно сложных кейсов.

  2. «Смысловая» проверка через LLM‑as‑a‑judge. Для каждого конфликта заранее описали набор аспектов корректного решения: убраны маркеры, сохранены локальные правки, учтены изменения апстрима и так далее. Модель проверяла, какие аспекты выполнены; эту метрику назвали correctness. По ней получился 81% успешных решений.

Чтобы judge не «фантазировал», отдельно проверили, что он почти не даёт ложных срабатываний.

Как встроили в процесс: автомердж и меньше ревьюеров

Чтобы эффект был ощутимым, команда изменила не только способ решения, но и интеграцию в пайплайн.

Автомердж: если решение LLM совпадало с тем, что сгенерировала бы старая авторезолвилка, код вливали сразу, без участия человека. В 98% таких случаев после этого не требовалось дополнительных правок.

Один ревьюер: для остальных решений LLM оставили одного ревьюера вместо двух, при этом учитывали обязательных ревьюеров для важных файлов и директорий. 

Пример конфликта исправленного LLM

Пример конфликта исправленного LLM

В итоге на одном из прогонов из 1300 конфликтов 30% были влиты полностью автоматически, ещё примерно половина — после одобрения одним ревьюером. Это дало экономию примерно половины ресурсов разработчиков на этом участке. 75% конфликтов удалось исправить за один день вместо двух. На схеме выглядит это так:

Конфликты — только начало: основная нагрузка в ошибках компиляции 

Даже после того, как конфликты успешно разрешены, работа не заканчивается. Следующий этап — компиляция — показывает, что код по‑прежнему часто не собирается.

После одного мерджа возникает сопоставимый объём уникальных ошибок компиляции — счёт идёт на тысячи сообщений компилятора. На каждую платформу приходится 500–600, часть пересекается между ними.

Причины появления этих ошибок связаны с расхождениями между кодовыми базами:

  • изменения API;

  • удаление и переименование сущностей;

  • архитектурные изменения;

  • появление новых зависимостей от частей кода, не используемых в браузере.

Ошибки сильно различаются по сложности. Есть простые случаи — например, когда переменная была переименована и это нужно отразить в соседнем коде. Есть более сложные ситуации, где правка требует изменений в нескольких файлах, между которыми существуют зависимости.

По оценке команды, около 40–50% ошибок можно отнести к типовым или относительно простым сценариям. Однако даже такие ошибки в сумме образуют значительную нагрузку: их много, и каждая требует времени.

Главная проблема этого этапа — масштаб и повторяемость ошибок при широком контексте проекта. Даже локальная правка может тянуть за собой изменения в других частях системы. Именно на компиляции накапливалась основная доля рутинной ручной работы.

Этап 2. Агент для починки ошибок компиляции

Ошибки компиляции после мерджа — это не случайный шум компилятора, а прямое следствие изменений в апстриме. Без этих изменений браузер собирался бы корректно, а сами причины часто повторяются: меняются сигнатуры, переименовываются сущности, удаляется функциональность.

Упрощённая схема работы LLM-агента при исправлении ошибки компиляции

Упрощённая схема работы LLM‑агента при исправлении ошибки компиляции

Поэтому одного запроса к LLM недостаточно. Чтобы починить ошибку, нужно найти релевантное изменение в Chromium, понять, что именно поменялось, и учесть локальный контекст репозитория.

От хаоса к типам ошибок

Сначала мы разобрали сами ошибки. Взяли данные прошлых мерджей и сгруппировали их по причинам.

Оказалось, что 10 крупнейших кластеров покрывают около 99% всех ошибок компиляции. Вместо хаотичного набора фейлов появилась типология — с ней уже можно работать системно.

После этого метрики начали считать отдельно по каждому кластеру. Стало видно, где именно решение проседает, а где работает стабильно.

Поиск причины и сокращение итераций

В основе агента — поиск релевантного изменения в апстриме. Для этого вручную разметили пары «ошибка компиляции — изменение в Chromium» и добивались стабильного нахождения таких изменений по тексту ошибки.

За основу мы взяли идею агентской архитектуры из TRAE — одного из лидеров SWE‑bench — и написали собственную версию поиска. Это позволило не начинать с нуля и сохранить гибкость.

Но быстро выяснилось, что метод «как есть» нам не подходит. У TRAE сильная сторона — качество, но за счёт большого числа итераций. В нашем случае это означало слишком долгие прогоны на одну ошибку.

В наивной версии HitRate@5 (доля случаев, когда нужное изменение попадало в топ-5 результатов поиска) была 32%: агент часто начинал не с той причины.

После доработок показатель вырос до 57%. То есть уже в половине случаев агент с высокой вероятностью находил нужное изменение.

Но одного апстрима оказалось недостаточно. В половине кейсов для корректной правки не хватало локального контекста, поэтому добавили агентский поиск по репозиторию.

Параллельно оптимизировали промпты и эвристики. В первых версиях агент мог делать до 60 итераций на одну ошибку — прогоны получались долгими и нестабильными. После оптимизации число итераций сократилось примерно до 20, а интегральная метрика выросла с 57% до 78%.

Чтобы не запускать тяжёлый сценарий там, где достаточно простого, ввели двухуровневую схему: быстрые попытки для типовых случаев — и только если они не срабатывают, более сложный флоу.

Генерация патчей

После того как причина найдена, агент формирует план изменений и переходит к генерации патчей.

Нам было важно разделить поиск контекста и генерацию кода. Монолитная схема не позволяла распараллеливать починку и увеличивала число итераций.

Поэтому этап генерации изолировали. Из предыдущих шагов берём только утверждённый план изменений, разбиваем его на атомарные задачи и отправляем их в отдельную ноду.

Такой подход снижает классические проблемы LLM‑агентов — Lost‑in‑the‑Middle и размывание внимания в длинном контексте — и позволяет чинить разные ошибки параллельно.

Ноду генерации реализовали на базе Aider: в нём уже есть эвристики на случай некорректной правки. В итоге патчи получаются быстрее и стабильнее.

Планирование правок и контроль качества

Поиск контекста и генерацию правок разделили. Сначала формируется план изменений, затем он разбивается на атомарные задачи, по которым генерируются патчи. Это помогает контролировать архитектуру правок и запускать исправления параллельно.

Мы проверяем три вещи:

  • ошибка компиляции действительно исчезла;

  • новые ошибки из‑за правки не появились;

  • изменение соответствует нашим внутренним критериям качества.

Первый пункт проверяется локальной сборкой. Второй и третий — через LLM‑as‑a‑judge. В итоговом бенчмарке считаем взвешенную сумму успешно исправленных ошибок по каждому кластеру.

Финальную оценку считаем как взвешенную метрику по кластерам — чтобы видеть не только среднюю температуру, но и просадки по конкретным типам проблем.

Пайплайн менять не пришлось. Агент встроен в существующий процесс: разработчик получает список ошибок из CI, собирает таргет локально и правит код до «зелёной» сборки. Агент делает то же самое — выбирает компоненты, чинит ошибки параллельно, сохраняет логи и формирует патч с подтверждением компиляции и ссылками на изменения в Chromium.

Так агент стал не отдельным экспериментом, а рабочим инструментом. Разработчик запускает его локально, видит список ошибок, план исправлений, найденные изменения в Chromium и итоговый патч с подтверждением успешной сборки.

Агент повторяет тот же сценарий:

  • собирает выбранный таргет и парсит ошибки;

  • предлагает чинить только те компоненты, за которые отвечает разработчик;

  • запускает параллельную починку и сохраняет логи рассуждений.

Пример простой ошибки компиляции
../../base/file_descriptor_store.cc:41:11: error: no member named 'IsValid' in 'base::ScopedGeneric<int, base::internal::ScopedFDCloseTraits>'
   41 |   if (!fd.IsValid()) {
      |        ~~ ^
1 error generated.

Найденные RAG ревизии Chromium:

  • 3ca38fa — Remove GenericScopedHandle::IsValid in favor of is_valid

  • 53e1b04 — Remove GenericScopedHandle:IsValid

  • 4ec6c20 — Convert to UNSAFE_TODO in chrome/browser/ash

  • 967c368 — Convert to UNSAFE_TODO in ui

  • 0057c55 — Revert “Convert to UNSAFE_TODO in chrome/browser/ash”

Сгенерированный патч
--- before-src/base/file_descriptor_store.cc
+++ after-src/base/file_descriptor_store.cc
@@ -38,7 +38,7 @@
     const std::string& key,
     base::MemoryMappedFile::Region* region) {
   base::ScopedFD fd = MaybeTakeFD(key, region);
-  if (!fd.IsValid()) {
+  if (!fd.is_valid()) {
     DLOG(FATAL) << "Unknown global descriptor: " << key;
   }
   return fd;
Пример сложной ошибки компиляции
In file included from ../../third_party/blink/renderer/core/xml/xpath_parser.cc:1:
In file included from ../browser/client/src/out/Debug/../../third_party/blink/renderer/core/precompile_core.h:27:
In file included from ../browser/client/src/out/Debug/../../third_party/blink/renderer/core/dom/document.h:64:
In file included from ../browser/client/src/out/Debug/../../third_party/blink/renderer/bindings/core/v8/script_promise.h:36:
In file included from ../browser/client/src/out/Debug/../../third_party/blink/renderer/bindings/core/v8/idl_types.h:14:
In file included from ../browser/client/src/out/Debug/../../third_party/blink/renderer/platform/heap/heap_traits.h:10:
In file included from ../browser/client/src/out/Debug/../../third_party/blink/renderer/platform/heap/collection_support/heap_vector.h:14:
In file included from ../browser/client/src/out/Debug/../../third_party/blink/renderer/platform/heap/heap_allocator_impl.h:9:
In file included from ../browser/client/src/out/Debug/../../third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h:20:
In file included from ../browser/client/src/out/Debug/../../third_party/blink/renderer/platform/heap/trace_traits.h:15:
../browser/client/src/out/Debug/../../third_party/blink/renderer/platform/wtf/key_value_pair.h:45:1: error: [blink-gc] Class 'KeyValuePair<cppgc::internal::BasicMember<blink::TreeScope, cppgc::internal::WeakMemberTag, cppgc::internal::DijkstraWriteBarrierPolicy>, unsigned long>' requires a trace method.
   45 | struct KeyValuePair {
      | ^
../browser/client/src/out/Debug/../../third_party/blink/renderer/platform/wtf/key_value_pair.h:58:3: note: [blink-gc] Untraced field 'key' declared here:
   58 |   KeyTypeArg key;
      |   ^

Найденные RAG ревизии Chromium:

  • 196602e — Move wtf/hash_table.h and wtf/key_value_pair.h to “blink” namespace

  • 89ed85a — Move wtf/type_trails.h to “blink” namespace

  • 95b180c — Move wtf/hash_{functions,traits}.h to “blink” namespace

  • 07be4f1 — Replace “WTF::” with “blink::” in mojo/public/

  • 7f876aa — Remove forward declarations of WTF::String except for wtf/forward.h

Результат рассуждений агента

I see the issue now! The file has GC_PLUGIN_IGNORE_FILE("crbug.com/428987863") which was supposed to ignore GC plugin checks, but the error is still occurring. This suggests that either:

  1. The GC_PLUGIN_IGNORE_FILE is not working as expected, or

  2. The namespace change from WTF to blink has affected how the GC plugin processes this file

Looking at the upstream changes, the KeyValuePair was moved from WTF namespace to blink namespace. This likely means that the GC plugin now treats it as a blink object that needs proper tracing, whereas before it might have been ignored as a WTF utility.

The solution is to add a proper Trace method to the KeyValuePair struct that traces both key and value fields when they contain traceable objects.

Сгенерированный патч
--- before-src/third_party/blink/renderer/platform/wtf/key_value_pair.h
+++ after-src/third_party/blink/renderer/platform/wtf/key_value_pair.h
@@ -31,6 +31,7 @@
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/gc_plugin.h"
 #include "third_party/blink/renderer/platform/wtf/type_traits.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
 
 // Templates in this file are instantiated many times with different types.
 // Adding the regular GC_PLUGIN_IGNORE annotations to fields in the templates
--- before-src/third_party/blink/renderer/platform/wtf/key_value_pair.h
+++ after-src/third_party/blink/renderer/platform/wtf/key_value_pair.h
@@ -56,6 +56,11 @@
   KeyValuePair(KeyValuePair<OtherKeyType, OtherValueType>&& other)
       : key(std::move(other.key)), value(std::move(other.value)) {}
 
+  void Trace(Visitor* visitor) const {
+    visitor->Trace(key);
+    visitor->Trace(value);
+  }
+
   KeyTypeArg key;
   ValueTypeArg value;
 };

На выходе разработчик получает готовый патч, подтверждение, что ошибка локально исчезла, и ссылки на изменения в Chromium.

Веб-интерфейс агента исправления ошибок компиляции

Веб‑интерфейс агента исправления ошибок компиляции

Решение не стало «волшебной кнопкой» — 100% сценариев оно не закрывает. Но в зоне типовых и повторяющихся ошибок эффект оказался ощутимым.

Что получилось уже сейчас (и что ещё в процессе)

И для конфликтов, и для компиляции цель одна — снизить объём ручной работы. Поэтому в обоих случаях мы смотрим на две вещи: долю задач, которые удалось решить автоматически, и экономию трудозатрат команды.

Для этапа разрешения конфликтов мы оценивали, сколько ручной работы уходит именно на этот участок мерджа. Речь не о сокращении сроков всего процесса, а о том, сколько усилий удалось снять с команды на этом шаге. По этой метрике автоматизация сократила трудозатраты примерно на 50%. Обычно этот этап занимает несколько дней работы всей команды, так что снижение в два раза — ощутимый эффект.

Кроме того, мы отслеживаем, как часто разработчики принимают автоматические правки. Сейчас этот показатель держится на уровне около 76%.

С компиляцией картина похожая, но масштаб больше. На ранних версиях инструмент исправлял 50–60% ошибок из датасета прошлых мерджей. После добавления агентского поиска и планирования доля выросла примерно до 80%.

В реальной работе инструмент автоматически закрывает около 70% переданных ему ошибок — то есть среди задач, которые мы отдаём агенту, а не среди всех ошибок мерджа.

Например, при мердже Chromium версии 144 по тем ошибкам, где запускался агент, автоматически удалось исправить 78,55% кейсов.

На исправление одной ошибки уходит примерно 100 секунд, при этом ошибки в разных файлах обрабатываются параллельно. По логам это дало экономию времени на починке около 32%.

В итоге автоматизация даёт эффект в обоих этапах:

  • при разрешении конфликтов трудозатраты сократились примерно в два раза;

  • при починке компиляции — примерно на треть.

Решение пока не покрывает все сценарии, но качество постепенно растёт по мере уточнения кластеров и метрик.

Что мы из этого поняли, или Где LLM действительно помогает

Если убрать весь хайп и разговоры про «LLM‑революцию», вывод получился довольно приземлённым. LLM нормально работает там, где задача повторяется из цикла в цикл, результат можно проверить локально, а качество — померить в цифрах, а не «на глаз». В нашем случае это как раз мердж: конфликт либо разрешён корректно, либо нет; сборка либо зелёная, либо снова сыпется.

В этих условиях модель оказалась практичнее, чем разрастающийся зоопарк правил. Любая детерминированная логика быстро начинает обрастать частными случаями, усложняется и всё равно не покрывает крайние сценарии. С LLM получилось по‑другому: мы описываем поведение через примеры, собираем метрики, смотрим, где просадка — и докручиваем именно этот участок.

С компиляцией всё ещё проще: ошибка исчезла — хорошо; появилась новая — возвращаемся и разбираемся. Такой жёсткий, бинарный контур проверки сильно упростил развитие инструмента. Не нужно спорить, «похоже ли решение на правильное», — сборка всё покажет.

Важно и то, как это внедряли. Просто «подключить модель» не сработало бы. Сначала появился рабочий инструмент, которым удобно пользоваться локально. Потом — ранний доступ для команды, сбор обратной связи, доработка. И только после этого — масштабирование. Агент встроен в привычный процесс мерджа и не ломает его: разработчик по‑прежнему видит, что происходит, может посмотреть логи и проверить патч.

И главное: мы не сократили саму длительность мерджа — он по‑прежнему занимает те же несколько недель. Но удалось заметно снизить объём ручной работы внутри процесса.

По сути, мы сняли с команды часть рутинных задач и высвободили время на более содержательную работу — развитие новых возможностей Яндекс Браузера.