Мой подход к разработке продукта с ИИ-агентами
Когда вы даёте ИИ-агенту задачу «сделай мне сервис заметок» без предварительной подготовки, результат почти всегда один и тот же: хаотичный набор кода, который решает не ту задачу, которую вы имели в виду, и который сложно развивать дальше. Причина не в том, что агент «плохой», а в том, что у него нет контекста — того самого понимания продукта, которое есть у вас в голове, но которое вы не зафиксировали в явном виде.
В этой статье я делюсь подходом к разработке продукта с помощью ИИ-агентов, который сложился у меня за время работы над несколькими проектами — методом проб и ошибок. Цель подхода простая: сделать так, чтобы агент строил именно то, что вы задумали, а не додумывал детали за вас.
Подход состоит из трёх крупных этапов:
- Анализ — проектирование системы на бумаге, до того как написана хоть одна строчка кода.
- Разработка — реализация функционала по заранее согласованному плану.
- Тестирование — проверка того, что реализованное соответствует задуманному.
Разберём каждый этап подробно.
Этап 1. Анализ: спроектируйте систему, прежде чем её строить
Это самый важный этап всего процесса, и именно на него стоит потратить больше всего внимания. Ошибка, допущенная здесь, размножится на всех последующих шагах: агент будет уверенно писать код, опираясь на неверные или неполные требования, а вы заметите проблему только тогда, когда переделывать станет дорого.
Логика простая: пока продукт существует только у вас в голове, агент не может с ним работать. Ваша задача — перенести это понимание в структурированные документы, к которым агент будет обращаться на каждом шаге, не теряя контекст проекта.
Шаг 1. Опишите проект своими словами
Начните с произвольного, неформального описания того, что вы хотите построить. Не нужно сразу писать техническое задание — просто изложите идею так, как вы бы рассказали её коллеге.
Например, если вы хотите сделать сервис для ведения заметок, начальное описание может звучать так: «Хочу сервис, где пользователь может быстро создавать заметки, группировать их по тегам и находить нужную через поиск по тексту».
Это описание сохраняется в отдельный файл — SOURCE.md. Он не обязан быть идеальным: его задача — зафиксировать первоначальный замысел, к которому агент будет возвращаться при заполнении остальных документов.
Шаг 2. Сформируйте три базовых документа проекта
Шаблоны для всех трёх файлов не нужно придумывать с нуля — я собрал их в отдельном репозитории: ai-project-tmpl. Скачайте нужные шаблоны оттуда и используйте как основу.
На основе SOURCE.md формируются ещё три файла. Вместе с исходным описанием они образуют полный комплект артефактов этапа анализа:
SOURCE.md— свободное описание проекта, отправная точка для всего остального.PROJECT.md— центральный технический документ: архитектура, стек, функциональные требования, пользовательские сценарии. Это основной файл, на который агент опирается на протяжении всей разработки, чтобы не терять контекст проекта.DATAMODEL.md— модель данных: таблицы, поля, связи между ними.ROADMAP.md— дорожная карта, по которой агент будет последовательно реализовывать проект.
Заполняются они не одновременно, а по цепочке: каждый следующий файл строится на основе предыдущих.
2.1. Заполнение PROJECT.md
Начните с архитектуры. Если вы уже знаете, какой стек хотите использовать — пропишите его сами. Если нет — попросите агента предложить архитектуру на основе SOURCE.md, но в этом случае обязательно проверьте предложение критически: агент может выбрать стек, который не подходит под ваши реальные ограничения (команда, инфраструктура, сроки).
Пример того, как может выглядеть описание стека для backend-части:
Стек: Python (FastAPI)
Зависимости:
- Python 3.11+
- FastAPI
- PostgreSQL 15+
- Обязательный async-first режим: async def в API/сервисах/CRUD,
SQLAlchemy AsyncSession, async-драйвер PostgreSQL (asyncpg)
- Запрещены блокирующие I/O операции в runtime-коде API
(HTTP, БД, sleep и т.п. — только через async API)
- pytest + pytest-asyncio для тестов
- pydantic-settings + .env для конфигурации
- structlog для логирования
Такой уровень детализации важен: чем конкретнее зафиксированы технические ограничения, тем меньше агенту придётся «додумывать» самому — а значит, тем меньше риск получить решение, которое технически работает, но не соответствует вашим стандартам.
Если backend и frontend в проекте разделены и общаются через API, имеет смысл описывать их архитектуру отдельно, начиная с backend как более критичной части.
После того как стек и архитектура описаны, отдайте агенту задачу на заполнение шаблона:
На основании файла @SOURCE.md заполнить шаблон @PROJECT.md.
Обязательно проверяйте результат вручную. Это не формальность: именно на этом шаге легче всего поймать смысловые нестыковки — например, если агент неверно интерпретировал часть вашего описания или упустил важный сценарий использования. Если находите проблемы — дорабатывайте описательную часть и повторяйте шаг. Переходите дальше только тогда, когда документ действительно отражает то, что вы задумали.
2.2. Формирование модели данных
Когда PROJECT.md готов, на его основе формируется модель данных:
На основании файла @PROJECT.md заполни шаблон @DATAMODEL.md
Здесь важно проверить не только полноту (все ли сущности учтены), но и логику связей между таблицами — именно ошибки в модели данных на старте сложнее и дороже всего исправлять после того, как на этой модели уже построен код.
2.3. Формирование дорожной карты
Финальный документ этапа анализа — план реализации:
На основании файла @PROJECT.md и @DATAMODEL.md заполни шаблон @ROADMAP.md
Хорошая дорожная карта разбивает разработку на последовательные, проверяемые этапы — так, чтобы после каждого шага получался работающий, тестируемый кусок функционала, а не бесформенный черновик. Это пригодится на следующем этапе.
Если находите пробелы — не бойтесь возвращаться назад
Если в процессе заполнения любого из файлов вы понимаете, что что-то не учли или описали неточно — пройдите цикл анализа заново: скорректируйте SOURCE.md или PROJECT.md и заново сформируйте зависящие от них документы. Дешевле потратить лишний час на этом этапе, чем переделывать реализованный функционал.
Этап 2. Разработка: Spec-Driven Development
Когда все четыре документа готовы и проверены, начинается непосредственно написание кода. Но здесь важно не наступить на ещё одни грабли: просто отдать агенту ROADMAP.md и попросить «реализуй всё по порядку» — недостаточно. Roadmap описывает что нужно сделать на уровне вех, но не фиксирует как именно агент должен рассуждать над конкретной задачей, какие у неё границы и какое поведение системы считается правильным. Без этого агент на каждой вехе заново додумывает детали — и снова рискует отклониться от замысла.
Поэтому на этапе разработки я использую подход Spec-Driven Development (SDD) — методологию, в которой спецификация конкретного изменения выступает источником истины для агента: не идея в голове разработчика и не абстрактный пункт дорожной карты, а зафиксированный документ, на который можно сослаться и который не меняется на лету в процессе диалога с агентом.
Погружаться в теорию SDD в рамках этой статьи я не буду — материалов по теме достаточно в открытом доступе. Расскажу про инструмент, которым пользуюсь сам.
Инструмент: OpenSpec
Реализовать SDD-подход вручную можно, но удобнее опираться на готовый фреймворк. Я использую OpenSpec — open-source фреймворк для SDD-разработки с LLM. Подобных инструментов немного, и OpenSpec не единственный вариант: например, есть также Specify от GitHub. Но в большинстве проектов мне хватает OpenSpec.
Устанавливается он глобально через npm:
npm install -g @fission-ai/openspec@latest
После установки инициализируется прямо внутри проекта:
cd your-project
openspec init
Настройка: артефакты на русском языке
По умолчанию OpenSpec генерирует артефакты на английском. Если вы хотите, чтобы все документы фреймворка были на русском языке, это настраивается в конфиге openspec/config.yml:
schema: spec-driven
context: |
1. Источник истины: PROJECT.md
2. Язык артефактов: все артефакты OpenSpec (proposal, tasks, design, specs и любые другие) должны быть написаны на русском языке. Заголовки, описания, задачи и текст в артефактах — только по-русски.
Здесь же полезно явно указать, что источником истины для агента остаётся PROJECT.md — так фреймворк не начнёт «спорить» с документами, которые вы подготовили на этапе анализа.
Жизненный цикл: explore → propose → apply → archive
В основе OpenSpec — четыре команды, которые образуют цикл работы над каждым изменением:
explore → propose → apply → archive
explore— агент разбирается в задаче и контексте, прежде чем предлагать решение.propose— на основе анализа формируется предложение по изменению: что и зачем мы делаем.apply— одобренное предложение реализуется в коде.archive— изменение завершается и убирается из списка активных предложений, при этом его история сохраняется.
На практике для большинства задач мне достаточно трёх команд из четырёх — propose, apply и archive; explore пригождается в основном для более сложных или неоднозначных задач, требующих отдельного разбора перед тем, как формировать предложение.
Как это выглядит на практике
Работа строится вокруг вех из ROADMAP.md. Я беру первую невыполненную веху целиком — с её описанием и списком задач — и передаю её агенту (например, в Cursor) командой propose:
/opsx-propose Milestone 1: Фундамент платформы и безопасность
Сама веха в ROADMAP.md к этому моменту выглядит примерно так — с чёткой целью, разбивкой на задачи и критерием готовности:
### Milestones (Вехи проекта)
#### [ ] Milestone 1: Фундамент платформы и безопасность
**Цель:** Заложить надежную асинхронную базу (FastAPI) и реализовать базовую модель пользователей и авторизации. Система должна быть готова к приему бизнес-логики.
- [ ] **TASK-01: Инфраструктура и Архитектура**
- [ ] Развертывание `docker-compose.yml` (PostgreSQL 15+, MinIO, FastAPI).
- [ ] Настройка слоистой архитектуры (`app/api`, `app/services`, `app/crud`, `app/db`).
- [ ] Настройка базовых библиотек: `SQLAlchemy AsyncSession`, `Alembic` для миграций, `pydantic-settings` для `.env`.
- [ ] Настройка линтеров (`ruff`, `mypy`) и CI-пайплайна.
- [ ] **TASK-02: Авторизация и Пользователи**
- [ ] Создание моделей БД (`workspaces` как root tenant и `users`, роли: Trainer / Athlete). При регистрации юзеру создается персональный workspace.
- [ ] Реализация эндпоинтов регистрации и логина (выдача JWT токенов).
- [ ] Разработка Dependency (`get_current_user`) для защиты закрытых роутов.
- **🏁 Результат (DoD):** Swagger UI доступен, можно зарегистрироваться, получить токен и дернуть защищенный тестовый роут. Настроен локальный MinIO и БД.
В ответ на propose система формирует не один документ, а сразу четыре взаимосвязанных артефакта:
proposal.md— намерение: зачем и что именно мы меняем.design.md— архитектурное решение: как технически будет реализовано изменение.specs/.../spec.md— контракт поведения: каким должно быть поведение системы после изменения.tasks.md— план работ: конкретный список задач для реализации.
Именно эти четыре документа, а не сам пункт ROADMAP.md, становятся источником истины для агента на время работы над вехой. Их стоит просмотреть перед тем, как двигаться дальше — так же, как вы проверяли PROJECT.md и DATAMODEL.md на этапе анализа.
Когда предложение устраивает, запускается реализация:
/opsx-apply
Агент реализует веху в коде, опираясь на зафиксированные design.md, spec.md и tasks.md. Когда работа завершена, изменение архивируется:
/opsx-archive
После архивации переходим к следующей вехе — и повторяем цикл propose → apply → archive заново. Принцип — одна веха за одну итерацию: это не даёт агенту распыляться сразу на весь проект и позволяет проверять результат на управляемых, законченных кусках функционала, а не после того, как реализован весь ROADMAP.md целиком.
Этап 3. Тестирование: проверка соответствия задуманному
Тестирование в этом подходе — это не только про отсутствие багов, но и про то, что реализованный функционал действительно соответствует тому, что описано в PROJECT.md и DATAMODEL.md.
Практический ориентир:
- Проверяйте каждый пункт дорожной карты сразу после реализации, а не откладывайте тестирование на конец проекта — так дешевле исправлять несоответствия.
- Сверяйтесь с пользовательскими сценариями из
PROJECT.md: даже если код технически работает и покрыт unit-тестами, стоит убедиться, что он решает исходную задачу пользователя так, как она была описана. - Используйте автоматизированные тесты там, где это возможно — например, если в стеке зафиксирован
pytestиpytest-asyncio, тесты должны появляться параллельно с кодом, а не постфактум. - Возвращайтесь к анализу, если тестирование вскрыло пробел. Если в процессе проверки выясняется, что какой-то сценарий вообще не был учтён на этапе анализа — это сигнал вернуться к
SOURCE.mdилиPROJECT.md, а не просто «залатать» проблему точечным изменением в коде.
Frontend: тот же подход, но на основе backend-документов
После того как backend протестирован и работает так, как задумано, наступает очередь frontend-части. И здесь не нужно изобретать новый процесс — я прохожу тот же путь анализа, что и в самом начале, только с одним отличием: файл DATAMODEL.md для frontend не формируется, поскольку модель данных уже полностью описана и зафиксирована на стороне backend.
Формируем документы для frontend
Удобнее всего сделать это, не выходя из backend-проекта: агент уже знает контекст всей системы, поэтому можно прямо там попросить его сформировать PROJECT.md и ROADMAP.md для frontend-части — указав нужный стек (например, React, Vue или любой другой, который вы выбрали). После того как документы готовы и проверены, перенесите их во frontend-проект, в каталог /project.
Файл AGENTS.md
В корне frontend-проекта дополнительно создаётся файл AGENTS.md — он указывает агенту, где искать базовую документацию проекта:
## Базовая документация проекта.
- project/PROJECT.md - Описывает проект
- project/ROADMAP.md - ROADMAP
- project/openapi.json - API endpoints
Третий файл в этом списке — openapi.json — спецификация OpenAPI по эндпоинтам вашего backend. Она нужна агенту, чтобы понимать, какие API-запросы доступны, какие у них параметры и форматы ответов, и корректно реализовывать интеграцию frontend с backend. Получить её просто: она скачивается прямо со Swagger-документации backend-проекта.
Разработка через тот же цикл OpenSpec
Дальше всё повторяет уже знакомый процесс: в frontend-проекте заново инициализируется OpenSpec, и начинается итеративная работа по ROADMAP.md — веха за вехой, через цикл explore → propose → apply → archive. Разница в том, что теперь агент опирается не только на PROJECT.md, но и на спецификацию openapi.json — это позволяет ему реализовывать не просто интерфейс, а корректную интеграционную часть, которая действительно соответствует контракту вашего backend.
Когда все вехи реализованы и протестированы, вы получаете готовый продукт — именно тот, который описывали на самом первом шаге анализа, а не то, что агент «додумал» по пути.
Важный момент на будущее: даже после завершения основной разработки любые дальнейшие изменения в проекте — что для backend, что для frontend — стоит проводить по тому же сценарию OpenSpec: explore → propose → apply → archive. Это сохраняет дисциплину процесса и не даёт проекту со временем снова превратиться в хаотичный набор кода.
И ещё немного за рамками этой статьи
Помимо описанного процесса, у меня есть ещё три навыка (skills) для агентов, которые проверяют готовый сайт с трёх разных сторон: юридическую часть, SEO-оптимизацию и качество контента. Это отдельный слой проверки, который логично встраивается уже после того, как продукт разработан и протестирован по описанному выше циклу. Но это самостоятельная и довольно объёмная тема — расскажу о ней в отдельной статье.
Итог
Весь подход можно свести к одной идее: сначала спроектировать, потом строить, потом проверить, и на каждом шаге явно фиксировать решения в документах, к которым агент может обращаться. Это не избавляет от итераций — вы всё равно будете возвращаться к SOURCE.md и PROJECT.md, когда найдёте пробелы, — но эти итерации происходят на уровне документов, что значительно дешевле, чем переделывать уже написанный код.
Такой цикл — анализ → разработка → тестирование → (при необходимости) снова анализ — превращает работу с ИИ-агентом из непредсказуемого процесса в управляемый, где итоговый продукт действительно соответствует тому, что вы изначально задумали.