«Кажется, стало лучше. Или хуже. Или так же. Не знаю» — эта фраза стала последней каплей. После неё я сел писать бенчмарк.
Привет! Это снова Михаил Федоров. В первой статье — архитектура 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 багов. По категориям:
|
Расшифровка категории |
Код категории |
Пример |
|---|---|---|
|
Безопасность |
|
XSS, SQL injection, утечка stack trace |
|
Валидация |
|
не проверяется длина поля, не подрезаются пробелы |
|
Функциональность |
|
кнопка не реагирует, фильтр возвращает не то |
|
Соответствие API-контракту |
|
неверный HTTP-код, неверный формат поля |
|
UI/UX |
|
опечатки, не адаптивная вёрстка |
|
Доступность |
|
нет лейблов у полей, отключён focus-outline |
|
Производительность |
|
долгий ответ ручки, выборка без пагинации |
|
Целостность данных |
|
данные пишутся в БД в разных форматах |
|
Локализация |
|
даты в неверной таймзоне |
|
Забытые артефакты |
|
|
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/blob/benchmark/benchmark/requirements/REQUIREMENTS\_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/
|
Файл |
Что внутри |
|---|---|
|
User Story по шаблону: бизнес-ценность, формулировка, use case, основной сценарий, расширения (альтернативы и ошибки), acceptance criteria, ссылки на технические задачи |
|
|
Frontend-таска: разметка формы, клиентская валидация, обработка кодов ответа (200/201/400/429), сетевые ошибки, страница успеха |
|
|
Backend-таска: контракт API, схема валидации, нормализация телефона, rate-limit, формат |
|
|
Отчёт оптимизатора требований: какие пункты дублировались между US и TASK, какие смерджились/удалены с алиасами |
Каждое требование получает уникальный ID. Это нужно потом, чтобы каждый тест-кейс ссылался на конкретный пункт спецификации, и можно было собрать матрицу покрытия.
Контроль дублей на уровне требований. REQUIREMENTS_REDUNDANCY_REPORT.md — недавнее нововведение. Проблема выросла из дублирования требований на различных уровнях пирамиды: одно и то же поведение описывалось и в US, и в TASK, и генерация сценариев плодила по два-три TC на одну суть. Сейчас после причёсывания требований по шаблонам за декомпозицию по пирамиде и дедупликацию отвечает отдельный агент — test-requirements-optimizer.
5.2. Тестовые сценарии
Папка: testing/scenarios/JTPZ-40/
|
Файл |
Что внутри |
|---|---|
|
UI тест-кейсы (isolated): валидация формы, состояния кнопки, обработка ответов сервера, focus, label, мобильная вёрстка |
|
|
API тест-кейсы: happy path, валидация полей, формат телефона, нормализация, rate-limit, SQL-инъекции (TC-JTPZ-40-BE-001..030) |
|
|
E2E сценарии: полный happy path, обработка серверной валидации, обработка |
|
|
Requirements traceability matrix: какой TC закрывает какое требование, итоговый процент покрытия |
|
|
Отчёт оптимизатора по тест-кейсам (cross-level дубли, e2e step overlap, excessive granularity) |
|
|
Расхождения между требованиями и реальностью, найденные на этапе генерации сценариев (7 штук) |
|
|
Дополнительные API-расхождения, всплывшие при отладке тестов (9 штук) |
|
|
Дополнительные UI-расхождения, всплывшие при отладке тестов (8 штук) |
|
|
|
Списки недостающих тестовых данных (общий + per track) |
5.3. Автоматизация
Папка: testing/auto/JTPZ-40/
|
Файл |
Что внутри |
|---|---|
|
Сгенерированные API-тесты (pytest) |
|
|
Сгенерированные UI-тесты (Playwright + pytest) |
|
|
Сводный отчёт по сгенерированным тестам |
|
|
Лог отладочного цикла |
Всё пишется в клонированные автотест-репозитории (_repo_api/, repoui/) — агент работает в их структуре, а не в своей, чтобы потом одним коммитом улететь в MR.
Что получилось на JTPZ-40:
|
Трек |
Тестов |
PASSED |
xFailed |
Найдено дефектов |
|---|---|---|---|---|
|
API |
33 |
6 |
27 |
9 ( |
|
UI (Playwright) |
28 |
18 |
10 |
8 ( |
Каждый xfail в коде помечен ссылкой на Jira-тикет с багом. Логика простая: тесты не должны быть «зелёными» из-за того, что мы знаем про баг, — они должны быть xfail с явной причиной. Когда баг чинят, тест становится зелёным сам.
6. Результаты бенчмарка: QA Assist vs Claude Code «в лоб»
Скоринг считается по простому правилу: для каждой находки ставится одна из трёх меток — TP (совпадает с эталоном), FP (выдумки или баги, не включённые в эталон), Miss (эталонный баг не найден). Дальше из этого считается recall = TP / (TP + Miss) — доля найденных эталонных багов, и FP-rate = FP / (TP + FP) — доля ложных срабатываний среди всех заведённых тикетов.
Оба прогона — по одному и тому же проекту, одному и тому же набору из 14 эталонных багов (US-1).
Найденные баги зафиксированы:
-
QA Assist — в Jira (
JTPZ-49..JTPZ-65) и в файлахERRORS_DISCREPANCIES_API.md+ERRORS_DISCREPANCIES_UI.md; -
Claude Code «в лоб» — в локальном файле.
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-группу: обсуждаем идеи, делимся проблемами и успехами.
Ссылки:
-
Бенчмарк-проект CallMeBack: github.com/spoon03/qa-benchmark-callmeback
-
Артефакты прогонов + SCORE: github.com/spoon03/jtpz-artifacts
-
Живой стенд: http://45.151.31.218:5000/
-
Telegram-группа: t.me/+SGrnBfcLxuYwNzVi
ссылка на оригинал статьи https://habr.com/ru/articles/1036136/