Comments 9
Не вполне понятна методика. Вопрос, который был задан агенту так и звучал, мол найди все баги, составь список, поясни, почему это баг?
Нет, формулировка была поуже. Вот промпт целиком, как он уходил в слепом режиме (в легком сверху добавляется блок с диффом, остальное слово в слово):
You are reviewing a change in a TypeScript backend monorepo
(Fastify, MikroORM, GraphQL, Vitest).
Here is a file from the codebase (<path>), with line numbers:
<файл с пронумерованными строками>
Report every defect that must be fixed before merge: anything that changes
runtime behaviour incorrectly, breaks a contract (HTTP response shape,
generated OpenAPI document, SQL that is produced, log payload), or
introduces a bug.
Do NOT report style, naming, formatting, typing preferences, missing tests
or refactoring ideas.
If you find nothing wrong, return an empty findings list. An empty list is
a valid and common answer.
Answer with JSON and nothing else, no prose, no markdown fences:
{"findings":[{"line":<номер строки>,"severity":"high|medium|low","what":"<одно предложение>"}]}
Стиль, нейминг и отсутствие тестов запрещены прямым текстом, иначе замер шума превращается в фикцию: на любом продовом файле можно набрать десяток замечаний про нейминг и формально быть правым.
Строчка про пустой список тоже не для красоты. Без нее модель считает, что раз ее позвали, то найти обязана, и двадцать нетронутых файлов дают двадцать находок. С ней codex выдал 10 из 20, qwen 5 из 20.
Ответ строго JSON с номером строки, поэтому основную метрику (попал в строку плюс-минус две) считает скрипт, а не я. Трактовка начинается только во второй, мягкой метрике, и про то, насколько там можно верить судье, в статье отдельный раздел.
Ну и температура ноль, инструменты выключены, работа в пустой директории: ни репозитория, ни тестов агент достать не может.
А есть репозиторий с вашим бенчмарком?
Ну раз просите :)
https://github.com/k41n/ai-review-benchmark
Про 301 секунду — это дефолтные таймауты Node на заголовки и на паузу между чанками, и они дают ровно такую картину: отказы копятся, а выглядит как «27B не тянет большие файлы». Отдельно зацепилась за нестабильность: 36 стабильных попаданий из 51 и 5-7 плавающих — это портрет одного движка. А объединение по разным движкам считали, не по прогонам одного? Если sonnet и qwen ловят непересекающиеся подмножества дыр, две дешевые модели по одному прогону могут дать соотношение сигнал/шум лучше, чем три прогона одной.
Считал только по прогонам одного движка, вы правы, что это разные вопросы. Пошел посчитал по вашей схеме (типа sonnet+qwen), благо сырые ответы все лежат. Слепой режим, по одному прогону на движок:
комбинация дыр из 51 ложных сигнал/шум
qwen один 35 29 1.21
sonnet один 38 44 0.86
qwen + sonnet 38 73 0.52
qwen + haiku 42 82 0.51
haiku + codex 44 113 0.39
sonnet, три прогона 41 140 0.29
TL;DR: объединение двух движков действительно выгоднее трех прогонов одного. Любая пара при сопоставимой полноте дает 0.39-0.52 против 0.29 у sonnet на трех прогонах. Это ожидаемо: у повторного прогона шум почти весь новый, а находки почти все те же самые, так что вы доплачиваете за одно и то же.
Но! ни одна комбинация не бьет одиночный движок. qwen сам по себе дает 1.21, и это остается лучшим числом в таблице. Полнота по этой метрике всегда покупается дороже, чем стоит.
И отдельно про вашу пару, потому что там получилось прикольно. У sonnet и qwen подмножества не непересекающиеся, а вложенные: из 35 дыр, которые нашел qwen, ровно ноль таких, которых не нашел sonnet. Вааще ни одной. Поэтому пара qwen + sonnet дает те же 38 дыр, что и sonnet в одиночку, и ровно ничего, кроме удвоенного шума. Непересекающееся есть в других парах: у haiku с qwen 4 и 7 своих, у haiku с codex 4 и 6, там объединение хотя бы что-то приносит.
Если считать ложные находки без дублей (одна и та же строка, помеченная обоими движками, читается человеком один раз), числа подрастают, но порядок тот же: 0.62 у лучшей пары против 0.44 у трех прогонов sonnet.
Оговорка та же, что и везде: это по одному прогону на движок, а прогон не воспроизводится.
Так а какие именно модели-то использовались?
claude-sonnet-5 и claude-haiku-4-5-20251001, через Claude Code CLI 2.1.258: claude -p --model sonnet / --model haiku, инструменты сняты --disallowedTools, работа в пустой временной директории.
gpt-5.6-sol, через codex-cli 0.152.0: codex exec --json --sandbox read-only.
qwen 27B локально: ollama 0.33.1, тег qwen3.8:27b (digest 22130167c4c2, архитектура qwen35, 27.3B, квантизация Q4_K_M), temperature 0, num_ctx 16384. Модель умеет 262k контекста, но в прогоне стоял именно 16k, и это часть объяснения, почему на больших файлах она проседала.
Судьёй во второй, мягкой метрике был claude-sonnet-5, и те же ответы отдельно прогонялись через gpt-5.6-sol и claude-opus-5, чтобы посмотреть, насколько судьи расходятся между собой. Расхождение есть, про него в статье отдельный раздел.
На самом деле, версии не прибиты гвоздями, я просто посмотрел что сейчас, но через месяц тот же sonnet может молча уехать на 5.1, например.
Интересно! Спасибо!
Я дал четырем ИИ-ревьюерам 60 багов, про которые точно известно, что они баги