Исполняемые спецификации для AI-агентов: гайд по BDD и YAML 2026 | AiManual
AiManual Logo Ai / Manual.
04 Мар 2026 Гайд

Исполняемые спецификации: как заставить кодинг-агентов генерировать рабочий код с первого раза

Практический паттерн работы с кодинг-агентами через исполняемые YAML-спецификации. Улучшаем качество кода, сокращаем итерации. Актуально на 2026 год.

Ты даешь задание агенту. Он пишет код. Код не работает. История повторяется

Знакомая картина? Ты просишь Claude Code или GitHub Copilot Custom Agent написать функцию валидации email. Агент выдает что-то вроде /^[^@s]+@[^@s]+.[^@s]+$/. Тесты падают на user@localhost. Ты объясняешь ошибку. Агент извиняется, правит. Новый код ломается на плюсах в адресе. Этот бесконечный пинг-понг съедает часы.

Проблема не в тупости моделей. Современные LLM вроде GPT-5, Claude 4 или открытых аналогов знают синтаксис лучше многих джунов. Проблема в двусмысленности человеческого языка. \"Проверь email\" - это что? Проверить формат? Существование домена? Отсутствие в спам-базе? Агент угадывает. Часто неудачно.

Стандартный промпт \"напиши функцию для X\" - это игра в испорченный телефон. Ты думаешь об одном, модель понимает другое, код делает третье. Итерации исправлений лишь добавляют шум в контекст.

Контракт вместо разговоров: что такое исполняемая спецификация

Забудь на время о промптах. Представь документ в формате YAML или JSON, который делает две вещи:

  1. Описание поведения на понятном языке (\"Given-When-Then\" из BDD).
  2. Автоматически исполняемые тесты, которые можно запустить против сгенерированного кода.

Это не ТЗ для разработчика. Это машиночитаемый контракт между твоим намерением и реализацией агента. Ты не говоришь \"сделай валидацию\". Ты говоришь: \"вот 10 конкретных примеров входных данных и ожидаемый результат для каждого. Сгенерируй код, который пройдет все эти тесты\".

💡
Идея не нова. BDD (Behavior-Driven Development) существует с 2006 года. Но его симбиоз с AI-агентами, особенно с мощными мультиагентными системами вроде OpenCode или Claude Code, дает взрывной эффект. Агент из угадывающего превращается в решателя конкретных задач.

Из чего состоит этот YAML-контракт

Спецификация - это не просто список тест-кейсов. Это структура, которую агент может парсить и анализировать. Вот базовая схема на 2026 год, адаптированная под понимание современными LLM.

# spec/email_validator.spec.yml
api_version: 'spec.dev/v1'
target:
  component: validator
  function: is_valid_email
  language: python
  framework: pydantic

description: |
  Проверяет, соответствует ли строка формату адреса электронной почты.
  Учитывает RFC 5322, но с практическими ограничениями (не допускает устаревшие форматы).

behavior:
  - scenario: \"Валидные стандартные email-адреса\"
    given: \"функция is_valid_email\"
    cases:
      - input: \"user@example.com\"
        expected: true
        comment: \"Базовый кейс\"
      - input: \"first.last@sub.domain.co.uk\"
        expected: true
        comment: \"Много точек и субдоменов\"
      - input: \"user+tag@example.com\"
        expected: true
        comment: \"Плюс-адресация разрешена\"

  - scenario: \"Невалидные email-адреса\"
    given: \"функция is_valid_email\"
    cases:
      - input: \"plainaddress\"
        expected: false
      - input: \"@no-local-part.com\"
        expected: false
      - input: \"user@.no-domain-part\"
        expected: false
      - input: \"user@domain..com\"
        expected: false
      - input: \"user@localhost\"
        expected: false
        comment: \"Локальные адреса не считаем валидными для нашей бизнес-логики\"

  - scenario: \"Пограничные кейсы и безопасность\"
    given: \"функция is_valid_email\"
    cases:
      - input: \"\"
        expected: false
        comment: \"Пустая строка\"
      - input: null
        expected: false
        comment: \"Null значение, тип входных данных - строка, но на случай ошибки выше\"
      - input: \"x\" * 320 + \"@example.com\"
        expected: false
        comment: \"Превышение максимальной длины локальной части (RFC-ограничение)\"

constraints:
  performance:
    max_time_ms: 10
  security:
    forbid_regex_dos: true
    max_input_length: 1024

generated_code_validation:
  run_tests_command: \"pytest spec/email_validator_test.py -xvs\"
  coverage_threshold: 100
  linter: ruff
  formatter: black

Обрати внимание на детали. target.component и function говорят агенту, что именно строить. behavior.scenarios - это живая документация. constraints диктуют нефункциональные требования. generated_code_validation - инструкция по автоматической проверке. Это полный цикл.

1 Почему YAML, а не промпт в свободной форме?

Структура убивает неопределенность. LLM, особенно новые архитектуры с улучшенным пониманием контекста, отлично извлекают данные из YAML/JSON. Им не нужно догадываться о твоих приоритетах - все явно. Кроме того, такой файл становится артефактом проекта. Его можно версионировать, ревьюить, использовать в CI/CD для автотестов сгенерированного кода. Это основа для агентной инженерии как дисциплины.

Пошаговый план: внедряем исполняемые спецификации в рабочий процесс

Теория - это хорошо. Давай сделаем так, чтобы это работало сегодня. Я использую эту схему с GitHub Copilot Custom Agents и открытыми моделями через инструменты вроде Continue.dev.

1 Шаг 1: Пишем спецификацию ДО того, как звать агента

Переверни привычный процесс с ног на голову. Не \"агент, напиши код, а я потом придумаю тесты\". Сначала садишься и накидываешь сценарии в YAML. Что система должна делать в разных условиях? Какие крайние случаи? Используй формат \"scenario\" и \"cases\". Это заставляет тебя самого продумать логику до мелочей. (Совет: если лень писать YAML с нуля, попроси того же агента по шаблону сгенерировать каркас спецификации - ирония).

2 Шаг 2: Создаем промпт-драйвер, который читает спецификацию

Твой промпт теперь выглядит не как монолог, а как системная инструкция. Вот его ядро:

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

СПЕЦИФИКАЦИЯ (YAML):
{{ВСТАВЬ_СОДЕРЖАНИЕ_SPEC.YAML}}

ИНСТРУКЦИИ:
1. Внимательно проанализируй target, behavior и constraints.
2. Сгенерируй код ТОЛЬКО на указанном языке, который удовлетворит ВСЕМ тест-кейсам.
3. Учтй нефункциональные ограничения (производительность, безопасность).
4. После генерации, предоставь команду для запуска автотестов, чтобы я мог немедленно проверить корректность.

Начни с анализа спецификации. Опиши своими словами, что должна делать функция и какие ключевые edge-кейсы учтены.

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

3 Шаг 3: Автоматизируем проверку - превращаем spec в тесты

Спецификация - это данные. Напиши небольшую утилиту (или попроси агента), которая конвертирует YAML в юнит-тесты. Для Python это может быть pytest, для JS - Jest. Главное - автоматически. Пример для нашего YAML:

# spec_to_test.py (утилита конвертации)
import yaml
import jinja2

# Загружаем spec
with open('email_validator.spec.yml') as f:
    spec = yaml.safe_load(f)

# Шаблон pytest
template = \"\"\"
import pytest
from validator import is_valid_email

{% for scenario in spec.behavior %}
# {{ scenario.scenario }}
{% for case in scenario.cases %}
def test_{{ scenario.scenario | slugify }}_{{ loop.index }}():
    result = is_valid_email({{ case.input | tojson }})
    assert result == {{ case.expected }}, f\"Failed for input: {{ case.input }}\"
{% endfor %}
{% endfor %}
\"\"\"

# Генерируем и сохраняем файл тестов
# ... (пропускаю детали рендеринга)

Запустив эту утилиту, ты получаешь email_validator_test.py с десятками точных тестов. Сгенерированный код агента должен проходить их все. Нет места для интерпретаций.

4 Шаг 4: Интеграция в CI и мониторинг дрейфа

Положи spec-файлы в Git. Настрой GitHub Actions или GitLab CI так, чтобы при изменении спецификации:

  • Запускался агент на генерацию новой реализации.
  • Автоматически запускались сгенерированные тесты.
  • Если тесты падают - падает и сборка.

Это превращает спецификацию в источник истины. Если бизнес-логика меняется (например, нужно разрешить email с кириллицей), ты правишь YAML, а CI заставляет агента перегенерировать код под новые требования. Никакого ручного переписывания тестов и надежд на память. Это прямой ответ на проблему технического долга от AI-генерации.

Где собака зарыта: нюансы и грабли, на которые ты точно наступишь

Метод не панацея. Вот что может пойти не так, и как избежать.

ОшибкаПочему возникаетКак исправить
Агент генерирует код, который проходит тесты, но нарушает constraints (например, медленный)LLM плохо учитывают нефункциональные требования, если они не проверяются автоматически.Добавь в generated_code_validation этап бенчмарка или статического анализа сложности. Используй pytest-benchmark.
Спецификация становится монолитом на 500 строк, непонятным ни тебе, ни агенту.Желание покрыть все случаи сразу. Агент теряется в деталях.Дроби спецификации по принципу одной ответственности. Один файл - одна функция или один сценарий. Ссылайся между ними через $ref.
Агент предлагает \"костыльное\" решение, которое технически проходит тесты, но уродливо.Он оптимизирует под прохождение тестов, а не под чистоту кода.Добавь в constraints секцию code_quality с требованиями по линтеру (ruff, eslint). В промпте явно попроси избегать антипаттернов.
Тесты, сгенерированные из spec, сами содержат баги (некорректные assertion).Утилита конвертации написана с ошибками или edge-кейсы в input данных (например, спецсимволы) сломали генерацию кода теста.Пиши утилиту конвертации максимально просто. Протестируй ее на десятке разных spec. Или используй готовые инструменты, если они появятся к 2026 (пока их нет).

Самый опасный нюанс: иллюзия полноты. Ты написал 20 тест-кейсов в spec и думаешь, что покрыл все. Агент генерирует код, который их проходит. Но в продакшене всплывает двадцать первый случай, который ты не предусмотрел. Спецификация - не замена мышлению. Это инструмент для повышения точности, а не магический черный ящик. Всегда оставляй место для ручного анализа сложных сценариев.

Вопросы, которые ты уже хочешь задать

Это же замедляет работу! Раньше я просто просил агента, а теперь надо писать YAML...

В краткосрочной перспективе - да, добавляет шаг. В долгосрочной - экономит часы на дебаг и перегенерацию. Когда спецификация написана, ты можешь давать ее разным агентам (Copilot, Claude, локальной модели) и получать сопоставимый результат. Это инвестиция в стабильность. Особенно важно в команде, где несколько человек работают с агентами.

А если моя задача - не изолированная функция, а целая фича с API, базой и интерфейсом?

Спецификации масштабируются. Создай набор файлов: api_contract.yml, database_schema.yml, ui_flow.yml. Используй ссылки между ними. Современные мультиагентные системы, те же OpenCode или Claude Code, могут распределять такие спецификации между специализированными агентами (бэкенд, фронтенд, тестировщик). Главное - держать контракты между модулями в машиночитаемом виде.

Поддерживают ли это современные IDE и плагины?

На 2026 год - да, экосистема растет. Плагины для VS Code и JetBrains учатся читать spec-файлы и предлагать на их основе контекстные промпты. GitHub Copilot Custom Agents позволяет загружать спецификации как контекст. Ожидай, что к концу года появятся специализированные инструменты для управления библиотекой исполняемых спецификаций.

Можно ли использовать для legacy кода, который нужно понять или переписать?

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

Что будет дальше? Спецификация как интерфейс

Я вижу будущее, где исполняемые спецификации станут стандартным интерфейсом между человеком и машиной в разработке. Ты не будешь писать промпты на естественном языке для рутинных задач. Ты будешь выбирать из каталога шаблонов спецификаций (\"валидация данных\", \"REST endpoint CRUD\", \"миграция базы\"), кастомизировать их под свой контекст и отправлять агенту на выполнение.

Агенты, в свою очередь, станут лучше понимать эти структуры. Модели нового поколения, обученные не только на коде, но и на корреляции между spec и реализацией, будут выдавать код с первой попытки. Возникнет рынок проверенных спецификаций для типовых задач. И главное - исчезнет мучительная боль \"он меня не понимает\".

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

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

Подписаться на канал