инженерные заметки
RED-driven development: зрелость ИИ-агента — в красных тестах
Почему для ИИ-агентов цикл «фича → тест → зелено» недостаточен и как RED-driven development измеряет зрелость качеством пережитых красных тестов, а не числом зелёных.
Коротко для руководителя. «Все тесты зелёные» — это не доказательство, что ИИ-агент работает, а доказательство, что его проверяли в удобных условиях. Зрелость агентной системы измеряется не числом пройденных тестов, а качеством атак, которые она уже выдержала. Если никто целенаправленно не пытался её сломать — у вас нет данных о надёжности, есть только надежда. RED-driven development делает эту проверку штатной: вы платите за неё до запуска, а не убытком после.
Классическая разработка приучила нас к ритму «сделали функцию — написали тест — получили зелёный — поехали дальше». Для обычного кода это работает, потому что код детерминирован: один и тот же вход даёт один и тот же выход. ИИ-агент так себя не ведёт, и поэтому привычный зелёный цикл создаёт ложную уверенность вместо настоящей.
Зрелость агента — это не количество зелёных тестов, а качество красных, которые он уже пережил.
Гипотеза: для агентов показатель зрелости — качество RED, а не число GREEN
Тест диалогового агента, который зелёный, говорит ровно одно: в этом конкретном проигранном сценарии агент дошёл до цели. Он ничего не говорит о том, что будет, когда пользователь собьётся, передумает, соврёт в данных или вернётся к старому вопросу через двадцать минут. Настоящая информация о надёжности появляется не из зелёных прогонов, а из красных — из ситуаций, где агент сломался, был пойман и исправлен. Поэтому зрелость измеряется качеством и разнообразием красных, которые система уже выдержала, а не длиной списка зелёных.
Проблема: гонка за зелёным фальсифицирует качество
Когда команда мерит прогресс числом пройденных тестов, она начинает оптимизировать именно это число — а не поведение в реальном мире. Сценарии пишут люди, которые знают систему, и неосознанно ведут диалог по «правильной» ветке. Среды разработки усиливают перекос: упрощают ввод, исправляют опечатки, выбирают наиболее вероятную интерпретацию. В результате растёт зелёный отчёт и стоит на месте реальная устойчивость. Хуже того: зелёный отчёт даёт менеджменту ложный сигнал «готово», и агент уходит в прод с непроверенными краями.
Почему обычные подходы не работают
Перенести классический TDD на агента нельзя по двум причинам. Первая — недетерминизм: один и тот же вход у LLM даёт разные ответы, поэтому единичный зелёный прогон ничего не гарантирует; нужна статистика по многим прогонам, а не галочка. Вторая — кооперативность тестировщика: и человек, и наивный LLM-симулятор через пару реплик начинают помогать агенту, потому что так проще довести диалог до конца. Тест, который подыгрывает, проверяет ожидания автора, а не прочность системы. Добавить сюда ещё тестов не помогает — больше зелёных в удобных условиях не дают ни одного красного в неудобных.
Провал — системный и предсказуемый: дело не в модели, а в отсутствии архитектуры (состояние, контракты, обработка сбоев, передача человеку).
Провал агентных проектов системный и предсказуемый: дело не в «слабой модели», а в отсутствии контура, который ищет красное. Там, где такого контура нет, край находит не команда, а клиент.
Инженерная модель: цикл, который производит красное
RED-driven development меняет сам цикл. Вместо «фича → тест → зелено» он выглядит так: создали агента → создали атакующего агента, чья задача сломать → получили красное → исправили → получили новое, более сложное красное. Контур состоит из трёх частей. Симулятор клиента ведёт диалог с целью максимально затруднить достижение результата — и ему задают модели трудного поведения (тревожный, конфликтный, забывчивый, подозрительный), потому что наивный симулятор слишком быстро начинает помогать. Целевой агент — то, что проверяем. Судья оценивает исход по факту: дошли до цели или нет, а не «вызвал ли агент нужную функцию». Источник сценариев — не синтетика, а корпус реальных диалогов, потому что люди ломаются не так, как воображает разработчик.
Почти 80% отказов — это спецификация и координация, то есть архитектура, а не «слабая модель». Лечится контрактами и явной координацией, а не сменой LLM.
Эта таксономия отказов из реальных трасс выполнения показывает главное: почти 80% сбоев — это спецификация и координация, то есть архитектура, а не качество модели. RED-driven и нужен, чтобы вытаскивать такие отказы наружу до прода — там, где их видно как красное, а не как ушедшего клиента.
Практический вывод для бизнеса
Мерьте зрелость правильно. Спрашивайте не «сколько тестов прошло», а «какие атаки агент уже пережил и кто их придумывал». Если ответ — «тестировала та же команда, что писала», у вас нет независимой оценки надёжности. Заведите отдельный контур, заинтересованный в красном: это дёшево относительно цены агента, который уверенно сказал клиенту не то.
Что поручить. Независимое тестирование агента — отдельная функция, как security review, а не доработка силами авторов. На старте достаточно одного атакующего агента и судьи поверх корпуса ваших реальных диалогов; это окупается уже на первой партии найденных красных.
Чего не делать. Не запускайте агента в клиентский контур по зелёному отчёту от его же разработчиков. Не считайте недетерминизм мелочью: проверяйте на множестве прогонов, а не на одном. Зелёный CI — это гигиена, а не доказательство, что живой человек доходит до результата.
Приложить это к вашему агенту — .
Открытые вопросы
Сколько красного достаточно — зависит от цены ошибки в конкретном процессе: для справочного бота планка ниже, для агента, который оформляет платёж, — кратно выше. Как не превратить RED-driven в бесконечную войну агентов — судья и корпус реальных диалогов держат контур привязанным к настоящим, а не выдуманным провалам. Кто принимает решение «достаточно зрело для прода» — это управленческий вопрос, и решается он до запуска, а не после первого инцидента.
Если у вас уже есть ИИ-агент с зелёными тестами, но нет уверенности, что он выдержит реальных людей, — это и есть сигнал завести красный контур. — посмотрим, какие атаки ваш агент пока не проходил.