- Дата публикации
AI-ревьюер для pull request’ов: как команда YADRO выбирала LLM и собирала бэкенд
Что нового
Команда YADRO собрала внутреннего AI-помощника, который автоматически ревьюит pull request’ы с автотестами.
Что он умеет:
- Анализирует только добавленный и изменённый код в PR.
- Ищет проблемы в стиле, логике и конструкциях кода.
- Оставляет комментарии прямо в pull request’е с конкретными правками.
- Снимает с инженеров рутину по поиску однотипных ошибок, особенно в коде стажёров.
Ключевые технические решения:
- Используются локальные LLM в формате GGUF, оптимизированные под CPU.
- Квантование «золотой середины» — Q4_K_M: разумный баланс между размером и качеством.
- Протестированы несколько моделей, от компактных до более тяжёлых:
| Модель | Размер репозитория, GB | Размер GGUF, GB | |---------------------|------------------------|------------------| | Microsoft/phi-2 | 5.5 | 1.7 | | TinyLlama | 2.2 | 1.1 | | Mistral | 15 | 4.2 | | Qwen3 | 6 | 2.81 |
- Для оценки качества брали реальную ошибку автотеста, связанную с неверной версией библиотеки: отсутствие символа
tboost_set_log_levelвlibtboost_sdk.so. - Модели сравнивали по тому, как они объясняют ошибку и предлагают варианты исправления.
Фокус не на максимальной скорости, а на практической пользе: бот не самый быстрый, но хорошо ловит повторяющиеся ошибки и экономит время на ревью.
Как это работает
Архитектура в общих чертах
- Разработчик открывает pull request с изменениями в автотестах.
- CI/CD или Git-хук вызывает бэкенд AI-ревьюера.
- Бэкенд:
- получает diff PR;
- фильтрует только добавленные и изменённые участки кода;
- формирует промт для LLM (контекст + инструкции по ревью);
- отправляет запрос на локальный сервер с LLM в формате GGUF;
- получает ответ и превращает его в комментарии к PR.
- Инженер видит комментарии бота и уже сосредотачивается на более сложных аспектах: корректность pytest-марок, соответствие автотеста описанию в TestY TMS и т.п.
Почему GGUF и квантование Q4_K_M
Команда запускала модели на CPU-сервере, без дорогих GPU. Для этого нужны компактные и быстрые форматы:
- GGUF — бинарный формат, оптимизированный для работы с LLM на CPU: быстрее загружается и экономит память.
- Квантование снижает точность чисел в весах модели, уменьшая размер и требования к RAM.
- Профиль Q4_K_M:
- большинство параметров хранится в 4-битном формате;
- качество всё ещё приемлемое для анализа кода;
- размер файлов — от 1.1 до 4.2 GB для протестированных моделей.
Подход к исследованию: сначала проверяли самые маленькие модели (минимальная нагрузка), затем переходили к более крупным (лучшие аналитические способности), пока не находили рабочий баланс.
Тестовый сценарий для выбора модели
Чтобы сравнить модели не абстрактно, а по реальной пользе, им давали один и тот же кейс:
Ошибка автотеста:
AttributeError: /opt/tboost-sdk/libtboost_sdk.so: undefined symbol: tboost_set_log_level
Задача для LLM (перевод промта на русский):
Объясни, почему произошла ошибка:
AttributeError: /opt/tboost-sdk/libtboost_sdk.so: undefined symbol: tboost_set_log_level. Как это пофиксить?
Критерии оценки:
- Понимает ли модель, что происходит на уровне нативной библиотеки (
.so) и символов? - Даёт ли реалистичные причины (сборка, версии, несовместимость), а не выдуманные истории?
- Предлагает ли конкретные шаги по исправлению?
Как отвечали разные модели
Microsoft/phi-2
- Придумала несуществующий лог-файл, которого не было в промте.
- Не дала рабочих советов по исправлению.
- Вывод: слишком много «галлюцинаций», мало пользы.
TinyLlama
- «Рассказала» историю про установку
libtboost_sdkчерезpip, которой тоже не было в исходных данных. - Предлагала переустановить библиотеку через
pip, что не решает проблему отсутствующего символа в.so. - Вывод: ответы выглядят правдоподобно, но к реальной ошибке почти не привязаны.
Mistral
- Правильно определила суть: в
libtboost_sdk.soнет символаtboost_set_log_level. - Предложила проверить установку библиотеки и процесс сборки нативной части.
- Указала на необходимость корректной сборки C-библиотеки и её совместимости с Python.
- Вывод: здравое объяснение и адекватные шаги по исправлению.
Qwen3
- Чётко описала проблему: символ не найден в
.so. - Предложила несколько возможных причин, связанных с несовместимостью версий и установкой библиотеки.
- Часть пунктов получилась повторяющейся, но общий посыл — разумный.
- Вывод: даёт набор гипотез и направлений для поиска ошибки.
Именно по такому типу задач команда оценивала, годится ли модель в роль ревьюера кода.
Что это значит для вас
Где AI-ревьюер реально помогает
-
Команды с большим потоком PR. Бот разгружает инженеров от однотипных комментариев и помогает не пропускать базовые ошибки.
-
Работа со стажёрами и джунами. Частые проблемы — огромные PR, повторяющиеся баги стиля и логики. AI-ревьюер стабильно указывает на такие вещи и обучает через комментарии.
-
Автотесты и инфраструктурный код. Для тестов особенно важны аккуратные конструкции, корректные маркировки, понятная логика. Бот помогает поддерживать единый уровень качества.
-
Инженеры, которые не хотят тянуть облачные сервисы. Всё крутится локально на CPU-сервере, без передачи кода во внешние API.
Где не стоит на него полагаться
-
Архитектурные решения и сложная бизнес-логика. Локальные квантованные модели уровня Mistral/Qwen3 в GGUF хорошо ловят паттерны, но не заменяют опытного архитектора.
-
Безопасность и критичные участки. Проверка на уязвимости, криптографию, тонкие гонки потоков — зона ответственности людей и специализированных инструментов.
-
Проекты, где важна максимальная скорость фидбэка. Модели в GGUF на CPU работают медленнее, чем облачные LLM на мощных GPU. Если вам нужно ревью за секунды, такой подход может не устроить.
Практические выводы, если вы хотите сделать так же
- Начинайте с чёткого сценария: что именно бот должен делать в PR (стиль, логика, тесты, безопасность?).
- Не берите сразу «самую большую» модель. Пройдите путь, как в YADRO: от TinyLlama/phi-2 к Mistral/Qwen3 и посмотрите, где качество уже устраивает.
- Обязательно проверяйте модели на реальных ошибках вашего проекта, а не на абстрактных примерах.
- Заложите время на настройку промтов: от формулировки инструкций сильно зависит полезность комментариев.
AI-ревьюер не снимает с инженеров ответственность за код, но хорошо закрывает рутину и помогает выровнять качество по команде.
Место на рынке
YADRO собрала не публичный продукт, а внутренний инструмент, построенный на открытых моделях. Его логично сравнивать не с GPT-4o или Claude 3, а с другими локальными LLM и подходами к ревью кода.
По ключевым параметрам подход выглядит так:
-
Тип развёртывания.
- Локальный сервер на CPU с GGUF-моделями.
- Без зависимости от внешних API и их SLA.
-
Размер и ресурсы.
- Используются модели от 1.1 до 4.2 GB в GGUF.
- Это заметно легче, чем разворачивать полноразмерные не-квантованные версии (до 15 GB и выше).
-
Качество анализа кода.
- Компактные модели вроде TinyLlama и phi-2 хуже справляются с техническим разбором ошибок и склонны «галлюцинировать».
- Более крупные варианты уровня Mistral и Qwen3 дают внятные объяснения и реальные пути решения.
-
Интеграция в процессы.
- Инструмент встраивается в существующий workflow ревью PR.
- Работает рядом с TestY TMS, который команда YADRO использует для управления тестами.
Если вы сейчас смотрите на рынок инструментов для ревью кода, то подход YADRO показывает рабочий сценарий: не ждать «идеального» облачного ассистента, а собрать свой стек из открытых моделей, оптимизированных под ваши ограничения по железу и приватности.
Как запустить локальную LLM (общая схема)
В исходном материале нет полного кода бэкенда, но по описанию можно набросать базовый сценарий запуска локальной модели в формате GGUF на CPU.
1. Скачать модель в GGUF
Модели в формате GGUF обычно лежат на HuggingFace. Пример (общее направление, не конкретный репозиторий):
# Установить huggingface-cli, если его нет
pip install -U huggingface_hub
# Авторизоваться, если нужно
huggingface-cli login
# Скачать модель (примерное имя, подставьте нужное)
huggingface-cli download mistral-7b-instruct-q4_k_m --local-dir ./models/mistral-7b-q4
2. Запустить сервер с LLM
Один из вариантов — использовать llama.cpp или совместимые обёртки.
Пример для llama.cpp (концептуально):
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make
# Запуск сервера с GGUF-моделью
./server \
-m ./models/mistral-7b-q4/model.gguf \
-c 4096 \
-ngl 0 \
-t 8
Где:
-m— путь к GGUF-файлу.-c— длина контекста (зависит от модели и ресурсов).-ngl 0— всё на CPU.-t— количество потоков.
3. Подключить бэкенд ревьюера
На стороне вашего сервиса ревью кода логика выглядит так (псевдокод):
import requests
def build_prompt(diff: str) -> str:
instructions = (
"Ты помощник по ревью кода. "
"Проанализируй только добавленные и изменённые строки. "
"Ищи проблемы стиля, логики и типичные ошибки в автотестах. "
"Отвечай кратко, в формате списка комментариев."
)
return f"{instructions}\n\nИзменения в PR:\n{diff}"
def call_llm(prompt: str) -> str:
response = requests.post(
"http://localhost:8080/completion",
json={
"prompt": prompt,
"max_tokens": 512,
"temperature": 0.2,
},
timeout=120,
)
response.raise_for_status()
return response.json()["content"]
def review_pull_request(diff: str) -> str:
prompt = build_prompt(diff)
llm_answer = call_llm(prompt)
return llm_answer
Дальше остаётся:
- разобрать ответ модели;
- сопоставить комментарии с конкретными строками diff;
- отправить их в систему контроля версий (GitHub, GitLab, Gerrit и т.п.).
Этот каркас придётся адаптировать под ваш стек, но общая идея совпадает с тем, как YADRO интегрировала AI-ревьюера в свой процесс разработки.