Amiga
Оглавление курса · урок 15 из 24

Модуль 3 · Датчики и ограничения · урок 15 из 24

Проверка поведения — главный открытый вопрос

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

Что говорят источники

Биргитта Бёкелер в статье Harness engineering for coding agent users делит то, что регулирует обвязка, на три категории: сопровождаемость, архитектурная пригодность и поведение. Первые две сегодня строятся сравнительно легко. Поведение она называет «слоном в комнате». Типичная практика — функциональная спецификация как направляющая и сгенерированные агентом тесты, покрытие, мутационное тестирование и ручная проверка как датчики. Оценка автора: такой подход слишком доверяет тестам, которые написал сам агент, и этого пока недостаточно. Паттерн approved fixtures у части её коллег работает хорошо, но и он, по её словам, не универсальный ответ.

Anthropic описывает те же провалы с другой стороны (длинные задачи, дизайн обвязки): агент склонен преждевременно объявлять работу готовой и снисходительно оценивать собственный результат. Юнит-тесты и curl пропускали ошибки, которые находила проверка через браузер.

OpenAI в своём эксперименте отводит людям роль, которая прямо касается поведения: расставлять приоритеты, превращать отзывы пользователей в критерии приёмки и проверять результат.

Почему тесты агента — слабое доказательство

Механика простая. Агент пишет код и тесты из одного и того же понимания задачи. Если понимание неверно, тесты подтвердят ошибку. Добавьте к этому типичные сбои:

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

Покрытие ни от чего из этого не защищает: почти все такие тесты исполняют код и засчитываются в покрытие.

Набор приёмов

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

Критерии приёмки до кода

Самый дешёвый и самый недооценённый слой. Человек или аналитик формулирует, что значит «готово», до того как агент начал писать. В эксперименте Anthropic это называлось sprint contract: до начала работы генератор и оценщик согласовывали, что будет сделано и как это проверить. Для задачи из Kaiten это раздел «Done when» в постановке: «форма заявки на странице услуги отправляет лид, в CRM появляется карточка с UTM-метками, при пустом телефоне — понятная ошибка под полем». Каждый пункт должен проверяться наблюдением, а не мнением. Как выстроить такую постановку — в уроке о spec-driven development.

Тест падает на старом коде

Порядок red/green, который Саймон Уиллисон описывает среди паттернов агентной инженерии: сначала тест, который воспроизводит баг или фиксирует новое поведение и падает, потом исправление. Это проверяется механически: прогоните новый тест на коммите до изменения. Если он зелёный, он ничего не доказывает.

Защищённые тесты

В схеме Anthropic агенту прямо запрещено удалять и править тесты, а в списке фич он может менять только поле passes. В Codex такое правило можно сделать не просьбой, а проверкой: хук PreToolUse отклоняет правки в каталоге приёмочных тестов во время работы над реализацией.

python · .codex/hooks/protect_acceptance.py
import json
import sys

event = json.load(sys.stdin)
patch = event.get("tool_input", {}).get("command", "")
if "tests/e2e/acceptance/" in patch:
    print(json.dumps({
        "hookSpecificOutput": {
            "hookEventName": "PreToolUse",
            "permissionDecision": "deny",
            "permissionDecisionReason": (
                "Приёмочные тесты утверждены до начала работы и не меняются агентом. "
                "Исправьте реализацию. Если тест неверен — остановитесь и опишите почему."
            ),
        }
    }))

Подключается матчером apply_patch|Edit|Write на событие PreToolUse; текст патча приходит в tool_input.command. Это защита от случайного «короткого пути», а не от злонамеренного обхода: правку через shell-команду этот хук не увидит, так что итоговую проверку дублируйте в CI — сравнением каталога с main.

Мутационное тестирование

Мутационный тестер вносит в код мелкие ошибки и проверяет, падают ли тесты. Выжившие мутанты — места, где тесты ничего не проверяют. Для PHP это Infection, для JS/TS — Stryker. Гонять его на всём проекте дорого; Бёкелер относит такие проверки к этапу после интеграции. Практичный вариант — мутационный прогон только по изменённым файлам в MR, где агент добавил тесты.

Approval-тестирование

Вместо десятков ассертов фиксируется эталонный вывод целиком, человек его один раз утверждает, а дальше любое отличие требует повторного утверждения. Хорошо ложится на детерминированный вывод: HTML посадочной, собранной из JSON-описания, ответ API, сгенерированный XML-фид, скриншот страницы.

typescript · tests/e2e/landing-snapshot.spec.ts
import { test, expect } from '@playwright/test';

test('посадочная услуги совпадает с утверждённой', async ({ page }) => {
  await page.goto('/services/mobile-development');
  await expect(page.locator('main')).toHaveScreenshot('services-mobile.png', {
    maxDiffPixelRatio: 0.01,
  });
});

Ключевое правило: обновлять эталоны (npx playwright test --update-snapshots) может только человек или отдельный шаг с явным одобрением. Если агент сам перезаписывает эталоны, приём превращается в формальность.

Независимый оценщик

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

Доказательства, а не отчёт

В эксперименте OpenAI агент по одному промпту записывает видео с багом до исправления и после. Для ревьюера это меняет работу: вместо чтения диффа и веры отчёту — просмотр тридцати секунд записи. Playwright умеет писать видео и трассы (video: 'on', trace: 'on' в конфиге), и их можно прикладывать к MR артефактами CI.

Где человек остаётся обязательно

Наш вывод из источников: сколько слоёв нужно, решает риск изменения, а не зрелость агента.

Изменение Минимум проверок
Текст, стили, контент структурные проверки, скриншот-сравнение
Новая страница или компонент критерии приёмки, e2e, визуальная проверка человеком
Бизнес-логика, расчёты, формы заявок тест падает на старом коде, защищённые приёмочные тесты, мутационный прогон, человек на приёмке
Платежи, персональные данные, интеграции с CRM всё выше плюс ревью человеком, знающим домен

Человек остаётся там, где нужно суждение о намерении: правильно ли понята задача, то ли это поведение, которое ждёт заказчик. Это не может проверить ни один датчик, потому что эталона, кроме головы заказчика, нет.

Открытые вопросы

Как измерить покрытие обвязки — по аналогии с покрытием кода — пока не знает никто, Бёкелер прямо называет это открытым вопросом. Молчащий датчик может означать и хорошее качество, и слепое пятно. Частичный ответ — свои evals на реальных провалах: если обвязка пропустила баг, этот баг становится задачей в наборе. Об этом урок о собственных evals.

Попробуйте сами

10–15 мин на рабочем месте
  1. Возьмите последний баг, исправленный агентом, и прогоните его тест на коммите до исправления. Упал ли он?
  2. Добавьте хук, защищающий каталог приёмочных тестов, и дайте агенту задачу, где проще всего «исправить» тест. Посмотрите, как он поведёт себя после отказа.
  3. Выберите одну детерминированную страницу или ответ API и сделайте для неё approval-тест. Договоритесь в команде, кто имеет право обновлять эталон.

Коротко

  • Агент пишет код и тесты из одного понимания задачи, поэтому его тесты — слабое доказательство.
  • Критерии приёмки до кода — самый дешёвый слой проверки поведения.
  • Тест должен падать на старом коде; приёмочные тесты агент не меняет — и это проверяется хуком и CI.
  • Мутационное и approval-тестирование ловят тесты, которые ничего не проверяют.
  • Объём проверок определяется риском изменения; суждение о намерении остаётся за человеком.
Отметка хранится только в вашем браузере
Хотите связаться с владельцем
компании напрямую?
Дмитрий Тарасов
Дмитрий Тарасов
СЕО

НАПИСАТЬ

Написать в MAX