Гефестыч: наш опыт автоматизации Code Review через LLM. «Грабли», решения, код. atlassian.. atlassian. code review.. atlassian. code review. llama.cpp.. atlassian. code review. llama.cpp. llm.. atlassian. code review. llama.cpp. llm. ollama.. atlassian. code review. llama.cpp. llm. ollama. Open source.. atlassian. code review. llama.cpp. llm. ollama. Open source. openwebui.. atlassian. code review. llama.cpp. llm. ollama. Open source. openwebui. pydantic-ai.. atlassian. code review. llama.cpp. llm. ollama. Open source. openwebui. pydantic-ai. rag.. atlassian. code review. llama.cpp. llm. ollama. Open source. openwebui. pydantic-ai. rag. self-hosted.. atlassian. code review. llama.cpp. llm. ollama. Open source. openwebui. pydantic-ai. rag. self-hosted. Блог компании Леста Игры.. atlassian. code review. llama.cpp. llm. ollama. Open source. openwebui. pydantic-ai. rag. self-hosted. Блог компании Леста Игры. искусственный интеллект.. atlassian. code review. llama.cpp. llm. ollama. Open source. openwebui. pydantic-ai. rag. self-hosted. Блог компании Леста Игры. искусственный интеллект. качество кода.. atlassian. code review. llama.cpp. llm. ollama. Open source. openwebui. pydantic-ai. rag. self-hosted. Блог компании Леста Игры. искусственный интеллект. качество кода. Машинное обучение.

Введение

Кто мы?

Меня зовут Данил Чечков, я Team Lead команды High End Meta Backend в «Леста Игры». Мы занимаемся всей web-составляющей «Мира кораблей». В нашем арсенале огромное количество микросервисов, работающих на Python и Go. Мы отвечаем за покупки в meta-валюте, авторизацию, стабильность инвентаря и профиля игрока, клановые сервисы, а также многое-многое другое.

Наш основной продукт – высококачественные web-сервисы на стыке интеграции с игрой. И, да, интеграция – часть нашей работы.

А ещё мы любим новые технологии и стараемся с ними знакомиться, чтобы оценить, как они могут принести выгоду бизнесу и нам. Одна из таких технологий – LLM

Что сделали?

Гефестыча. Вы когда-нибудь копировали код из PR (MR) и отправляли LLM для объяснений? Вот и мы никогда, а решили попробовать. Попробовали, автоматизировали и интегрировали. Назвали – Hephaestus. Забегая вперёд, скажу, что нам очень понравилось. В этой статье я подробнее расскажу и про сам процесс внедрения, и про его преимущества.

Проблема

С чем столкнулись?

Поговорим о Code Review – это длительный и трудоёмкий процесс, который зачастую превращается в рутину. Чем больше объём изменений, тем меньше желания проводить ревью. Знакомо?

 ну ведь совсем не так

ну ведь совсем не так

А ещё постоянные сообщения в рабочий мессенджер, свои задачи и созвоны, которые мешают довести процесс до конца.

Одна из мер, которую мы ввели, – обязательный час в неделю на командное Cross Review. Это очень помогло разобрать очередь запросов на слияние, однако, и этого было мало.

Решение

«Если это может быть автоматизировано – это должно быть автоматизировано». Вот так я и подумал, когда пулл-реквесты стали висеть по две недели в ожидании ревью.

Тут я хотел бы сделать важное отступление. В нашем арсенале уже отлажены CI/CD процессы, линтеры, форматеры, единообразная архитектура и огромное количество unit-тестов. Всё это – первое, что вы должны сделать для повышения качества кода, доставляемого в продакшен. LLM – лишь вишенка на торте, которая доступным языком расскажет вам своё мнение.

Прежде чем рассказывать про нашу реализацию, перечислю возможные пути. Первый – закрытые платформы вроде CodeRabbit или Codium. Они хорошо работают, но код уходит на чужие серверы, что для нас риск. Второй – готовые открытые решения, например github/ai-review. Они появились, когда мы уже начали пилить Гефестыча, но сегодня я бы рекомендовал стартовать с них, чтобы сэкономить сотни человеко-часов. Третий – написать свою обёртку поверх self-hosted моделей.

Мы выбрали третий путь. В компании уже был инструмент для взаимодействия с LLM с открытыми весами – OpenWebUI во внутренней сети. Это удобный инструмент, предоставляющий OpenAI-совместимое API. А значит, можно написать инструмент для моделей с открытыми весами и в будущем, если появится такая возможность, переехать на нечто более мощное или закрытое и платное.

Минимальные системные требования: машина с VRAM около 24 гигабайт (у нас 4090), либо смирение с медленной скоростью обработки ревью при делегировании части работы на RAM и CPU.

Да, есть готовые и закрытые решения

Меня подстегнул пост Николая Соболева – сделать своё self-hosted-решение, которое можно крутить во внутренней сети компании и использовать все преимущества open-source-моделей.

Кроме того, уверен: если забить в поисковик Code Review AI, можно найти огромное количество закрытых решений, делающих свою работу очень хорошо.

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

Готовые и открытые решения

github/ai-review – забавно, но первая версия появилась примерно в то же время, когда Гефеста уже интегрировали в разработку нашим департаментом. Было уже поздно сворачивать или резко менять стек проверенных технологий, так что мы продолжили внедрение и развитие своей.

Сегодня я бы присмотрелся к этому варианту – он сэкономит вам сотню человеко-часов разработки: у вас будет решение, которое вы сможете впоследствии корректировать и совершенствовать уже внутренними усилиями.

Отличный вариант, чтобы оценить лично, насколько вообще могут быть полезны LLM-инструменты для Code Review именно вам и вашей команде.

Кроме того, мне удалось подготовить для вас сравнительную таблицу с открытыми self-hosted:

Сервис

Интеграция с системами управления проектами и задачами

Интеграция с сервисами системы управления версиями

Интеграция с корпоративной базой знаний

Кастомизация инструкций (per-project / per-PR)

RAG для поиска по кодовой базе

ai-review (Nikita-Filonov)

GitLab, GitHub, Bitbucket Cloud, Bitbucket Server, Azure DevOps, and Gitea

PR-Agent / Qodo Merge OSS

JIRA, GitHub Issues, GitLab Issues

GitHub, GitLab, Bitbucket, and Azure DevOps

❌ (только enterprise/SaaS)

⚠️ Конфиг есть, но только enterprise по факту (Qodo single-tenant/on-prem)

kodus-ai (Kodus)

через плагины/MCP

GitHub, GitLab, Bitbucket, and Azure Repos

code-review-gpt (mattzcarey)

только GitHub

villesau/ai-codereviewer

только GitHub

⚠️ Ограниченно (статические промпты; последнее обновление — дек. 2023)

cirolini/genai-code-review

только GitHub

⚠️

snarktank/ai-pr-review

только GitHub

⚠️

Codedog

GitHub + GitLab

Hexmos LiveReview

только GitLab

OpenReview (Vercel Labs)

только GitHub

⚠️ (агент обходит файлы в runtime, без постоянного индекса)

Sweep AI

только GitHub

✅ Да (индексация репо) — но лицензия BSL-1.1, не полностью FOSS

Гефестыч: наш опыт автоматизации Code Review через LLM. «Грабли», решения, код - 2

Имплементация

OpenWebUI

Вполне себе полноценный чат с любой загруженной в ollama LLM.

Я решил попробовать там скормить в виде .patch файлов diff и поспрашивать за качество изменений. И знаете – qwen3-coder:30b неплохо с этим справился. Да, ревью нельзя назвать совершенным, т.к. у qwen просто нет вашего контекста, но это поправимо. Однако, что qwen точно смог заметить, smelly, security и perf code issues. Получилось довольно душное Code Review, но с этим можно работать и настроить инструмент именно на ваш проект.

Open WebUI API

Кроме функционала чата, OpenWebUI также предоставляет OpenAI-совместимый API — казалось бы, вот он, фундамент для универсального инструмента автоматизации. Но не спешите. Именно на этом этапе мы совершили ошибку.

Усвоенные уроки

Я вам советую использовать llama.cpp напрямую, потому что в OpenWebUI API для загрузки документов и преобразования их в векторы для RAG — синхронное.

Заметили мы это слишком поздно, только на этапе проверок интеграции RAG и базы знаний для расширения контекста. Нас ввело в заблуждение асинхронное API для чата. Мы полноценно интегрировали весь функционал, проводя проверки на небольшом количестве файлов и получая ответы со статус-кодом 200.

А когда столкнулись с реальными нагрузками, осознали: в базу знаний попадает намного меньше файлов, чем мы отправляем. Пришлось чинить на ходу и превращать асинхронный код в синхронный.

Упс, техдолг.

Упс, техдолг.

Это огромный блокер, если вы планируете распространить сервис на большое количество департаментов, которые будут запускать систему в ревью ежедневно. Сразу остановитесь и переключитесь на ollama, llama.cpp или vllm.

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

Следующее, что мы сделали неверно, – написали небольшой клиент. Ради пары эндпоинтов мы не хотели интегрировать целую библиотеку, поэтому ограничились самописным клиентом к этому API.

Предостерегу вас от наших ошибок и порекомендую: сразу используйте Pydantic AI. Это целый набор инструментов, с которым организация подобной системы займёт не так много логики. Кроме того, это полноценный конструктор для того, чтобы вы могли сделать что угодно с LLM.

Псевдокод

Начинаем с провайдера

Предположим, что вы уже подняли ollama/llama.cpp. Если ещё нет, то это довольно легко сделать:

from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIChatModel
from pydantic_ai.providers.ollama import OllamaProvider
  

ollama_provider = OllamaProvider(
    base_url="http://localhost:11434/",
    api_key="your_amazing_api_key",
)

model = OpenAIChatModel(
    model_name="qwen3-coder:latest",
    provider=ollama_provider,
)

agent = Agent(model=model)

result = agent.run_sync("Hello world!")
print(result.output)

Это очень лаконичный код на фоне того, что мы написали для наших клиентов.

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

А какой контекст?

Давайте на пути к реализации представим, что у вас есть такие методы, и заодно обсудим, почему они важны.

Jira/GitHub/Gitlab Issues

Контекст и качество задачи напрямую повлияют на результат ревью. Начните с пересмотра процессов, если ваши задачи выливаются в запрос на слияние в 500 млн изменений на 150 тысяч файлов.

# docs: Содержание,тайтл и коментарии к задаче
def _get_issue_context(issue_code:str) -> str:
    pass

Если задача была про синие кнопки, а на выходе получили оранжевые шрифты, у LLM будут вопросы. И это вполне себе правильные вопросы, но скорее процессуального характера.

В нашем случае получилось воспроизвести интересный кейс. Есть библиотека на фронте, в которой расположены иконки. Есть эпик, в котором сформированы задачи на обновление версии библиотеки в сервисах. Каждый ПР в таком случае выглядит одинаково – вы обновляете версию пакета, прописываете CHANGES и ждёте RFI хотя бы апрува.

Гефест приходит в 2 таких PR и ставит одному approve, а другому need work:

Гефестыч: наш опыт автоматизации Code Review через LLM. «Грабли», решения, код - 4
Гефестыч: наш опыт автоматизации Code Review через LLM. «Грабли», решения, код - 5

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

В то же время в другой задаче комментарием к Jira issue было чётко указано, какая версия библиотеки нужна. Гефест говорит: мужик, ты всё сделал правильно – вот тебе approve.

Корпоративная база знаний

# docs: Документация для сервиса/репозитория
def _get_service_docs(docs_ids: list[str]) -> list[str]:
    pass

Я не стану распыляться, лишь скажу – для проектов нужна документация. Чтобы понимать, что там вообще происходит и как оно было задумано создателем.

Самое главное – diff

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

Есть 2 стула варианта реализации. Первый: классический .patch файл. Его можно сформировать с помощью git или использовать уже готовое API для этого:

  • Github: https://patch-diff.githubusercontent.com/raw/{projectKey}/{repositorySlug}/pull/123.patch

  • Bitbucket: https://your_host/api/latest/projects/{projectKey}/repos/{repositorySlug}/pull-requests/{pullRequestId}.patch

Второй вариант, на котором мы остановились, – формировать diff в виде .md файлов. Мы написали свой парсер.

И тут, пожалуй, требуется пояснение.

Разные модели ведут себя по-разному с разным типом diff. Серьёзно, qwen3-coder сходит с ума с .patch файлом. gpt-oss:20b, кстати, ведёт себя довольно схожим образом.

Кроме того, важен не только формат, но и его компоновка. Сначала мы формировали каждый файл в отдельное сообщение. Удивительно, но даже при большом контекстном окне LLM умудрялись их терять. qwen3-coder вообще довольно плохо работает с сообщениями от пользователя, если на них ранее не было ответов.

Поэтому мы пошли таким путём: собираем весь diff в md. Пакуем в одно сообщение и отправляем.

# docs: Запрос diff
async def get_diff(project: str, repository_slug: str, pr_id: str) -> str:
	pass

Codebase

from pathlib import Path

# docs: Запрос файлов для внедрения в контекст
async def get_code_context(project: str, repository_slug: str, pr_id: str) -> list[Path]:
    pass

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

Вариантов на самом деле много:

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

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

  • Сформировать source tree и попросить LLM выбрать необходимые для ревью файлы самостоятельно.

Мы остановились на первом и решили довериться эмбедингу и RAG. Путь довольно трудный. Предостерегу вас: необходимо будет продумать не только процесс векторизации, но и что делать с файлами по мере их «охлаждения». Это задача, которая может занять очень много времени и потребовать более глубокого понимания того, как работают нейросети. Однако, преодолев эти трудности, у вас получится шикарное Code Review.

Что дальше?

Каждый из источников информации может стать отдельной tool для LLM.

...
agent = Agent(model=model, deps_type=PRDeps)


# docs: Содержание, тайтл и коментарии к задаче
@agent.tool
def get_issue_context(ctx: RunContext[PRDeps]) -> str:
    issue_code = ctx.deps.issue_code
    issue_context = _get_issue_context(issue_code)
    return issue_context


# docs: Документация для сервиса/репозитория
@agent.tool
def get_service_docs(ctx: RunContext[PRDeps]) -> str:
    docs_ids = ctx.deps.docs_ids
    documentation = _get_service_docs(docs_ids)
    return documentation


# docs: Запрос diff
@agent.tool
def get_diff(ctx: RunContext[PRDeps]) -> str:
    diff = _get_diff(
        project=ctx.deps.project,
        repository_slug=ctx.deps.repository_slug,
        pr_id=ctx.deps.pr_id,
    )
    return diff
...

Я очень рекомендую к прочтению инструкцию pydantic по этому поводу и скажу, что pydantic AI оперирует дополнительным вариантом — instructions: это своеобразное расширение системного промпта.

Кроме того, что уже есть, вы можете настроить поведение tools так, что модель сможет сама ставить approve либо need work в зависимости от результатов ревью.

Retrieval Augmented Generation

Если вам не знакомо это понятие, то я рекомендую вам почитать статьи на Хабре, в которых это уже описано (например, тут и тут).

Pydantic AI, к слову, предоставляет функционал и для этого:

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

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

Даже без этого шага качество ревью будет оставаться удовлетворительным. Это будет похоже на ревью разработчика, который недавно пришёл из другой компании и пытается навязать свои правила, однако, security и perf issues система всё же выявит.

В нашем конкретном случае введение RAG позволило улучшить качество проводимого ревью тем, что количество замечаний Гефеста, на которые реально хочется обратить внимание, выросло примерно до 7 из 10.

Как это выглядит?

Гефест – это надстройка над движком LLM, которая использует общепринятое API для выполнения задачи автоматизированного Code Review.

Гефест – это надстройка над движком LLM, которая использует общепринятое API для выполнения задачи автоматизированного Code Review.

Давайте из этой формулировки перейдём к следующему преимуществу системы.

AIaaS

При построении такого сервиса важно понимать, что это не просто proof of concept, а универсальный инструмент на вырост. И ставку вы делаете не только на развитие открытых моделей, а на развитие LLM как отрасли и инструмента.

Недавним примером того, что ставка выигрышная, стал релиз Opus 4.6 с контекстным окном в 1M токенов. Представьте, каких показателей получится достичь, если даже полностью открытая младшая модель Qwen3 Coder уже сегодня удовлетворительно проводит ревью. Разница между релизами, к слову, полгода.

Обобщая вышесказанное, вы создаёте обёртку, которая может работать на любом типе LLM-моделей. С увеличением качества последних ваш инструмент будет показывать лучшие результаты с минимальными затратами на обслуживание. Потрясающе?

Гефестыч: наш опыт автоматизации Code Review через LLM. «Грабли», решения, код - 7

Автор: DanilChechkov

Источник