Загрузка 0
ПОДЕЛИТЬСЯ

Мой блог

Листай вниз

Как собрать семантику проекта для кодового агента без лишней бюрократии

Как собрать семантику проекта для кодового агента без лишней бюрократии

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

Допустим, передо мной стоит задача внедрить недельную квоту в компактный программный модуль. Модель успешно отыскивает метод, встраивает туда счетчик и даже генерирует сопутствующий тест. Однако вскоре выясняется, что лимит должен вычисляться строго на конкретного пользователя, отклоненные запросы не имеют права расходовать доступный объем, а отрицательные значения по-прежнему обязаны вызывать ошибку. В исходном коде подобные требования обычно размыты между доменной моделью, тестами и устаревшими комментариями. Проблема заключается вовсе не в самой нейросети: я передал ей исходники, но совершенно забыл обозначить намерение.

Что скрывается за понятием семантики проекта

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

Реклама

Сюда входят словарь специфической предметной области, важнейшие инварианты, обязанные пережить любой рефакторинг, публичные контракты и четкие границы конкретной модификации. Такой подход во многом напоминает практику Spec-Driven Development (SDD), но в значительно уменьшенном масштабе. Официальная документация GitHub Spec Kit трактует SDD как методологию, где намерения фиксируются задолго до написания реализации и уточняются пошагово. Разумеется, слепо копировать весь этот тяжеловесный рабочий процесс не имеет никакого смысла. Для скромного репозитория вполне достаточно сделать намерения доступными для ИИ и надежно связать их с автоматическими тестами.

Минимальный набор файлов для контекста

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

  • agent-context/index.md — навигационный указатель;
  • agent-context/domain.md — доменные термины и инварианты;
  • agent-context/contracts.md — публично наблюдаемые контракты;
  • agent-context/features/weekly-limit.md — спецификация текущей задачи.

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

Реклама

Например, файл domain.md для нашей задачи с лимитами может содержать всего три лаконичных правила:

  • Недельная квота рассчитывается исключительно на пользователя, игнорируя API-ключи и IP-адреса.
  • Попытка доступа, отклоненная из-за исчерпания лимита, не должна уменьшать оставшийся объем.
  • Отсчет новой недели начинается строго по понедельникам в 00:00 UTC.

Эти три строки приносят агенту значительно больше пользы, чем очередной громоздкий пересказ файла app/limits.py. Первое правило задает четкую границу агрегации, второе описывает корректное поведение при отказе, а третье регламентирует работу со временем. Разумеется, все они должны беспрекословно проверяться юнит-тестами.

Как быстро собрать контекст за один вечер

Начинать формирование такой документации с банальной генерации текстов самой нейросетью — тупиковый путь. В противном случае вы быстро получите аккуратный, но абсолютно бесполезный пересказ файла package-lock.json. Вместо этого я советую самостоятельно проанализировать пять базовых элементов проекта.

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

Однако глубинный смысл правила «отказ не должен расходовать квоту» невозможно надежно извлечь из одних лишь строк кода. Эту информацию должен зафиксировать человек, досконально понимающий предметную область. Здесь действует предельно простой фильтр: если какое-то утверждение можно без труда восстановить прямо из исходников, дублировать его в папку agent-context не нужно. Достаточно прописать путь к нужному модулю в файле index.md. Если же правило обязано оставаться истинным даже после масштабного рефакторинга, ему самое место в domain.md или в спецификации отдельной фичи.

Как правильно использовать собранный контекст

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

Реклама

Перед началом любых изменений модель должна прочитать файл agent-context/index.md. Получив задачу по настройке лимитов, агент открывает domain.md, contracts.md и спецификацию weekly-limit.md, после чего переходит к указанным там исходникам и тестам. Первым делом модель сопоставляет каждый критерий готовности с существующими тестами. Если для какого-то критерия не находится соответствующей проверки, агент обязан ее добавить или скорректировать. При этом публичный контракт запрещено менять без предварительного обновления файла contracts.md.

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

Что подлежит автоматизации, а что лучше оставить людям

Для поддержания порядка в небольшом проекте мне хватает всего двух жестких правил при оформлении Pull Request: при изменении публичного API обязательно обновляется contracts.md, а при появлении нового инварианта корректируются domain.md и соответствующие тесты.

Автоматизировать имеет смысл исключительно очевидные вещи. Отличный пример — автоматическое сравнение свежесгенерированной схемы OpenAPI с версией, закоммиченной в репозиторий. При этом точно не стоит настраивать CI-пайплайны, которые требуют в обязательном порядке переписывать документацию после банального переименования локальной переменной. Иначе вся работа с контекстом быстро превратится в унылый ритуал, который команда обходит стороной с тем же выражением лица, что и процесс смены пароля в корпоративной сети.

Спецификацию разовой функциональности после успешного слияния ветки можно смело удалять. Если же в ней содержался перманентный инвариант, его следует заблаговременно перенести в общие файлы domain.md или contracts.md. Методология Spec Kit также не навязывает жестких требований к судьбе временных артефактов спецификации после изменения исходных требований.

Границы применимости подхода

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

В таких масштабах имеет смысл присмотреться к специализированным решениям вроде OpenViking. Это полноценная контекстная база данных, созданная специально для ИИ-агентов и объединяющая знания, память и рабочие навыки в единой виртуальной файловой системе. В ней модель сначала знакомится с коротким абстрактом каталога, затем изучает общий обзор (overview) и только после этого обращается к первичным исходным материалам.

Для обычного пет-проекта развертывание OpenViking исключительно ради того, чтобы искусственный интеллект нашел пару тестов — это стрельба из пушки по воробьям. Подобное решение сопоставимо с вызовом грузового крана ради перестановки табуретки. Однако когда проектная база живет гораздо дольше одной фичи, у агента появляется постоянная память между сессиями, а источников информации становится слишком много, подобная инфраструктура превращается в логичный и осознанный шаг вперед.

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

Чек-лист для внедрения первой версии

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

  • Файл index.md четко выстраивает путь от типа конкретной задачи к исходному коду и тестам.
  • В документе domain.md зафиксированы исключительно ключевые термины и неизменяемые инварианты.
  • Файл contracts.md точно описывает все внешне наблюдаемые особенности поведения системы.
  • Для каждой активной фичи прописаны понятные границы задачи и критерии ее готовности.
  • Каждое важное правило и ограничение надежно покрыто автоматическими тестами.
  • В чеклисте каждого Pull Request присутствует вопрос об изменении контрактов или доменных инвариантов.

Описанного набора мер вполне достаточно для того, чтобы кодовый агент оперировал не «весь проект целиком», а его компактной и рабочей моделью. Внедрять более сложные инструменты стоит лишь тогда, когда возможностей четырех базовых файлов объективно перестает хватать для решения текущих задач.

01.