Меня зовут Иннокентий Бодров. Я Senior Product Manager в Sumsub, по бэкграунду системный аналитик. Сейчас я работаю с оценкой AI-систем, строю собственный процесс агентной разработки и веду практический интенсив для аналитиков. Из этой работы вырос фреймворк TDPD — Test-Driven Product Development.

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

Команда подключает coding agent, выдаёт ему задачу и через несколько минут получает pull request. Код собирается. Тесты зелёные. Агент пишет, что работа завершена.

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

Ускорение реализации здесь только увеличивает пропускную способность ошибки. Команда быстрее получает больше кода, который ещё нужно сопоставить с замыслом.

За последний год я перестроил свой процесс вокруг другой точки контроля. Пользовательский сценарий превращается в исполняемый end-to-end тест до реализации. Агент получает спецификацию, тест и ограниченную среду, доводит реализацию до зелёного состояния, а я провожу приёмку результата. Этот подход я называю Test-Driven Product Development, или TDPD.

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

В этой статье я соединю две линии опыта. TDPD даст продуктовый контур от проблемы до приёмки. Материалы OpenAI и Anthropic помогут разобрать инфраструктуру, без которой этот контур остаётся красивой схемой.

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

Обычная постановка для агента часто выглядит достаточно конкретно:

Добавь защиту от повторного создания платежа. Используй ключ идемпотентности. Обнови API и тесты.

Агент может реализовать несколько правдоподобных вариантов:

  • считать повтором любой запрос с тем же ключом;

  • учитывать ключ только внутри одного клиента;

  • хранить ключ сутки или бессрочно;

  • возвращать прежний ответ либо отдельную ошибку;

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

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

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

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

Что TDPD меняет в последовательности работы

Канонический контур TDPD выглядит так:

Бизнес-проблема
    ↓
Спецификация
    ↓
Пользовательские сценарии
    ↓
E2E-тесты
    ↓
Реализация агентом
    ↓
Приёмка человеком (UAT)

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

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

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

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

Первая находится на входе. Человек выбирает проблему, границы и компромиссы. Вторая находится на выходе: человек проводит User Acceptance Testing и принимает либо отклоняет результат. Между ними агент может получить значительную свободу реализации, потому что цель и способ доказательства заданы заранее.

Один сценарий вместо абстрактной спецификации

Возьмём учебный кейс Acme Pay: маркетплейс переводит старый прототип платёжной интеграции на новую версию API. Один из рисков — покупатель повторно нажимает кнопку оплаты, пока банк обрабатывает первый запрос.

Бизнес-проблема формулируется без технического решения:

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

Спецификация добавляет принятое решение:

Для запросов создания платежа клиент передаёт Idempotency-Key. Ключ действует в пределах продавца. Повторный запрос с тем же ключом и теми же параметрами возвращает результат первой операции. Тот же ключ с другими параметрами отклоняется как конфликт.

Из неё получается пользовательский сценарий:

Сценарий: повторная отправка платежа не создаёт дубль

Дано продавец отправил запрос создания платежа
И передал Idempotency-Key pay-2026-0814-001
И платёж перешёл в статус processing

Когда продавец повторяет тот же запрос с тем же ключом

Тогда система возвращает идентификатор первого платежа
И в журнале операций существует один платёж
И покупателю не создаётся второе списание

До реализации этот сценарий можно превратить в исполняемую проверку на уровне API:

test('repeated payment request returns the original operation', async () => {
  const key = 'pay-2026-0814-001';
  const payload = { merchantId: 'm-42', amount: 12500, currency: 'RUB' };

  const first = await createPayment(payload, { idempotencyKey: key });
  const second = await createPayment(payload, { idempotencyKey: key });

  expect(second.status).toBe(200);
  expect(second.body.paymentId).toBe(first.body.paymentId);
  expect(await countPayments({ merchantId: 'm-42', key })).toBe(1);
});

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

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

Почему одного теста недостаточно

Исполняемая приёмка задаёт цель, но агенту всё ещё нужна среда, в которой он способен работать и проверять себя.

OpenAI называет этот слой harness engineering. В опубликованном разборе команда описывает сдвиг роли инженера формулой «люди направляют, агенты исполняют». Люди переводят пользовательскую обратную связь в критерии приёмки, задают ограничения и проверяют результат. Когда агент систематически ошибается, команда добавляет недостающую способность в среду: инструмент, проверку, документацию или наблюдаемость.

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

Для практической работы я разделяю harness на пять частей.

1. Навигация по знаниям

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

OpenAI описывает похожий опыт: монолитный AGENTS.md не сработал как энциклопедия. Команда оставила короткую карту примерно на сто строк, которая ведёт к профильным источникам истины в репозитории. Число строк здесь не норматив. Важен принцип: входной файл объясняет, где искать, а не пытается хранить всё.

В Claude Code аналогичную роль выполняет CLAUDE.md: проектные команды, архитектурные соглашения и правила работы. Повторяемые процедуры можно выносить в skills, чтобы агент загружал подробную инструкцию только для релевантной задачи.

Для TDPD навигационный файл должен отвечать хотя бы на четыре вопроса:

  • где лежит спецификация;

  • где находятся пользовательские сценарии и тесты;

  • какие команды запускают локальную проверку;

  • где записаны решения, которые нельзя принимать заново.

2. Исполняемые ограничения

Текст «не импортируй слой хранения из UI» полезен до первой спешки. Structural test или lint-правило останавливает нарушение каждый раз.

OpenAI описывает custom linters и структурные проверки для архитектурных инвариантов. Это не замена документации. Документация объясняет причину, а проверка не позволяет случайно нарушить правило.

В TDPD исполняемые ограничения окружают продуктовый E2E-тест. Один слой проверяет пользовательское поведение. Другой защищает архитектуру, безопасность, типы, формат и границы модулей. Зелёный продуктовый сценарий не оправдывает SQL-инъекцию или зависимость UI от внутренней таблицы.

3. Наблюдаемость, доступная агенту

Агент способен исправлять только то, что может наблюдать. Код возврата процесса редко объясняет, почему пользовательский сценарий не работает.

В harness OpenAI агентам доступны UI, логи, метрики и трассировки. Anthropic отдельно описывает проблему преждевременного объявления готовности: агент отмечал функцию выполненной, хотя end-to-end поведение оставалось сломанным. Явная проверка через браузер и требование пройти путь пользователя улучшали результат.

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

4. Состояние между сессиями

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

Anthropic использовал progress file и содержательные коммиты для передачи состояния следующей сессии. OpenAI хранит execution plans вместе с прогрессом и журналом решений в репозитории.

Минимальная запись продолжения выглядит так:

## Сделано
- добавлена уникальность merchant_id + idempotency_key;
- базовый повторный запрос проходит.

## Проверено
- npm test -- payment-idempotency;
- повтор с теми же параметрами возвращает исходный paymentId.

## Не решено
- параллельные запросы обходят проверку до commit;
- срок хранения ключа не утверждён.

## Следующее безопасное действие
- добавить конкурентный e2e-тест, не менять схему до решения по TTL.

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

5. Изоляция параллельной работы

Worktrees позволяют нескольким агентам работать с отдельными рабочими директориями. Anthropic рекомендует их для независимых задач. OpenAI поднимал отдельный экземпляр приложения и стек наблюдаемости на каждый worktree.

Изоляция файлов не устраняет общую зависимость. Два агента могут независимо изменить миграцию, контракт API или один компонент и принести логический конфликт без единого конфликта Git.

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

Шесть гейтов вместо статуса «агент работает»

В открытой референсной реализации TDPD я использую шесть гейтов:

Гейт

Что должно существовать

Context

источники, противоречия и решения доступны и трассируемы

Problem

бизнес-проблема и рисковое допущение сформулированы

Input

спецификация, сценарии и архитектурные решения приняты человеком

Red

исполняемые проверки существуют и ожидаемо падают без реализации

Green

реализация проходит согласованные проверки

Output/UAT

ответственный человек принял или отклонил результат

Порядок Context и Problem на практике итеративный. Иногда проблема ведёт к поиску источников, иногда новый источник заставляет изменить формулировку проблемы. Гейты нужны не для изображения линейного процесса, а для запрета опасных переходов.

Нельзя начинать реализацию, если команда не согласовала Input. Нельзя объявлять инженерную готовность без Green. Нельзя называть поставку завершённой без Output/UAT.

В этом месте особенно полезно разделять два статуса:

engineering complete, awaiting UAT

и

accepted

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

Как TDPD связан с инструментами Аналитической мастерской

TDPD не требует конкретной модели или продукта. Его можно применять с файлами Markdown, обычным тестовым фреймворком и любым coding agent.

В Аналитической мастерской я применяю тот же контур в Подмастерье аналитика (AnalystCraft Coworker), AI-напарнике системного аналитика. На Context-гейте он поддерживает цепочку Sources → Project-local RAG → System Context Pack → Review Findings → Task Pack → Export: собирает материал, показывает противоречия и готовит проверяемую заготовку. Решение остаётся за человеком.

Это разделение принципиально. Подмастерье помогает аналитику быстрее собрать контекст и увидеть слабые места, но не выбирает продуктовый компромисс. На выходе действует то же правило TDPD: AI готовит доказательства и заготовку, мастер проверяет и принимает решение.

Где сходятся TDPD и опыт лабораторий

OpenAI и Anthropic не описывают TDPD и не подтверждают метод целиком. Их материалы рассказывают о собственных продуктах, командах и экспериментах. Переносить конкретные размеры файлов, архитектуру harness или показатели скорости как универсальный рецепт нельзя.

Но независимые линии опыта сходятся в нескольких инженерных выводах.

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

Во-вторых, критерий готовности должен находиться вне заявления агента. Тест, пользовательский путь, структурная проверка и наблюдаемый сигнал сильнее текста «выполнено».

В-третьих, знания команды должны переживать отдельную сессию. Решение, которое существует только в чате или голове, недоступно следующему запуску.

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

Наконец, ownership остаётся у людей. Делегирование реализации не передаёт ответственность за проблему, компромисс и выпуск.

Где метод не работает автоматически

Субъективное качество

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

Легаси без тестовой поверхности

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

Неверный критерий

Агент способен идеально реализовать плохо выбранный сценарий. Тест сделает ошибку воспроизводимой, но не превратит её в правильный продукт. Поэтому UAT не является церемонией после Green.

Рискованные и необратимые действия

Миграция production-данных, изменение доступа, платёжная операция и публикация наружу требуют отдельных разрешений, безопасного preview и плана отката. Зелёный тест в изолированной среде не даёт автоматического права выполнить действие в production.

Формальная имитация процесса

Можно написать тест после реализации и назвать его Red-гейтом. Можно отметить UAT без просмотра результата. Framework не защищает от самообмана. Он лишь оставляет места, в которых самообман можно обнаружить.

Практический аудит готовности команды

Перед масштабированием числа агентов я бы проверил семь вещей.

  1. Может ли команда сформулировать пользовательский сценарий без описания реализации?

  2. Существует ли исполняемая проверка этого сценария до появления кода?

  3. Видит ли агент те же логи, интерфейсы и ошибки, которые использует человек при диагностике?

  4. Лежат ли актуальные решения рядом с кодом, а не только в переписках?

  5. Останавливают ли CI и линтеры нарушение критических ограничений?

  6. Может ли новая сессия восстановить прогресс и продолжить с безопасной точки?

  7. Назван ли человек, который проводит UAT и принимает решение о выпуске?

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

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

Источники