10–15 багов в месяц превратились в 200–300 — а кому их фиксить?. kaiten.. kaiten. llm.. kaiten. llm. автоматизация рутины.. kaiten. llm. автоматизация рутины. багфикс.. kaiten. llm. автоматизация рутины. багфикс. Блог компании Kaiten.. kaiten. llm. автоматизация рутины. багфикс. Блог компании Kaiten. искусственный интеллект.. kaiten. llm. автоматизация рутины. багфикс. Блог компании Kaiten. искусственный интеллект. нейросети.. kaiten. llm. автоматизация рутины. багфикс. Блог компании Kaiten. искусственный интеллект. нейросети. промпт-инжиниринг.. kaiten. llm. автоматизация рутины. багфикс. Блог компании Kaiten. искусственный интеллект. нейросети. промпт-инжиниринг. процессы разработки.. kaiten. llm. автоматизация рутины. багфикс. Блог компании Kaiten. искусственный интеллект. нейросети. промпт-инжиниринг. процессы разработки. Управление проектами.
10–15 багов в месяц превратились в 200–300 — а кому их фиксить? - 1

Фиксить рутинные баги — это отстой. Никто в здравом уме не просыпается с мыслью: «О, как же я хочу сегодня весь день ковырять чужой легаси-код, чтобы понять, почему кнопка в IE11 уезжает на три пикселя влево!»

Так-то мы хотим пилить фичи, строить архитектуру, пить кофе и приходить на перфоманс-ревью просить зарплату больше.

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

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

Короче, нас засыпало. Если раньше приходило 10–15 в месяц, то стало 10–15 в день. А дальше классическая дилемма:

— Если заставить сеньора месяц разгребать минорные баги, он просто выгорит и уйдёт.

— Нанимать джунов фиксить баги — хорошая идея, но не в этом случае.

— Поручить всё это дело нейросетям — возможно, выстрелить себе в ногу.

А когда мы пропускали шанс выстрелить себе в ногу? Короче, сейчас процесс выглядит так: баг попадает на доску в нашем Кайтене, летит в специальную колонку, там его подхватывает модель, пишет фикс, делает саморевью, делает тесты, собирает Pull Request, второй независимый агент в репозитории делает ещё контрольное ревью, и дальше это попадает на ревью к человеку.

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

Когда баги только начали сыпаться толпой

Мы сначала очень расстроились.

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

А дальше начинается боль деплоя: мы идём друг за другом, создаётся очередь, нужно постоянно обновлять свой код из мастера, ждать аппрувов от коллег. На простейший баг уходят часы. Из-за этого мелкие, незначительные тикеты просто лежали в бэклоге месяцами.

То есть там было две проблемы:

— Сама рутинность задач.

— И куча промежуточных потерь, пока ждёшь другого человека.

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

«Устал я время тратить, пусть нейронка делает»

Идея автоматизировать эту тоску жила у нас в бэклоге месяцы, если не годы.

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

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

На MVP гоняли синтетические локальные тесты. Дали модели локальный репозиторий и стали работать с задачами типа просто перечислить и добавить имена футболистов. Смотрим — реально ориентируется в репозитории, понимает контекст и делает.

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

90% этих задач нейросеть проглотила с первого раза и сделала нормальный PR.

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

Как ограничить ИИ, чтобы он не сломал прод

К тому моменту в компании уже официально внедрялся подход AI First. Правило простое: чего-то не понимаешь — перед тем как дёргать живого человека, спроси нейронку.

Разработчики уже активно использовали AI-ассистентов для экономии времени на погружение в контекст и написание бойлерплейта. Но у нас не было никакой автономной работы моделей — LLM — это инструмент, а не замена разработчику.

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

Внутри каждого лежат файлы с контекстом: архитектурное описание, гайдлайны по код-стайлу, которых мы придерживаемся.

Промпты менялись постоянно. Сначала модель пыталась лезть в дебри, куда не следует. Нам пришлось жёстко связать ей руки инструкциями: делай чётко то, что описано; не делай того, чего не требуется; не предлагай того, о чём не просят; за минимальное время и минимальными средствами почини баг и не рыпайся.

Не все задачи попадают к модели. Перед тем как скормить задачу в этот поток, есть ручной фильтр. Тимлид читает карточку без глубокого погружения и, опираясь на опыт, распределяет. Если это понятный баг в рамках одного репозитория — отдаём ИИ-кодеру (наш ИИ-помощник). Если понятно, что баг — это не просто мини-фикс, а проблема, которая аффектит схему базы данных или давно устоявшиеся сложные процессы, либо затрагивает личные данные компаний-клиентов, — задача идёт мимо нейросети в очередь к живым разработчикам для ресерча.

При этом описания багов для ИИ никто специально не меняет и не дописывает — он получает ровно то, что написала служба поддержки (с описанием процесса воспроизведения). Если шаги воспроизведения непонятны, мы просим тестировщика попытаться воспроизвести баг и описать кейсы по-человечески. В итоге к моменту начала конвейера есть достаточно точное техническое задание.

Сам процесс

Так как мы сами делаем канбан-доски, мы собрали для ИИ-кодера отдельную доску с колонками: бэклог, в работе, PR готов и передано на тестирование.

10–15 багов в месяц превратились в 200–300 — а кому их фиксить? - 2

Правда, совсем бесконтрольно магия пока не работает: разработчик всё равно должен запустить процесс для конкретной задачи, проконтролировать и перевести её. Робот работает в режиме Concurrency 1 — берёт строго один инстанс за раз. На один баг уходит около 20–40 минут: он клонирует репо, изучает контекст, пишет код. То есть как раз за день всё разбираем.

Дальше идёт автоматическое составное код-ревью. Сначала ИИ-кодер делает селф-ревью. Затем создаёт Pull Request. Дальше к репозиторию подключаются наши плагины и совершенно отдельная самостоятельная нейронка, которая финально перепроверяет код на уязвимости и архитектурные косяки.

Если на этапе PR падают тесты (CI пайплайны), ИИ не сдаётся: у него есть доступ к логам. Он смотрит, что завалилось, понимает, что не учёл, и возвращается доделывать. Бывает, что на баг уходит несколько таких раундов. Если ни один тест не упал и регресс пройден, код выкатывается на стейдж-сервер.

Только на этом этапе подключаются люди — сразу двое. Живой разработчик просто просматривает готовый код глазами как ревьюер, а тестировщик параллельно проверяет по тест-кейсу, что должно быть и что получилось (и что баг больше не воспроизводится). Если проблема осталась, тестировщик пишет замечание прямо в карточку или PR. AI-кодер подхватывает эту обратную связь, анализирует свой прошлый код и вносит правки. 80–90% задач пролетают этот конвейер с первой итерации.

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

Робот копит аппрувленные задачи и выкатывает их ночью, пока все спят. «Папа, не деплой в пятницу, тебя ждут дома» — такого нет.

Как развивались промпты

  1. Базовый скелет: «You are implementing a task from a Kaiten card» + заголовок/описание карточки + 5 строк инструкций (работать только в репозитории, изменения минимальные, следовать code style и архитектурным гайдлайнам, не запускать вотчеры/серверы).

  2. Дальше добавили контекст карточки, список файлов/встроенных картинок, потому что часто в карточках ТЗ в макетах/файлах/скриншотах, а не в тексте.

  3. В Кайтене задачи иерархичны; контекст эпика нужен, но был риск, что агент начнёт делать родителя вместо непосредственной задачи. Появилась секция связанных карточек описаниями предков + оговорка «это только фон, реализуй задачу из основной карточки, а не из предков».

  4. Описание PR — агент пишет финальное описание PR в файл вне рабочего дерева на русском; если есть PR-шаблон репозитория — использовать его структуру; иначе — короткое тело с «Закрывает карточку…», «Изменения», «Тестирование». Надо было, чтобы отделить тело PR от кода (его не нужно коммитить), стандартизировать описания и соблюдать шаблоны PR целевых репозиториев.

  5. Потом добавили секцию ## Returning to an existing branch (только при followUp): прочитать git log/diff base..HEAD, относиться к прежнему коду как к черновику, чинить/удалять. Это потому, что карточку возвращают из ревью на доработку. Без этого агент игнорировал или дублировал прежнюю работу.

  6. Добавили ## Comments — комментарии самой карточки и предков, с автором и привязкой к источнику. Уточнения и причина возврата карточки чаще всего живут именно в комментариях.

  7. PR’ы падали на CI из-за линта. Дальше линтер + дисциплина PR-шаблона. Найти lint-скрипт (lint:check/lint, предпочесть read-only вариант), прогнать и чинить до зелёного.

  8. Агент уходил чинить чужой lint-долг, раздувал диффы и тратил время/токены. Потом линтер научили гонять только по изменённым/добавленным файлам и чинить ошибки только в них, а не во всём репозитории.

Что не так

Конечно, бывают возвраты. Мы даём ИИ три попытки. Если за три захода он не справился, задача переводится целиком в ручной режим с полноценным расследованием. Иногда нейронка просто зацикливается и выдаёт: «Всё, я не могу поправить, правьте сами». Таких возвратов у нас около 5%, это штучные истории.

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

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

За несколько месяцев потоковой работы — а робот чинит десятки багов в сутки — мы ни разу ничего не уронили на проде и не сломали. Нас спасает полный регресс-набор автотестов перед мерджем в мастер. Если падает хоть один тест, задача не передаётся на тестирование и возвращается. Максимум, что у нас было: на стейдже с тестовыми данными баг казался починенным, а на проде с реальным контекстом всплывал снова.

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

Результат

Раньше баги выжигали нервы сразу двух разработчиков из-за рассинхрона и дёрганий.

Теперь на такие задачи уходит время только одного человека. Нейросеть не страдает от того, что её PR висит без аппрува. Разработчик просто решает, что у него есть полчаса в день только на баги.

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

Психологически для команды это стало огромным облегчением.

Залежи минорных багов, которые копились месяцами, наконец-то пропущены через эту автоматическую мясорубку. Бэклог очистился.

Сейчас мы дописываем новый функционал ИИ-кодеру, чтобы спихивать и другую рутину. Например, научили его автоматически верстать. Например, если срочно нужен лендинг, кидаем в карточку ИИ-кодера ссылку на макет в Фигме, он понимает, что нужно делать, забирает дизайн, верстает всё сам и отдаёт тестировщику на визуальную сверку.

Следующий шаг — отдать ИИ рутинные запросы от смежных отделов. Например, маркетинг постоянно приходит с экспериментальными запросами на выгрузку из баз данных. Раньше для этого нужно было идти в Mattermost, писать заявку на девопсов, ждать человека с правами доступа. Скоро ИИ-кодер будет забирать эти тикеты и сам лезть в базу. Права ему выданы на реплику базы, в read-only режиме, с жёсткими лимитами по ресурсам и таймаутам. Права не ко всей БД, а к скрипту, написанному человеком, который вытаскивает из БД чётко указанные колонки, не затрагивая персональные данные и прочее. То есть изначально есть очень узконаправленный канал получения данных, к которому подключена ИИ-модель.

Так что вот, работает же.

Автор: dimaninc

Источник