
В своей прошлой статье я писал о том, как мы упростили процесс написания платёжных POS-интеграций для касс и киосков самообслуживания. Кратко перескажу: интеграция представляет собой JS-модуль (далее плагин). Он импортируется в рантайме в frontend-приложение. Интеграции пишут команды на аутсорсе, а мы добавляем новые enum, несколько моделек и немного мапперов в пару мест. После этого интеграция начинает работать везде, где надо.
С того момента, как мы запустили первого платёжного провайдера, прошёл год. У нас открылось 10 новых стран и появилось 1500 новых киосков самообслуживания. 20 запланированных интеграций быстро превратились в 30+ новых платёжных провайдеров, а их количество продолжало расти. Более того, во время еды пришёл аппетит — многие страны захотели не одну интеграцию, а две и больше. В итоге сейчас мы обрабатываем около 150 тысяч операций в день, и эта цифра продолжает расти.


Наш домен тоже неслабо так разросся — появились новые места в коде, где нужно учитывать новых провайдеров. Добавилась логика по возвратам средств, их типу и обработке. Одни терминалы требуют возврата на том же устройстве, а некоторым даже карту не требуется подносить к устройству для возврата. Ну и не забудем про QR-платежи — их возвраты происходят через API провайдера.
А ещё мы улучшили нашу админку! Теперь у каждого провайдера стало ещё больше метаданных, которые могут учитываться во время платежей.
Планы на будущее
Осталось всего 20 интеграций в разных странах, но на каждую мы не потратим больше 2-3 часов. Теперь новые страны смогут открываться без нашего участия, а мы сможем сфокусироваться на других задачах и проектах.
В прошлой статье были вот такие выводы и планы на будущее. Я, конечно, погорячился с 2-3 часами на одну интеграцию, да. У меня на неё в среднем уходит 4-5 часов, а мой коллега, который никогда до этого интеграциями не занимался, недавно потратил на это 8 часов. Это немного, но хочется же ничего не делать и получать зарплату оптимизировать этот процесс.
По большей части интеграция — это рутина. Она делается по одному шаблону, но для этого нужно знать кодовую базу и все места — около 30 файлов на бэке и фронте в нашем большом монорепозитории.
Все предпосылки для автоматизации такого процесса есть, так что «а давай-ка что-нибудь с этим сделаем и упростим этот процесс» не заставило себя долго ждать. Ну что ж, лень — двигатель прогресса. Я начал думать о том, как упростить жизнь своей команде.
Первые попытки
Мы живём во времена тотального AI-бума. Все уже слышали о том, что «разработчики станут не нужны», «скоро код будут идеально писать ИИ-агенты по промпту «хочу красиво» и т.д. Ну и думаю, что если вы этими самыми ИИ-агентами пользовались, то понимаете: до «скоро» ещё очень далеко.
Я — не ИИ-евангелист, а ChatGPT для меня — удобный инструмент, упрощающий жизнь и выполняющий рутинные задачи. Так что когда интеграции мы стали воспринимать как ещё одну рутину, я сразу стал думать, как бы ему — или другому чат-боту — это дело передать.
Для реализации задумки мне нужен LLM с доступом к нашему коду. В этом году я экспериментировал с разными IDE со встроенными ИИ-агентами — c Cursor и WindSurf, например. У них есть доступ к кодовой базе, плюс можно писать запросы агенту прямо во время разработки.
Пару месяцев назад я написал в обеих IDE простой промпт:
Вот у меня есть файл PaymentProvider.cs, мне требуется добавить новое значение в enum MyNewProvider. Найди все использования в коде и добавь по аналогии с предыдущим значением все использования нового MyNewProvider.
Агенты начали анализировать код. Cursor уже через 10 минут нагенерил похожий на правду код, добавив всё необходимое в backend- и frontend-файлы, хотя и получил довольно простой промпт. Мне всё равно пришлось вмешаться, но тем не менее Cursor меня приятно удивил. Да и в целом Cursor стал моей основной IDE для фронта, потому что это форк привычного VS Code с теми же хот-кеями и дополнительными плюшками в виде ИИ.
А вот WindSurf меня расстроил: он добавил новое значение, зачем-то начал менять файлы, не связанные с платёжными провайдерами, не сделав и 20% от того, что сделал Cursor. В общем, желание возвращаться к WindSurf отпало вообще. Думаю, что напиши я более подробный промпт, он смог бы выполнить мою задачку, ну а пока мой фаворит — Cursor (фанаты Windsurf, не бейте).
Так я выяснил, что написание интеграций точно можно автоматизировать. Осталось этот процесс правильно приготовить и обернуть в красивую упаковку.
Как будем готовить?
На самом деле, тут можно было бы остановиться. Cursor решил мой запрос. Осталось докрутить промпт и написать инструкцию для каждого в команде разработки.
Однако в этом и проблема: мне придётся всех пересадить на Cursor и купить им подписку. В Додо уже активно помогают с этим и выдают лицензии на нужные IDE по запросу, но дело же и в удобстве людей. Каждому придётся настроить заново свою рабочую среду, чтобы выполнить всего одну задачу. Так что я решил делать всё через CI (Continuous Integration).
Чтобы собрать интеграцию через CI, у агента должен быть CLI. У Cursor и Windsurf его нет, так что я начал искать им альтернативу. Первыми на ум пришли Copilot CLI и Claude. У них есть CLI, их можно запускать прямо из терминала, прописывая им промпт в команде. А ещё они видят контекст с кодом и могут изменять кодовую базу.
Я выбрал Copilot, тем более, что в нашем GitHub уже есть лицензия на него. Мы используем его для ревью Pull Request'ов. Он помогает искать опечатки в коде и мелкие логические ошибки, а также делать саммари всего Pull Request'а, чтобы разобраться, что происходит.
Первые попытки автоматизации из одной команды
Чтобы запустить всё это из CI, мне нужен был bash-скрипт, принимающий в себя параметры моего нового провайдера. Так что первым делом я нашёл все отличающиеся у провайдеров параметры:
название;
метаданные: логин, пароль и всякие секреты;
тип возврата средств: требуется карта или нет, надо ли её прикладывать или нет, есть ли автовозврат через API;
название папки в blob storage — в нём разработчики будут публиковать собранный бандл плагина.
Эти параметры я вставил в промпт и вызвал команду copilot. Через некоторое время у меня появился bash-скрипт:

Конечно, промпт был более развёрнутый — для наглядности я его сократил. Когда появилась база, я отладил промпт — что-то добавил, что-то уменьшил. С достаточно подробными инструкциями он начал хорошо отрабатывать и писать похожий на правду код.
Интересное наблюдение
Отлаживая скрипт, я заметил, что он качественно генерит всё, кроме пары моделек. «Глупые агенты. Ничего не понимают» — подумал я, но потом разобрался и понял, что он не видит смысла создавать эти модели, потому что они... просто пустышки!
Пересмотрев код, я понял, что мы можем просто удалить его, адаптировав сериализацию. Так наша кодовая база сократилась почти на 1000 бесполезных строк. Нам стало легче жить, а ИИ-агенту — проще анализировать и понимать контекст.

Забавно, что ни один статистический анализатор не обнаружил этих бесполезных строчек и моделей. А вот Copilot, пусть и не явно, но намекнул на это упущение в нашем коде.
Упаковываем в красивую обёртку
Закончив отладку промпта, я посчитал, что локальный результат мне нравится. Тогда я решил обернуть свой скрипт в GitHub Action, чтобы запускать всё из интерфейса GitHub'а.
Я написал воркфлоу, но у моего токена не хватило прав для авторизации — локально я авторизовался через веб-интерфейс GitHub'а. Если расширить права, то Copilot в CI получит неограниченные возможности в работе с репозиторием. В теории, если что-то пойдёт не так или начнётся восстание машин, Copilot сможет выполнить следующие команды:

Конечно, наша main-ветка защищена по всем канонам безопасности, а такой сценарий — просто фантастичен. Но давать такую власть чёрному ящику всё равно не хотелось, так что мы нашли другой вариант.
ПРИМЕЧАНИЕ: данный вариант актуален только если ваш код лежит в GitHub и вы пользуетесь его инфраструктурой! Если вы используете другую платформу для контроля версий, то вам все-таки придется делать через скрипт в CI.
Недавно GitHub Copilot научился анализировать Issues в репозитории. В Issues вы можете задавать шаблоны и передавать в них определённые параметры — то что надо! Для этого нам нужно создать шаблон Issues в репозитории:

Теперь при создании Issue выбираем нужный шаблон и получаем красивую и удобную форму:

Теперь нам нужно создать кастомного Copilot-агента в нашем репозитории. Создаём файлик и описываем в нём задачку для агента в виде промпта из скрипта:

Теперь Copilot может понять контекст и задачу, которую ему нужно выполнять. Подробнее про эту настройку вы можете прочитать в документации GitHub, а мы перейдём к демонстрации!
Как это работает
Появляется задача — добавить нового платёжного провайдера. Пусть это будет HabrPayments, а для его работы нам потребуется логин и пароль пользователя, а также условный API Key. Тип возврата у него Online. Бандл плагина должен лежать в папке russian-habr-payments в Blob Storage.
Заполним форму через новое Issue:

Создаётся новое Issue. Справа видим кнопку Assign to Copilot:

Появляется окошко с выбором репозитория. В выпадающем списке Custom Agent видим нашего кастомного PaymentProviderAgent с готовым промптом. Поле Optional prompt оставим пустым. Однако если хотите что-то уточнить для агента, то можете его заполнить, дав ему какую-то подсказку.

Copilot автоматически создаёт новый драфтовый Pull Request с нашими требованиями и начинает сессию по анализу нашего промпта и кодовой базы.

Кликнув на View Session, можем перейти на страницу сессии и посмотреть, что именно делает Copilot. Там же можем дать ему дополнительные инструкции или остановить его, если понимаем, что Copilot делает что-то не то.

Поскольку я локально отладил свой промпт, я смог оставить Copilot на 20 минут с нашим кодом и получил готовый Pull Request с подробным саммари о том, что и куда он добавил.

Запускаем локально нашу админку, проверяем, что фронт отображается корректно, и видим это:

Copilot добавил даже примерные переводы наших полей, сделав нашу работу ещё проще.
Выводы
У меня получилось доверить ИИ-агентам создание платёжных интеграций. Да, это рутинная работа, но какая! Они даже формы в админке рисовать научились. Да и за безопасность кода в репозитории можно не беспокоиться — агент полностью изолирован.
Однако до замены разработчиков ИИ-агентам ещё далеко. Если бы я не указывал в промпте все нужные места, корректный код под все мои нужды не смог бы написать ни один ИИ-агент.
Что касается GitHub Copilot, то его сильно прокачали за последний год. Он сильно ускоряет разработку, но, опять же, только под контролем разработчика. Да и не каждый готов доверить свой код в репозитории какому-то ИИ.
Спасибо, что дочитали статью! А что вы думаете по поводу использования ИИ? Поделитесь своим мнением, проголосовав в опросах ниже: