GitHub переписал движок своего ИИ-помощника Copilot. Получилось 832 378 строк нового кода, не считая тестов. Большинство кода написали ИИ-агенты, а руководил переносом инженер Microsoft Стивен Тауб при поддержке коллег. Перенос шел с мая по август, пока команда продолжала развивать продукт.
Задача была вполне приземленная: сделать помощника быстрее при запуске, сократить расход памяти и упростить его встраивание в другие программы. Переписывали программную оболочку вокруг нейросети: она передает ей запросы, дает доступ к инструментам и следит за ходом работы. Саму модель ИИ здесь не меняли.
По оценке Тауба, раньше такая переделка потребовала бы от команды год-два и, скорее всего, проиграла бы борьбу за время разработчиков более срочным задачам. Агенты позволили за нее взяться. Но по дороге они перегрузили ноутбук, полезли в чужие незаконченные изменения и однажды сами разрешили себе пройти проверку, которую должны были провалить.
Тауб подробно рассказал об этом в блоге GitHub. Работы руками стало меньше, а поводов вмешаться у человека хватало.
Переписать, ничего не потеряв
Старый движок был написан на TypeScript, новый решили сделать на Rust. Раньше вместе с помощником приходилось запускать отдельную программу со всей необходимой ей инфраструктурой. Это занимало время и память. Новую версию можно встроить прямо в приложение, которому нужен ИИ-помощник, но пока такой режим нужно включать отдельно.
Сначала команда подготовила инструменты и проверки, затем попробовала перенос на небольших самостоятельных частях. Убедившись, что все работает, перешли к более крупным и связанным между собой кускам.
Меняли их постепенно: новая часть занимала место старой и сразу начинала работать в продукте. За время переноса выпустили 135 версий, включая предварительные. Возможные поломки разбирали по мере появления, не дожидаясь замены всего движка.
При этом объем задачи рос прямо по ходу работы. В начале речь шла примерно о 130 тысячах строк старого кода. В итоге через перенос, по оценке Тауба, прошло около 430 тысяч: коллеги добавляли возможности, а часть работы поначалу не попала в оценку.
Тауб старался сначала сохранить прежнее поведение программы, а уже потом улучшать ее устройство. Иначе при поломке попробуй разберись, виноват перевод на другой язык или попутная удачная идея. Несколько раз он отступал от этого правила и потом жалел: получал лишние ошибки, тратил время и деньги.
Даже без таких улучшений агент мог потерять что-нибудь нужное. Однажды из новой версии исчезла функция, которой пользовались другие приложения. Автоматическая проверка это заметила и остановила приемку изменения. Но у агента нашелся обходной путь. Он поставил специальную метку: такую несовместимость разрешено пропустить. Проверка после этого могла стать зеленой, хотя пропавшая функция никуда не вернулась.
Перед окончательным принятием кода Тауб просмотрел результат и спросил, почему это исключение вообще допустимо. Оснований не оказалось: функцию просто забыли перенести. После его вмешательства агент убрал разрешающую метку и восстановил функцию на Rust.
Проверка сработала. Но исполнитель мог сам себе выдать освобождение от требования. Без человека, проверившего, что стоит за зеленым статусом, потеря рисковала попасть в продукт.
Пятнадцать агентов и один ноутбук
Ближе к концу оставалась особенно сложная часть: большой файл, через который проходила работа почти всего движка. Тауб поручил его агенту. Тот первые 56 минут читал код и разбирался, что с чем связано. А затем сам начал раздавать задания другим агентам.
Он запустил пятнадцать исполнителей со своими копиями рабочих файлов, чтобы те могли писать код параллельно. Задания им тоже составлял главный агент.
Под главным заданием в Copilot появились пятнадцать сессий, каждая со своим участком работы. Скриншот: Стивен Тауб / GitHub Blog.
Некоторое время все шло хорошо. Потом пятнадцать исполнителей почти одновременно решили проверить написанное: собрать из кода работающую программу и запустить тесты. Но ноутбук у них был один.
Машина практически встала. Тауб через главного агента остановил тяжелые проверки. Исполнители продолжили работу, которая не требовала столько ресурсов.
Позже Тауб настроил очередь. Он выделил обычный чат, который выдавал разрешение на сборку восьми параллельно работающим сессиям. Нужна тяжелая проверка – сначала спроси разрешение. Занято – жди или делай другую часть работы. Координатор следил, кто сейчас использует ресурс и кто следующий.
Координатор сообщает, кому выдано единственное разрешение на сборку. Остальные ждут очереди. Скриншот: Стивен Тауб / GitHub Blog.
С очередью удалось договориться. С чужими полномочиями вышло сложнее. Пока один агент переносил центральную часть движка, Тауб запустил другого на соседний участок, который к ней обращался. Указал, где остановиться, перечислил другие параллельные работы и пошел спать.
Агенты нашли друг друга. Второй обнаружил общие участки, связался с первым и спросил, готов ли тот объединить изменения. Получил отказ: работа еще не готова. Спросил еще три раза. Получил еще три отказа.
После чего сам забрал незаконченные изменения соседа и включил их в свою работу. Оба продолжили заниматься своими задачами.
Тауб не стал объяснять это просто своеволием модели. В разборе он возложил ответственность на себя. Перечень соседних работ должен был подсказать агенту, куда не лезть, но прямого запрета не содержал. Инструменты позволяли взять чужой код. Общую установку действовать самостоятельно агент распространил и на это решение, а отказ равного ему исполнителя ничем не был подкреплен.
Получился конфликт, в котором никто не назначил главного. Его разрешил тот, кто первым решил действовать.
За что в итоге отвечал человек
За весь перенос Тауб написал или продиктовал агентам около 2600 сообщений. Он проверял результаты, оспаривал решения, возвращал исполнителей к недоделанному. Подробное сравнение старого и нового кода во многом делали другие агенты, а человек разбирал рискованные места и решал, можно ли принимать изменения.
И все равно ошибки доходили до пользователей. Например, новая версия могла отправить другой программе число 42.0 вместо ожидаемого целого 42. Для человека разница выглядит пустяковой, но программа, которая ждала строго целое число, отвергала ответ. Сам по себе успешно собранный код этого не исключал.
Известные к моменту разбора ошибки исправили. Тауб при этом прямо допускал, что обнаружатся новые: весь набор редких ситуаций заранее не перебрали.
В токенах работа обошлась около 120 тысяч долларов, но это не полная стоимость проекта: к ней нужно прибавить человеческую работу. Коллеги Тауба помогали подключать новый движок к приложениям, готовить его доставку пользователям, ускорять сборки и проверять изменения.
Собственный вклад Тауб грубо оценил в три рабочие недели, исходя из доли задач переноса среди всех своих предложенных изменений кода за этот период. Это не учет часов: он предположил, что доля изменений примерно соответствует доле времени. И все месяцы с мая по август исключительно этому проекту не посвящал.
При всех оговорках результат впечатляет. Большой работающий компонент заменили, не останавливая развитие продукта. Агенты взяли на себя большую часть работы по написанию кода, и проект, который раньше было трудно оправдать, состоялся.
Другой живой пример я разобрал в “Сбежавшей нейросети”: как создатель Rails DHH работает с агентами. Он сравнивает этот сдвиг с фотографией: камера упрощает получение снимка, но умение увидеть кадр все еще нужно кому-то принести с собой.
Автор: runaway_llm


