|
Professor Seleznov
|
«Кажется, стало лучше. Или хуже. Или так же. Не знаю» — эта фраза стала последней каплей. После неё я сел писать бенчмарк.
Привет! Это снова Михаил Федоров. В первой статье — архитектура QA Assist: 11 AI-агентов от декомпозиции требований до готовых автотестов. Во второй — как «4 часа подключения» превращаются в неделю корпоративной реальности. В третьей — почему пирамида тестирования ломается, когда тест-дизайнером работает LLM. Сегодня — про то, как я решил наконец-то перестать оценивать агента «на глаз» и собрал отдельный проект-бенчмарк, на котором можно честно сравнивать прогоны: версии агента, отдельные «улучшалки», даже эксперименты с моделями. В качестве бонуса покажу все артефакты, которые агент готовит за один прогон пайплайна. И бенчмарк, и артефакты — в публичном доступе, ссылки в конце статьи. Обсудить всё это можно в Telegram-группе. - Оглавление
- Проблема: как понять, что агент стал лучше
- Идея бенчмарка
- Что внутри проекта CallMeBack
- Как я готовил тестовый проект к прогону агента
- QA Assist vs нативный Claude Code: что на выходе
- Результаты бенчмарка: QA Assist vs Claude Code «в лоб»
- Что показал бенчмарк
- 1. Проблема: как понять, что агент стал лучше AI-агент — как новый джун в команде: сначала ему надо подробно объяснить, что и как, и только потом помощь становится по-настоящему ощутимой. Поэтому вы постоянно его «обучаете»: переписываете системные промты, добавляете шаги в пайплайн, подкручиваете правила консолидации тест-кейсов, меняете провайдера моделей, вводите кеширование, чтобы сэкономить токены. И каждый раз — одна и та же беспомощность: похоже, стало лучше. Но доказать не могу. Это очень неприятное чувство. Вы тратите часы на оптимизацию, делаете коммит — и не можете уверенно сказать, что коммит улучшил систему. Особенно весело с расходом токенов: вы переписали один из шагов так, чтобы он расходовал в три раза меньше, — но убедиться, что качество детекции при этом не просело, на живых проектах проблематично. Мне нужна была среда, где я могу запустить агента, посмотреть в табличку и сказать: вот эта версия лучше прошлой по такой-то метрике на столько-то процентов. - 2. Идея бенчмарка Как мы обычно понимаем, что улучшение процессов QA сработало? Замеряем метрику до, внедряем изменение, замеряем после. Простая и проверенная схема. Только растянутая во времени на месяцы и подверженная куче параллельных факторов: пока вы измеряете эффект перехода на shift-left, в команду пришёл новый разработчик, поменялся техлид, команда переехала на другой фреймворк и т.п. Любая дельта в метрике может объясняться чем угодно — кроме вашего изменения. С AI-агентом ситуация принципиально другая. Изменения делаются часто: переписали системный промт, добавили шаг в пайплайн, поменяли провайдера моделей. И каждый раз нужно быстро понять — стало лучше или хуже. Ждать пару месяцев, пока накопится статистика на живых проектах, нельзя: к этому моменту сама версия агента уже устареет. Здесь нужна 100% контролируемая среда. В итоге возможны два сценария:
- Анализировать реальность — собирать метрики на живых проектах. Точно по эффекту, но не годится для быстрых решений: данных мало, шум большой, цикл — месяцы.
- Считать на песочнице — фиксированный проект с заложенными багами, повторяемые прогоны, результаты сравнимы между собой. Быстро, дёшево, чисто.
Именно второго — быстрых подсказок для принятия решений — мне и не хватало. Так появился бенчмарк. Он фиксирует условия. Один и тот же проект. Одно и то же окружение. Один и тот же набор багов, заложенных намеренно. Одна и та же система оценки результата. Меняется только то, что я хочу измерить — версия агента, версия промта, конкретная улучшалка. С его помощью можно отвечать на практические вопросы:
- Какие типы багов агент ловит, а какие систематически пропускает?
- Насколько стабильно он их ловит между запусками?
- Помогает ли конкретная улучшалка или это иллюзия?
- Сколько это стоит?
Я искал готовый инструмент. Что-то под учебные задачи есть, под LLM-кодинг есть, под QA-агентов в нужном мне виде — нет. Поэтому собрал свой. Ключевой принцип: бенчмарк — это отдельный проект, а не часть основного репозитория ассистента. Агент должен работать с проектом точно так же, как с боевой задачей. Второй принцип — компактность фичи. Гоняю бенчмарк часто, поэтому он должен давать сигнал минимальным числом токенов. Большой проект — это большой контекст, длинный пайплайн и дорогая итерация. Маленький — это быстро, дёшево и можно проверять гипотезы хоть несколько раз в день. Репозиторий: qa-benchmark-callmeback.
Живой стенд: http://45.151.31.218:5000/. - 3. Что внутри проекта CallMeBack Бенчмарк-проект — это маленькое Flask-приложение «заявка на обратный звонок». Лендинг с формой (имя, телефон, удобное время, комментарий), страница /success, админка с Basic Auth для просмотра заявок. В репозитории — две ветки. В main лежит то, что мы показываем агенту: код проекта и требования (бизнес-контекст, User Stories с AC, спецификация API). В ветке benchmark — то, что агент видеть не должен: эталонный список багов и методика оценки. Важный момент: эталонные списки лежат в ветке benchmark (bugs_us1.yaml — 14 багов под публичную форму, bugs_us2.yaml — 11 багов под админку) и должны быть исключены из контекста перед прогоном агента — иначе нечестно. Внутри проекта намеренно заложены 25 багов. По категориям:
| Расшифровка категории |
Код категории |
Пример |
| Безопасность |
security |
XSS, SQL injection, утечка stack trace |
| Валидация |
validation |
не проверяется длина поля, не подрезаются пробелы |
| Функциональность |
functional |
кнопка не реагирует, фильтр возвращает не то |
| Соответствие API-контракту |
api_contract |
неверный HTTP-код, неверный формат поля |
| UI/UX |
ui_ux |
опечатки, не адаптивная вёрстка |
| Доступность |
a11y |
нет лейблов у полей, отключён focus-outline |
| Производительность |
performance |
долгий ответ ручки, выборка без пагинации |
| Целостность данных |
data_integrity |
данные пишутся в БД в разных форматах |
| Локализация |
i18n |
даты в неверной таймзоне |
| Забытые артефакты |
stray |
console.log в проде, мёртвый код |
- 4. Как я готовил тестовый проект к прогону агента Подготовка описана в статье «Возможно ли запустить AI-тестирование за 4 часа?». Сейчас нас интересует раздел 3, шаги 1 и 2. Кратко опишу основное: 1. Завести новый проект в Jira, создать там US, скопировав описание из файла требований в репозитории. 2. Собрать Global Context с помощью global-context-builder. 3. Запустить агента:
test-orchestrator pipeline JTPZ-40
Дальше агент работал сам: декомпозировал требования, генерил сценарии, прогонял на реальном стенде, писал автотесты, запускал, отлаживал, оформлял баг-репорты в Jira. Бонус. Для сравнения я прогнал тот же проект «в лоб» — просто скормил Claude требования и попросил найти баги. Никакого пайплайна, никакой инфраструктуры, один промт. Результаты — в разделе 6.
claude --chrome \ "Ты — QA-инженер. Перед тобой требования к проекту: [REQUIREMENTS_US1.md](https://github.com/spoon03/qa-benchmark-callmeback/...EMENTS\_US1.md). \ Реализация доступна по адресу http://localhost:5000. \ Изучи требования и найди все баги в реализации."
- 5. QA Assist vs нативный Claude Code: что на выходе Прежде чем сравнивать результаты бенчмарка, давайте сравним артефакты, генерируемые агентами. QA Assist за один прогон оставляет в репозитории целый слой документации и кода — всё, что появилось ниже, я не писал и не редактировал руками.
Нативный Claude Code на выходе даёт список найденных багов — и всё. Если вам нужны дополнительные артефакты — traceability matrix, отчёт по расхождениям, структурированные сценарии и так далее — всё это придётся описывать в системном промте вручную. В скиллах QA Assist это уже заложено: каждый шаг знает, что производить и в каком формате. 5.1. Декомпозиция требований Папка: testing/requirements/JTPZ-40/
| Файл |
Что внутри |
| US-JTPZ-40.md |
User Story по шаблону: бизнес-ценность, формулировка, use case, основной сценарий, расширения (альтернативы и ошибки), acceptance criteria, ссылки на технические задачи |
| TASK-JTPZ-40-01.md |
Frontend-таска: разметка формы, клиентская валидация, обработка кодов ответа (200/201/400/429), сетевые ошибки, страница успеха |
| TASK-JTPZ-40-02.md |
Backend-таска: контракт API, схема валидации, нормализация телефона, rate-limit, формат created_at, security-требования |
| REQUIREMENTS_REDUNDANCY_REPORT.md |
Отчёт оптимизатора требований: какие пункты дублировались между US и TASK, какие смерджились/удалены с алиасами |
Каждое требование получает уникальный ID. Это нужно потом, чтобы каждый тест-кейс ссылался на конкретный пункт спецификации, и можно было собрать матрицу покрытия. Контроль дублей на уровне требований. REQUIREMENTS_REDUNDANCY_REPORT.md — недавнее нововведение. Проблема выросла из дублирования требований на различных уровнях пирамиды: одно и то же поведение описывалось и в US, и в TASK, и генерация сценариев плодила по два-три TC на одну суть. Сейчас после причёсывания требований по шаблонам за декомпозицию по пирамиде и дедупликацию отвечает отдельный агент — test-requirements-optimizer. 5.2. Тестовые сценарии Папка: testing/scenarios/JTPZ-40/
| Файл |
Что внутри |
| TASK-JTPZ-40-01-SC-UI.json |
UI тест-кейсы (isolated): валидация формы, состояния кнопки, обработка ответов сервера, focus, label, мобильная вёрстка |
| TASK-JTPZ-40-02-SC-API.json |
API тест-кейсы: happy path, валидация полей, формат телефона, нормализация, rate-limit, SQL-инъекции (TC-JTPZ-40-BE-001..030) |
| US-JTPZ-40-SC-E2E.json |
E2E сценарии: полный happy path, обработка серверной валидации, обработка 429 |
| Coverage.md |
Requirements traceability matrix: какой TC закрывает какое требование, итоговый процент покрытия |
| SCENARIOS_REDUNDANCY_REPORT.md |
Отчёт оптимизатора по тест-кейсам (cross-level дубли, e2e step overlap, excessive granularity) |
| ERRORS_DISCREPANCIES.md |
Расхождения между требованиями и реальностью, найденные на этапе генерации сценариев (7 штук) |
| ERRORS_DISCREPANCIES_API.md |
Дополнительные API-расхождения, всплывшие при отладке тестов (9 штук) |
| ERRORS_DISCREPANCIES_UI.md |
Дополнительные UI-расхождения, всплывшие при отладке тестов (8 штук) |
| ERRORS_TEST-DATA*.md |
Списки недостающих тестовых данных (общий + per track) |
5.3. Автоматизация Папка: testing/auto/JTPZ-40/
| Файл |
Что внутри |
| repoapi/tests/JTPZ-40/ |
Сгенерированные API-тесты (pytest) |
| repoui/tests/JTPZ-40/ |
Сгенерированные UI-тесты (Playwright + pytest) |
| AUTOMATION_REPORT.md |
Сводный отчёт по сгенерированным тестам |
| DEBUG_REPORT.md |
Лог отладочного цикла |
Всё пишется в клонированные автотест-репозитории (_repo_api/, repoui/) — агент работает в их структуре, а не в своей, чтобы потом одним коммитом улететь в MR. Что получилось на JTPZ-40:
| Трек |
Тестов |
PASSED |
xFailed |
Найдено дефектов |
| API |
33 |
6 |
27 |
9 (JTPZ-49..57) |
| UI (Playwright) |
28 |
18 |
10 |
8 (JTPZ-58..65) |
Каждый xfail в коде помечен ссылкой на Jira-тикет с багом. Логика простая: тесты не должны быть «зелёными» из-за того, что мы знаем про баг, — они должны быть xfail с явной причиной. Когда баг чинят, тест становится зелёным сам. - 6. Результаты бенчмарка: QA Assist vs Claude Code «в лоб» Скоринг считается по простому правилу: для каждой находки ставится одна из трёх меток — TP (совпадает с эталоном), FP (выдумки или баги, не включённые в эталон), Miss (эталонный баг не найден). Дальше из этого считается recall = TP / (TP + Miss) — доля найденных эталонных багов, и FP-rate = FP / (TP + FP) — доля ложных срабатываний среди всех заведённых тикетов. Оба прогона — по одному и тому же проекту, одному и тому же набору из 14 эталонных багов (US-1). Найденные баги зафиксированы:
6.1. Общие метрики
| Метрика |
QA Assist |
Claude Code «в лоб» |
| TP |
11 / 14 |
7 / 14 |
| FP |
6 |
4 |
| Miss |
3 |
7 |
| Recall |
79% |
50% |
| FP-rate |
35% |
36% |
6.2. Recall по категориям
| Категория |
Эталон |
QA Assist |
Claude «в лоб» |
| validation |
3 |
3 (100%) |
2 (67%) |
| api_contract |
2 |
2 (100%) |
2 (100%) |
| ui_ux |
2 |
2 (100%) |
1 (50%) |
| a11y |
2 |
2 (100%) |
1 (50%) |
| performance |
1 |
1 (100%) |
0 (0%) |
| security |
2 |
1 (50%) |
1 (50%) |
| functional |
1 |
0 (0%) |
0 (0%) |
| stray |
1 |
0 (0%) |
0 (0%) |
6.3. Recall по сложности
| Difficulty |
Эталон |
QA Assist |
Claude «в лоб» |
| easy |
11 |
8 (73%) |
4 (36%) |
| medium |
2 |
2 (100%) |
2 (100%) |
| hard |
1 |
1 (100%) |
1 (100%) |
6.4. Recall по происхождению
| Origin |
Эталон |
QA Assist |
Claude «в лоб» |
| requirements |
10 |
9 (90%) |
7 (70%) |
| general_expertise |
4 |
2 (50%) |
0 (0%) |
- 7. Что показал бенчмарк 7.1. Главное — инструменты, а не модель Под капотом у обоих прогонов один и тот же Claude Opus. Разрыв в 29 п.п. recall — это не разница в «уме модели», а разница в инструментарии вокруг неё: у QA Assist есть автогенерация pytest-тестов по acceptance criteria, Playwright + DOM-инспекция, оптимизаторы требований и сценариев. У Claude «в лоб» — только curl, DevTools через MCP и интуиция. Это значит, что Claude «в лоб» довольно легко подтянуть: дайте ему те же инструменты, и цифры выровняются. Модель одна и та же. Главное преимущество QA Assist — не в победе по recall на одном прогоне, а в том, что после прогона остаётся:
- переиспользуемые артефакты. Requirements → scenarios → tests, traceability matrix, discrepancies — следующая итерация по этому проекту стартует не с пустого чата, а из готовой структуры.
- уровни контроля. Оркестратор контролирует форматы и полноту артефактов на каждом шаге.
- накапливаемые оптимизации. Агенты постоянно допиливаются — новые проверки, чек-листы, оптимизаторы, форматы отчётов. Управлять всеми этими нюансами через один системный промт «в лоб» практически невозможно: правки начинают мешать друг другу, а сам промт быстро превращается в простыню, которую страшно трогать. У пайплайна со скиллами каждый шаг изолирован, и правки в одном не ломают другие.
- тонкая настройка под проект. Чек-листы, шаблоны декомпозиции, форматы отчётов — всё конфигурируется отдельно от модели и продолжает работать при её апгрейде.
- масштабирование. В агента закладываются хорошие практики с прицелом на рост: подключить новый проект — дело часов, а не недель, всё нужное (шаблоны, оптимизаторы, оркестрация) уже есть.
- автоматизированный регресс. Сгенерированные pytest- и Playwright-тесты остаются в репозитории и перезапускаются без расхода токенов — в CI, на каждом PR, при каждом релизе. Claude «в лоб» каждый раз начинает с нуля и платит токенами за повторение той же работы.
Claude «в лоб» решает одну задачу здесь и сейчас — найти баги. QA Assist строит инфраструктуру вокруг этой задачи: изолированные скиллы, оркестрацию, переиспользуемые артефакты, заложенный путь к масштабированию.
7.2. Бенчмарк уже помогает, но требует допиливания Базовая задача, ради которой я его и собирал, — сравнивать ассистент «вчера» и «сегодня» — закрыта. Я могу сказать «эта правка дала +X п.п. recall в категории Y» вместо «вроде стало лучше»: между двумя моими прогонами видны конкретные эффекты от конкретных правок. В этом плане всё работает как и хотелось. Что нужно допилить:
- Дополнить эталон: часть «FP» — реальные баги, которые просто не попали в фиксированный список. Ассистент нашёл несоответствия контракту (placeholder'ы, charset, nullable, размеры кнопки), которых нет в bugs_us1.yaml. По правилам бенчмарка это FP, по содержанию — кандидаты в новые BUG'и.
- Гонять прогон 5×. Одна точка — это одна точка. Чтобы отличить настоящее улучшение от случайного шума, нужно мерить разброс.
- Трекинг расхода токенов. Recall ↑ — здорово, но если новая версия стоит втрое больше, это тоже надо знать.
- Подумать над размером выборки багов. Хочется больше — точнее метрика. Но больше багов = более громоздкий проект = дороже один прогон. Надо искать середину.
7.3. Пора прикручивать исследовательское тестирование Самое чёткое разделение в результатах — по происхождению бага (см. таблицу 6.4):
- requirements — 90%: всё, что описано в acceptance criteria, агент берёт почти полностью;
- general_expertise — 50%: то, что без спеки заметил бы опытный инженер.
Все слепые зоны (functional, stray, недозакрытый security) — это про общеинженерную интуицию: stack trace в 500-х, console.log в проде, Enter без вызова validate() перед fetch. Их нельзя поймать ни pytest'ом по AC, ни DOM-инспекцией — только осознанным «потыкать руками с гипотезами в голове». То есть исследовательским тестированием. И, похоже, это следующий большой шаг для пайплайна: добавить отдельный скилл с чек-листом «что инженер обычно проверяет, когда у него нет спеки». Это не сделает агента «человеком», но даст ему второй угол зрения — кроме requirements-driven. Сейчас этого больше всего не хватает.-Если у вас был похожий опыт с бенчмарками AI-агентов, вы автоматизируете тестирование сторонними инструментами, разрабатываете свои или только собираетесь, или есть вопросы и замечания по выложенным артефактам — заходите в Telegram-группу: обсуждаем идеи, делимся проблемами и успехами.-Ссылки:
-Источник
|