TL;DR
Исследование показывает, как кодовые агенты (Codex, Claude Code, OpenCode) пишут проверки по текстовому ТЗ. Агенту дают ТЗ, репозиторий и готовую реализацию. Он должен написать набор проверок: генератор тестовых сценариев (с какими аргументами вызывать код) и сами проверки (что должно выполняться). Проверку тестируют на трёх реализациях: эталонной, с внедрённым нарушением и валидной альтернативной. Альтернативная написана иначе, но ТЗ не нарушает.
Главная находка: агенты пишут проверки, которые копируют поведение реализации, а не требования ТЗ. Поэтому проверка ловит баги, но заодно бракует рабочий код: требует конкретный порядок элементов, точный текст ошибки или побочный эффект, о которых ТЗ молчит. Лучший результат — ровно верные проверки лишь примерно на 63% задач. Нарушение агенты находят чаще, чем пишут верные проверки: разрыв 11–22 пункта съедают ложные тревоги. Если показать агенту реализацию с багом, он теряет 19–31 пункт верности: его проверки либо принимают баг, либо бракуют правильный код. Агент «заземляет» проверки на код перед глазами.
Метод оценки из статьи переносится в практику простой схемой: проверь тесты агента не только на «ловит баг», но и на «пропускает корректную переделку». Решающий критерий качества проверок — «не больше и не меньше, чем требует ТЗ». Следствие для работы: по возможности не давай агенту код, когда он пишет проверки по ТЗ. Если код всё же в контексте, прямо требуй считать стандартом ТЗ, а не код.
Схема проверки тестов агента (так оценивают в статье)
ШАГ 1: ТЗ → разбить на атомарные требования (одно требование = одно нарушение)
ШАГ 2: Агент получает ТЗ + репозиторий + реализацию → пишет набор проверок:
а) генератор сценариев (какие аргументы подавать)
б) проверки (что должно выполняться), не привязанные к конкретному сценарию
ШАГ 3: Прогон на трёх реализациях:
• эталонная → проверки ДОЛЖНЫ принять
• валидная альтернатива (другой код, ТЗ не нарушает) → ДОЛЖНЫ принять
• с нарушением ТЗ → ДОЛЖНЫ отклонить
ШАГ 4: Верно = нарушение отклонено И всё корректное принято
Ложная тревога = отклонён корректный код
Пример применения
Задача: Интернет-магазин на Python, как у Ozon или Wildberries. Есть функция расчёта цены корзины с промокодом. ТЗ: «Скидка по промокоду не может превышать 30% от суммы корзины. Скидка не применяется к товарам с пометкой "уценка". Итог округляется вниз до целого рубля». Код уже написан. Нужно, чтобы агент написал проверки, которые поймают будущие баги при рефакторинге, но не сломаются от безобидных изменений вроде другого порядка позиций в чеке.
Промпт:
Ты пишешь проверки для функции apply_promo в файле cart/pricing.py.
Стандарт правильности — ТЗ ниже, а не текущий код. Код может не соответствовать ТЗ.
ТЗ:
1. Скидка по промокоду не превышает 30% от суммы корзины.
2. Скидка не применяется к товарам с пометкой "уценка".
3. Итоговая сумма округляется вниз до целого рубля.
Сделай для КАЖДОГО пункта ТЗ отдельно:
А) Генератор сценариев: список разных вызовов (пустая корзина, одна позиция,
только уценка, промокод на 50%, копейки в сумме, смесь обычных и уценённых).
Для каждого — конкретные аргументы.
Б) Проверки: утверждения о результате, которые следуют ТОЛЬКО из текста ТЗ.
Проверка не привязана к конкретному сценарию и годится для любого вызова.
Правила проверок:
- Проверяй не больше и не меньше, чем требует ТЗ.
- Не проверяй то, о чём ТЗ молчит: порядок позиций в ответе, текст сообщений,
названия внутренних полей, число вызовов вспомогательных функций.
- Если сомневаешься, следует ли утверждение из ТЗ, выкинь его и запиши в список
«Не проверяю, потому что ТЗ молчит».
В конце для каждой проверки ответь: «Какой корректный код она могла бы
ошибочно отклонить?» Если такой код легко представить, ослабь проверку.
Результат: Агент выдаст для каждого пункта ТЗ набор сценариев и проверок, не привязанных к конкретному вызову. Отдельным списком он перечислит, что сознательно не проверяет. В конце будет самокритика по каждой проверке: какой корректный вариант кода она могла бы забраковать. Вероятнее всего, в проверках не будет жёсткой привязки к порядку позиций или тексту ошибок. Но полной гарантии это не даёт: даже лучшие агенты в исследовании промахивались на трети задач. Поэтому проверки всё равно надо прогнать на заведомо правильной переделке кода и на заведомо сломанной.
Почему это работает
Слабость. Если в контексте лежит готовый код, модель берёт его как образец. Тест из таких проверок превращается в «пересказ того, что код делает сегодня». Любое отличие от кода, даже допустимое по ТЗ, он видит ошибкой. Если в коде баг, проверка зафиксирует и баг. Это показал эксперимент: подсунули реализацию с нарушением, и все агенты потеряли 19–31 пункт верности.
Сильная сторона. Модель умеет читать текстовые требования и выводить из них утверждения о результате. Ещё она хорошо придумывает разнообразные входные данные. Находить нарушения, когда есть что проверять, ей удаётся: обнаружение у агентов заметно выше верности. Слабое место в проверках, а не в количестве сценариев.
Что делает подход. Он разводит источники: стандарт — ТЗ, код — только справка. Он заставляет отдельно отвечать на вопрос «что из этого ТЗ реально требует?» и вычёркивать лишнее. Явный список «не проверяю, потому что ТЗ молчит» работает как барьер от привычки перечислять всё, что видно в коде.
Рычаги управления: - Убрать реализацию из контекста совсем → самый сильный рычаг против копирования кода (но тогда агент не сможет запускать сценарии). - Строгость вычёркивания («при сомнении выкинь») → ослабь, если пропускаются баги; усиль, если агент бракует корректный код. - Разбивка ТЗ на атомарные пункты → одно требование на одну проверку, проще понять, что именно сломалось. - Финальный вопрос «какой корректный код ты бракуешь» → можно задать отдельным проходом другой модели.
Шаблон промпта
Ты пишешь проверки для {функция_или_модуль} в {файл}.
Стандарт правильности — ТЗ ниже, а не текущий код.
Код может не соответствовать ТЗ, не копируй его поведение.
ТЗ:
{нумерованный_список_требований}
Сделай для КАЖДОГО требования отдельно:
А) Генератор сценариев: набор конкретных вызовов (аргументы), включая
граничные случаи: {какие_граничные_случаи}.
Б) Проверки: утверждения о результате, которые следуют ТОЛЬКО из текста ТЗ.
Проверка не привязана к конкретному сценарию и работает для любого вызова.
Правила:
- Проверяй не больше и не меньше, чем требует ТЗ.
- Не проверяй то, о чём ТЗ молчит: {что_ТЗ_не_фиксирует}.
- Сомневаешься — выкинь утверждение и запиши в «Не проверяю, потому что ТЗ молчит».
В конце по каждой проверке ответь: какой корректный код она могла бы ошибочно
отклонить? Если легко представить — ослабь проверку.
Что подставлять:
- {нумерованный_список_требований} — ТЗ, разбитое на отдельные пункты. Одно требование должно ломаться независимо от других.
- {какие_граничные_случаи} — пустые данные, лимиты, копейки, нестандартные типы.
- {что_ТЗ_не_фиксирует} — порядок элементов, тексты ошибок, внутренние поля, побочные эффекты. Эти пункты ты знаешь лучше агента.
🚀 Быстрый старт — вставь в чат:
Вот шаблон промпта для проверок «по ТЗ, а не по коду». Адаптируй под мою задачу: {опиши_функцию_и_ТЗ}.
Задавай вопросы, чтобы заполнить поля.
[вставить шаблон выше]
LLM спросит, какие требования в ТЗ, какие граничные случаи важны и что в ТЗ сознательно не зафиксировано. Это нужно, чтобы метод работал: без чёткого списка того, о чём ТЗ молчит, агент не сможет отсечь лишние проверки.
Ограничения
⚠️ Статья — бенчмарк, а не готовый метод. Авторы измерили, где агенты ошибаются, но не проверили, насколько помогает промпт вроде шаблона выше. Шаблон собран из формулировки задачи в статье и главных находок. Прирост от него в статье не измерен.
⚠️ Лучший результат всё равно слабый. Ни один агент не построил верный набор проверок больше чем на 63% задач. Прогони проверки на правильной и сломанной версиях кода сам.
⚠️ Нужна чёткая спецификация. Задачи в бенчмарке — «атомарные» требования, выписанные из хорошего ТЗ. Если ТЗ расплывчато («работает быстро», «удобно»), метод не сработает: нечего вычёркивать и не с чем сверять.
⚠️ Только Python и синтетические нарушения. Баги внедряла другая модель, не реальная команда разработчиков. Проверено на Python-репозиториях с открытым кодом.
⚠️ Отказ от кода в контексте имеет цену. Если убрать реализацию, агент не сможет запускать сценарии. Баланс — оставить код, но жёстко приказать считать стандартом ТЗ.
Как исследовали
Исследователи взяли 30 реальных функций из открытых Python-проектов (13 репозиториев) и разбили каждое ТЗ на мелкие требования. Получилось 291 задача. Для каждой требование нарушали: модель Claude Opus 5 вносила в код баг, который не ловили оригинальные тесты. Вторая модель из другого семейства, GPT-5.6-sol, голосованием из трёх ответов подтверждала, что это настоящее нарушение, а не безобидное отличие. Неудачные варианты выбрасывали. «Валидными альтернативами» становились баги из соседних требований: для текущего ТЗ они корректны, а для своего — нет. Двое авторов вручную проверили 50 задач и согласились между собой в 94,7% случаев; с решением пайплайна совпали на 98%.
Затем четыре агента (Codex с GPT-5.6-sol, Claude Code с Opus 5, OpenCode с DeepSeek-V4-Pro и GLM-5.3) по 80 вызовов модели на задачу писали наборы проверок. Верными проверки считались, если баг отклонён, а всё корректное принято. Верность получилась 45–63%, обнаружение 65–82%, ложные тревоги 15–27%. Удивила разница в рейтингах: GPT-5.6-sol обнаружил нарушения на 8 пунктов чаще GLM-5.3, но и ложных тревог дал на 8 пунктов больше, и верность у них оказалась почти равной. Ложные тревоги составили 42–60% всех неудач.
Чтобы понять, виноваты сценарии или проверки, исследователи подставили агентам «идеальные» сценарии, заведомо вскрывающие баг. У трёх из четырёх агентов большинство пропущенных нарушений осталось: проверки по-прежнему принимали баг. Значит, узкое место в самих проверках. Дополнительно агентам показывали реализацию с багом вместо эталонной. Все четверо потеряли 19–31 пункт верности и стали бракуя неизвестную им эталонную реализацию в 12–41% задач: агент подгонял проверки под то, что видел.
Адаптации и экстраполяции
🔧 Техника: добавить «альтернативную реализацию» → ловим ложные тревоги
После того как агент написал проверки, попроси его (или другого агента) переписать функцию иначе: другой порядок, другие внутренние структуры, другие тексты ошибок, но с тем же поведением по ТЗ. Прогони проверки на ней. Если что-то упало, это ложная тревога: проверка требует больше, чем сказано в ТЗ. Идея взята из дизайна бенчмарка, но в статье эту процедуру применяют для оценки, а не как приём для практика.
🔧 Техника: сломать код специально → ловим пропущенные баги
Попроси другого агента: «Внеси в код ровно одно нарушение пункта {N} ТЗ, которое не видно по чтению кода, но видно при запуске». Если проверки пропускают нарушение, они слабы.
Экстраполяция: два прохода с разделением ролей.
Проход 1 (агент А, БЕЗ доступа к коду):
Вот ТЗ: {ТЗ}. Напиши проверки только из текста ТЗ. Код тебе не показан.
Проход 2 (агент Б, С доступом к коду):
Вот ТЗ, вот код и вот проверки агента А. Запусти проверки на коде.
Если проверка падает на корректном коде, определи по ТЗ: ошибка в коде
или проверка требует больше, чем в ТЗ? Не меняй проверку, если ТЗ её подтверждает.
Это моя комбинация, не из статьи: она применяет вывод «агент копирует код» через разделение контекста.
Ресурсы
- SpecGuardBench: Can Coding Agents Construct Reliable Validation Harnesses from Natural Language Specifications? (Preprint)
- Код и данные: github.com/coxhin/SpecGuardBench, huggingface.co/datasets/coxhin/SpecGuardBench
- Авторы: Zhiqing Zhong, Mingyu Chen, Aoyang Fang, Yuzhong Zhang, Haoye Tian, Lionel Briand, Boxi Yu, Pinjia He
- Организации: The Chinese University of Hong Kong, Shenzhen; Aalto University; Lero (Research Ireland Centre for Software); University of Limerick; University of Ottawa
- Основа датасета: FeatureBench (Zhou et al., 2026)
