Привет, Хабр! На сегодняшний день активно распространяется вайб‑кодинг — практика написания кода с помощью ИИ-ассистента. При его правильном использовании можно ускорить процесс разработки, переложить написание рутинного кода на ИИ и покрыть пробелы в использовании инструментов и библиотек.

Меня зовут Никита Кулин, я Senior ML‑инженер в команде AI X5 Digital, которая интегрирует ИИ в процессы компании. Я расскажу о том, как создать собственного кодового ассистента. Рассмотрим полный цикл разработки: от постановки задач до прототипирования.

Зачем и кому нужен свой ИИ-ассистент?

Обычно ИИ‑ассистент применяют в Pull Request‑ах, в Integrated Development Environment и в WebUI диалогового чат‑бота, чтобы проверить, ускорить и автоматизировать написание кода. Он может выполнять разные задачи:

  • делать автоматическое ревью PR‑ов;

  • создавать inline‑автоподсказки в IDE;

  • покрывать код тестами;

  • искать и исправлять ошибки в коде;

  • писать документацию для скриптов и проектов.

Для этого существуют открытые решения кодовых ассистентов, такие как Cursor, Github Copilot или Tabnine. Они справляются с большинством задач, а разработка собственного кодового ассистента требует системного подхода, глубокого понимания современных LLM и правильных метрик оценки качества. Поэтому давайте сначала разберёмся, нужен ли он вам или будет достаточно открытого решения.

Собственный ассистент нужен, если:

  1. Вы работаете по существующим паттернам разработки и соглашениям команды, о которых не знают открытые ИИ‑ассистенты.

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

  3. Вы не хотите, чтобы ваш корпоративный код логировался и отправлялся на сторонние сервисы других компаний, которые сопровождают открытые решения кодовых ИИ‑ассистентов.

У нас в X5 Digital как раз совпали все 3 пункта, поэтому мы решили делать свой собственный кодовый ассистент. Спойлер: на текущий момент он работает для всех IT‑команд в компании. Если ваша ситуация из описанных выше, тогда собственный кодовый ассистент будет и вашим решением. Давайте посмотрим, как к нему подступиться.

С чего начать?

Современные ИИ‑ассистенты могут покрывать различные запросы благодаря обобщающей способности LLM решать пользовательские инструктивные задачи. Однако задача «оптимизация всего кода» звучит слишком обобщенно. Поэтому, чтобы оценить ассистента, проконтролировать его способности и выяснить слабости, прежде всего нужно разделить обобщённую задачу на отдельные подзадачи и чётко определить, какие из них приоритетные.

Например, мы для себя в первую очередь выделили такие подзадачи:

  • Написание тестов (юнит, интеграционные).

  • Написание кода по запросу (функции, mock‑объекты).

  • Поиск и решение ошибок в коде.

  • Генерация документации (docstring‑ов).

После выделения подзадач останется решить, с какой из них начать. К примеру, если в ваших репозиториях остро не хватает тестов для покрытия кода, можно начать создание ассистента с решения именно этой проблемы. А когда вы выделите свои подзадачи и определите приоритеты, можно переходить к самому ассистенту, а конкретнее — к выбору LLM модели.

Как выбрать LLM?

Первичный отбор моделей лучше всего основывать на бенчмарк‑оценке способностей LLM по задачам с кодом. Есть много различных лидербордов, но мы выбрали для себя Big Code Models Leaderboard, SWE‑bench Leaderboard, LLM‑Explorer. Эти лидерборды показывают обобщающую способность LLM к решению задач с кодом. Из них можно взять первых кандидатов.

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

Кроме объема потребляемой памяти, нужно учитывать размер контекстного окна. Он определяет, сколько дополнительных данных и кода можно передать модели. Ориентируйтесь на большой размер контекстного окна, так как это будет важно для больших скриптов. Иначе вам придется подавать код по кусочкам, а это не всегда хорошо, потому что в модель будет подан не весь контекст, что срежет точность и полноту ответа.

Также важна поддержка языков программирования. Её можно проверить в карточках моделей на HuggingFace. Там авторы оставляют информацию о поддержке языков программирования, но если вы не найдете нужной информации, можно попробовать написать LLM тестовые запросы на понимание.

Итого, при отборе LLM необходимо смотреть на:

  • Эффективность решения задач с кодом по лидербордам.

  • Утилизацию объема памяти в GPU под ваши ресурсы.

  • Размер контекстного окна.

  • Поддержку языков программирования.

По этим критериям мы отобрали топ-5 моделей, которые стали нашими кандидатами для прототипа кодового ассистента. В зависимости от своих результатов отбора вы можете выбрать больше кандидатов.

Как оценивать эффективность модели?

Поговорим про две основные компоненты оценки: данные и метрики.

Данные

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

  • Во‑первых, полнота и качество юнит‑тестов могут оказаться не из лучших.

  • Во‑вторых, не все ваши скрипты могут быть покрыты юнит‑тестами.

К счастью, для первой итерации можно взять — 30–100 примеров для оценки, а для последующих итераций повышать их количество. Но при этом не стоит забывать, что чем больше примеров, тем более объективная оценка. Конечно, кроме количества важно, чтобы эти примеры были разнообразными как по сложности, так и по кейсам.

Если у вас не хватает готовых примеров — это не проблема. В современной практике чаще всего выполняется полуавтоматический процесс разметки:

  • Отбираются готовые скрипты для входных данных.

  • Берутся LLM (желательно побольше).

  • Генерируются эталонные ответы.

  • Вручную валидируются и корректируются неточные примеры.

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

В итоге вы получите полноценный датасет, даже если у вас мало готовых данных.

Метрики

Пространство метрик для оценки ответов моделей
Пространство метрик для оценки ответов моделей

На текущий момент есть большой выбор в метриках оценки ответов. Однако традиционные метрики для оценки качества ответов моделей, такие как BERTScore, BLEU или ROUGE, будут неточными и слишком обобщенными. Поэтому итоговая оценка качества кодовых ассистентов основывается на многоаспектном подходе, включающем специализированные метрики под задачи с кодом.

Во‑первых, это функциональная корректность.

  • Pass@k — вероятность того, что хотя бы одно из k сгенерированных решений пройдет все тесты.

  • Accuracy — доля задач, для которых сгенерирован корректный код.

  • Compilation Rate — процент кода, который компилируется без ошибок.

Во‑вторых, это покрытие кода (важно для написания тестов).

  • Statement Coverage (LCov@k) — процент покрытых строк кода.

  • Branch Coverage (BCov@k) — процент покрытых ветвей выполнения.

  • Mutation Score (Mut@k) — способность тестов обнаруживать внесенные изменения.

В‑третьих, сопоставление с эталоном.

  • G‑Eval — оценка LLM по заданному пользовательскому критерию или критериям.

  • CodeBLEU — специализированная метрика для кода на основе BLEU, которая учитывает не только токены, но и синтаксическое дерево (AST) и семантические зависимости кода.

  • CodeBERTScore — специализированная метрика для кода на основе BERTScore, учитывающая важность токенов кода.

В‑четвертых, пользовательские метрики, которые проверяют соблюдение отдельных правил. Например, чеккер импорта/использования той или иной библиотеки или проверка объема кода и проверка на язык сгенерированной документации.

Выбор метрик зависит от решаемой подзадачи. Изучите каждую и подберите наиболее подходящие для каждого кейса. Составляйте свои пользовательские метрики и оценивайте модель всеми метриками вместе.

После оценки метриками можно переходить к созданию прототипа.

Создаем прототип

Инструменты разработки

Для быстрого создания LLM ассистента лучше использовать библиотеку LangChain, которая поддерживает языки Python и JS. Среди её преимуществ подробная документация и множество примеров реализации приложений с LLM на старте.

Настройка моделей

Далее настроим вызов модели. К примеру, на этапах тестирования и экспериментов подойдет нативный вызов из HuggingFace или Ollama. А для генерации ответов с высокой нагрузкой запросов подойдут vLLM, TGI или TensorRT.

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

Для генерации ответа настроим основные параметры:

  • Температура (T) — отвечает за «креативность» ответа, где значение 0 — уверенный ответ, а значения около 1 — более креативный.

    • Для генерации кода ставим значения T ≈ 0-0,2

    • Для документации можно поставить значение как для строгой типизации (T ≈ 0-0,2), так и для вариативных описаний (T ≈ 0,7-1,2).

  • Максимальная длина ответа (max_new_tokens) — отвечает за длину сгенерированных токенов. Лучше ставить больше, если планируете генерировать большой объем кода.

После настройки переходим к написанию инструкции модели.

Промптим

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

К примеру, за основу можно взять такой базовый промпт:

"""
### Роль: Умный помощник по коду

### Описание: 
Ты квалифицированный AI Ассистент, который помогает разработчикам писать 
качественный код и его документацию по лучшим практикам. 

Твоя задача — отвечать на запросы пользователей, 
предлагая наилучший ответ.

### Формат ответа: 
Отвечай в формате JSON
"""

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

Формат ответа нужен для получения структурированного вывода (он же Structured Output), который упростит и стабилизирует парсинг сгенерированного ответа.

Начните с базового промпта и постепенно его улучшайте. В любом случае вам придется перебрать и протестировать разные вариации промптов, потому что, к сожалению, «серебряной пули» в виде универсального промпта не существует. Используя советы, попробуйте разные формулировки, добавляйте дополнительные уточнения и ограничения, пробуйте разные примеры ввода‑вывода (он же Few‑Shot).

Собираем и тестируем ассистента

В итоге у нас получится базовая архитектура LLM‑системы.

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

Теперь можно переходить к следующему важному этапу. У нас есть разные варианты системных промптов, настроек и моделей, оценим их на созданном датасете и получим результаты метрик.

Создаем свой лидерборд

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

Пример кастомного лидерборда
Пример кастомного лидерборда

«Все должно быть сделано так просто, как это возможно, но не проще» / Альберт Эйнштейн

Итоги оценки в оффлайн

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

Оцениваем в онлайне

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

Помимо текстовой оценки фидбека, оценивайте удовлетворенность разработчиков и скорость работы системы:

  • AcceptRate (принятие ответа модели).

  • Retention (удержание разработка в использовании сервиса).

  • Кол‑во лайков и дизлайков в ответах.

  • Latency (Задержка): время между отправкой запроса и появлением ответа.

  • Throughput (Пропускная способность): сколько запросов в секунду может обработать сервис.

Заключение

Для начала создания кодового ассистента мы проделали следующие шаги:

  • Определили ключевые задачи, под которые будет использоваться ассистент.

  • Спланировали, как и на чем будем оценивать ассистента.

  • Выбрали модели‑кандидатов для первичного отбора.

  • Построили прототип и сварьировали его компоненты для получения наибольшей эффективности.

  • Вывели прототип на тест, чтобы получить первую обратную связь от пользователей.

Но на этом разработка прототипа не заканчивается.

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

Комментарии (0)