
В последние годы языковые модели всё активнее применяются для задач, связанных с программированием. Если раньше разработчики экспериментировали с решениями вроде Code Llama и Mistral, то в 2024 году на сцену вышло новое поколение специализированных моделей: DeepSeek Coder, Codestral, CodeQwen1.5 — это открыло гораздо больше возможностей для создания умных ассистентов, помогающих писать, править и анализировать код. В Яндексе мы развиваем собственную экосистему LLM‑инструментов для работы с кодом. Модели уже используются для автоматического ревью, встроены в IDE и помогают вносить масштабные правки в проекты.
Один из таких инструментов — генератор описаний для Pull Request. Он упрощает жизнь разработчикам: автоматически формирует понятные и информативные саммари для изменений в коде. Наша цель — сделать этот генератор ещё точнее и полезнее. Для этого мы искали оптимальную кодовую опенсорс‑LLM, которую можно развернуть локально, и подбирали эффективный промпт.
Меня зовут Дмитрий Успенский, я работаю в команде ML RnD Техплатформы Городских сервисов Яндекса, и в статье я расскажу, как мы применили подход LLM as a judge — когда сама языковая модель оценивает качество генераций и сравнивает между собой разные варианты описаний. Поделюсь опытом определения критериев качества, сбора валидационного датасета, подбора промптов и выбора модели. Результаты оказались обнадёживающими: метод действительно позволяет улучшить генеративную систему без участия ручной разметки и асессоров.
Генерация описаний для PR’ов: как это работает
Прежде чем двигаться дальше, давайте вспомним, как вообще устроена командная разработка ПО. Обычно каждый разработчик ведёт работу над своей задачей в отдельной ветке репозитория. Когда фича или фикс готовы, создаётся Pull Request — запрос на добавление изменений в основную ветку. После этого запускаются линтеры, проходят тесты, а сам код внимательно просматривают коллеги.
Чтобы другим участникам команды было проще разобраться в изменениях, автор PR’а должен составить описание: заголовок и краткое резюме с пояснением, что и зачем он сделал. Как подчёркивается в гайде по стилю PR’ов Google:
Что именно изменилось? — кратко, по сути, чтобы не приходилось вчитываться в код.
Почему это было сделано? — контекст и мотивация, особенно если решение неочевидное.
Но придумывать такие описания — дело не самое увлекательное. Особенно если только что погрузился в сложный код, а теперь нужно переключиться на обобщение и краткость. И вот тут в игру вступают языковые модели. В Яндексе мы разработали систему, которая автоматически генерирует описания для PR’ов — и уже интегрировали её в наш CI/CD.
В основе — русскоязычная языковая модель на 7 миллиардов параметров. Чтобы обучить её без использования внешних API (из‑за NDA на внутренний код), мы развернули локально DeepSeek Coder и с его помощью сгенерировали тренировочный датасет из реальных PR’ов. Этот подход позволил сохранить конфиденциальность и при этом получить достаточно данных для обучения.

Сейчас система генерации описаний поддерживает два режима работы:
В виде комментариев — описания добавляются как обычные комментарии к изменениям.
Единым блоком — текст размещается в отдельном разделе Pull Request’а.
Этой системой уже пользуются десятки команд, и каждую неделю через неё проходят тысячи PR’ов. Один запрос обрабатывается всего за три секунды — модель быстро анализирует изменения и автоматически добавляет итоговое описание в систему контроля версий.
Решение уже хорошо себя зарекомендовало, но мы не стоим на месте. В 2024 году появилось сразу несколько мощных опенсорс‑моделей, которые потенциально могут заметно улучшить качество генерации. Кроме того, современные языковые модели можно переиспользовать и для других задач — например, автоматического ревью кода.
Поэтому мы решили пойти дальше и серьёзно улучшить нашу систему: подобрать более подходящую модель и найти промпт, который даст наилучшие результаты. Причём не на глаз, а с объективной, воспроизводимой оценкой качества.
Критерии хорошего описания для PR’а
Прежде чем пытаться что‑то улучшать, нужно понять, что именно считать хорошим результатом. В нашем случае — что такое «хорошее описание» Pull Request’а. Мы решили начать с опроса самих разработчиков — ведь именно им каждый день приходится читать (и составлять) эти описания.
Мы подготовили пять реальных PR’ов и для каждого сгенерировали три варианта описания с помощью разных промптов:
базовый промпт — тот, что используется в текущей версии системы;
расширенный — с упором на технические детали;
структурированный — явно разделяющий цели и сделанные изменения.
Участников опроса просили выбрать лучший вариант и объяснить свой выбор. Такой подход позволил не просто выяснить, какой стиль им ближе, но и понять, почему именно он. На основе анализа ответов мы выделили ключевые характеристики хороших описаний:

Эти критерии стали для нас основой при оптимизации промптов и выборе модели. Мы сознательно ограничили их количество — чтобы задача не стала слишком размытой для автоматической оценки.
Собираем валидационный датасет
Чтобы проводить эксперименты не «на коленке», а действительно объективно, мы собрали собственный датасет — OpenPR. В него вошло 116 тысяч Pull Request’ов из более чем 50 известных опенсорс‑проектов, таких как Kubernetes, TensorFlow, Redis и других.
Наша цель была — охватить как можно больше типов проектов: инфраструктура, базы данных, фреймворки, библиотеки. И вот как мы это делали:
Парсили GitHub через API, отфильтровывая только активные репозитории, созданные до 2022 года (до широкого распространения Copilot); разные языки программирования: Python, Java, C++ и не только.
Чистили данные: убирали пустые diff’ы и описания, приводили формат к единому виду.
Структурировали всё по полочкам: заголовок PR’а, сообщения коммитов, изменения (diff), привязанные issues (если были).
Для финальной оценки моделей мы использовали отдельную валидационную выборку — она не участвовала в процессе оптимизации, чтобы обеспечить честные результаты.
Выбор эффективного промпта
После того как мы определились с критериями качества и собрали валидационный датасет, настало время заняться оптимизацией промпта. Для этого мы применили метод LLM as a judge — итеративный подход, при котором языковая модель сама оценивает результат своей работы и помогает выбрать лучший вариант.
В роли автоматического асессора мы протестировали две модели:
GPT-4 Omni показала себя недостаточно чувствительной к нюансам между вариантами описаний.
Claude Sonnet 3.5, наоборот, оказался более надёжным и чувствительным к тонким отличиям в стиле, структуре и информативности текста.
Мы зафиксировали тестовую выборку из 100 PR’ов из датасета OpenPR и начали итерации:
Вносили небольшое изменение в промпт.
Генерировали описания для всей выборки по двум версиям промпта: старому и новому.
Сравнивали пары описаний через Claude Sonnet.
Принимали или отклоняли изменения на основе сравнений.
Периодически проверяли результат вручную — чтобы убедиться, что модель не ушла куда‑то не туда.
В процессе мы заметили несколько интересных закономерностей:
Фиксированная структура (с заголовками и разбивкой по разделам) делает описание заметно более удобным.
Ссылки на конкретные элементы кода — функции, классы, переменные — ощутимо повышают ценность текста.
И, что неожиданно, эмодзи помогают воспринимать информацию быстрее и проще.
Вот как теперь выглядит наш улучшенный промпт:
Тебе на вход будет дан Pull Request, ты должна дать его описание.
Тело Pull Request будет дано в следующем формате:
1. Title — заголовок Pull Request
2. Commit messages — сообщения коммитов из Pull Request в порядке от завершающего к начальному
3. Diff — изменения в коде
Описание PR должно содержать:
- Задача, решаемая данным PR;
- Список описаний ключевых изменений.
Дополнительные требования:
- Описание должно содержать два раздела с заголовками: «Задача, решаемая данным PR», «Список описаний ключевых изменений»;
- Задача, решаемая данным PR, должна быть описана максимально коротко и просто для понимания. Длина описания не должна превышать 250 символов;
- Каждое описание ключевого изменения должно быть максимально коротким и простым для понимания. Его длина не должна превышать 250 символов. Стремись добавлять отсылки к коду там, где это возможно (имена функций, классов, переменных и т. д.). Каждое описание ключевого изменения должно начинаться с эмодзи, соответствующего его содержанию;
- Для описания ключевых изменений используй ненумерованный список.
Тело Pull Request:
1. Title: {message}
2. Commit messages: {commits}
3. Diff: {patch}
В сравнении с базовым промптом новая версия показала улучшение в 68% случаев (на отложенной выборке из 1000 PR’ов). Причём наибольший прирост качества был в PR’ах среднего и большого размера, где структурированный подход особенно важен.
Сравниваем модели для генерации описаний
После оптимизации промпта мы перешли к следующему этапу — сравнению различных языковых моделей для генерации описаний Pull Request’ов.
В качестве baseline мы использовали текущую систему на базе русскоязычной модели с 7 миллиардами параметров. Верхней границей качества служила GPT-4 Omni, которую мы брали как ориентир, хотя она и недоступна для локального развёртывания.
Для финального сравнения мы отобрали четыре продвинутые опенсорс‑модели, появившиеся в 2024 году:
DeepSeek‑Coder‑V2-Lite‑Instruct (16B)
Qwen2.5-Coder-14B‑Instruct
Qwen2.5-Coder-32B‑Instruct
Codestral-22B‑v0.1
Каждая из них запускалась локально и работала с тем же промптом, который мы оптимизировали на предыдущем этапе.
Как проходила оценка
Мы использовали фиксированную тестовую выборку из 1000 Pull Request’ов из датасета OpenPR. Для оценки качества применяли метод попарного сравнения: каждый вариант описания сравнивался с другим при помощи Claude Sonnet 3.5, выступающего в роли автоматического асессора.
Такой подход позволяет сравнивать модели по принципу «честного боя»: на одном и том же входе, с тем же промптом и по единым критериям.
Результаты сравнения (процент случаев, когда модель генерировала лучшее описание):

Что показали результаты
Интересные наблюдения:
Все протестированные опенсорс‑модели значительно превзошли текущий baseline по качеству описаний.
DeepSeek‑Coder‑V2-Lite продемонстрировал лучший баланс между качеством генерации и потреблением ресурсов.
Qwen2.5-Coder-32B показал наивысшее качество, но требует существенно больше вычислительных мощностей.
Дополнительная валидация
Чтобы убедиться в надёжности результатов, мы провели несколько дополнительных проверок:
Сравнение одинаковых описаний между собой дало распределение оценок 57/43 — это говорит о приемлемом уровне шума в оценках со стороны LLM‑асессора.
Мы протестировали Qwen2.5-Coder-32B в роли альтернативного асессора (вместо Claude Sonnet). Результаты остались согласованными, что подтверждает воспроизводимость выводов.
А что с продакшном?
Мы также протестировали квантизованную версию Qwen2.5-Coder-32B в формате GGUF (Q4_M). Несмотря на существенное сжатие, модель показала сопоставимое качество (76% улучшения по сравнению с baseline) при среднем времени генерации ~ 9,4 секунды на 1 PR.
Что в итоге рекомендуем
Qwen2.5-Coder-32B — для максимального качества, если ресурсы позволяют.
DeepSeek‑Coder‑V2-Lite — отличный компромисс при ограниченных мощностях.
Qwen2.5-Coder-32B (Q4_M GGUF) — разумный вариант для продакшн‑сценариев, где важны стабильность и экономия ресурсов.
Можно ли проверить на реальных разработчиках?
В процессе работы у нас возник закономерный вопрос: а насколько вообще можно доверять оценке качества, сделанной языковой моделью? Может быть, разумнее запустить A/B‑тест и узнать мнение реальных пользователей?
Чтобы ответить на этот вопрос, мы провели эксперимент: проверили, заметят ли разработчики умышленное снижение качества описаний. Для этого мы обрезали входные данные:
удалили половину diff’а;
удалили половину commit‑сообщений.
Дизайн эксперимента:
контрольная группа (80%) — стандартная система генерации;
тестовая группа (20%) — система с урезанным контекстом;
метрика: доля описаний, которые были отредактированы вручную;
охват: все PR’ы в режиме «отдельный блок»;
длительность: две недели.
Сначала мы убедились с помощью Claude Sonnet, что снижение качества действительно есть: оценка «хорошести» описаний упала с 93% до 75%, хотя тексты по‑прежнему выглядели правдоподобно.
Разработчики редактировали описания с одинаковой частотой в обеих группах. 90% описаний принимались без изменений, даже в тестовой группе с ухудшенным качеством. Ручной разбор подтвердил: в тестовой группе описания были хуже — но это не повлияло на пользовательское поведение.
Эксперимент показал важный эффект: разработчики склонны доверять автоматической системе и не перепроверяют критически сгенерированные описания. Это делает классический A/B‑тест неэффективным инструментом для оценки качества таких систем — особенно если ухудшения неявные, но значимые.
Поэтому особенно важно применять автоматические методы оценки, такие как LLM as a judge, которые способны последовательно и объективно сравнивать разные варианты генерации.
Заключение
Мы начинали с простой и прагматичной задачи: улучшить существующую систему генерации описаний для Pull Request’ов. Базовая система уже работала на небольшой модели, но появление мощных опенсорс‑решений открыло путь к существенному росту качества.
Самый сложный вопрос оказался не техническим, а методологическим: как объективно измерить и доказать улучшение?
A/B‑тест с реальными пользователями не дал результата:
разработчики не замечали даже намеренно ухудшенных описаний, доверяя автоматической системе «по умолчанию».
Поэтому мы сделали ставку на подход LLM as a judge, использовав современные языковые модели как автоматических асессоров — последовательных, беспристрастных и чувствительных к нюансам.
На нашем пути было несколько ключевых этапов:
Определили критерии хорошего описания через опросы разработчиков.
Собрали датасет из 116 тысяч PR’ов из открытых репозиториев.
Провели итеративную оптимизацию промпта с LLM в роли оценщика.
Сравнили опенсорс‑модели между собой и с проприетарными решениями.
Что мы узнали:
Современные опенсорс‑модели (Qwen, DeepSeek, Codestral) могут конкурировать с GPT-4 в прикладных задачах вроде генерации описаний.
Автоматическая оценка с помощью LLM может быть более надёжной, чем человеческая, особенно при неочевидных различиях в качестве.
Оптимизация промптов должна опираться на объективные метрики, а не только на ощущения от «хорошего текста».
Наш подход к улучшению генеративных систем оказался не только эффективным, но и универсальным. Его можно применять и в других задачах, где требуется семантически точная генерация, таких как генерация технической документации, формулировка сообщений об ошибках, составление ответов на пользовательские запросы и автосоставление changelog’ов или release notes.