Три прогона подряд Claude Opus 5.5 проваливала одно и то же ревью. Тот же PR, та же роль ревьюера, тот же результат: «failed to parse». Ревью засчитывалось как ошибка, и Opus оказывалась внизу моей таблицы.
Когда я наконец достал исходный ответ, оказалось, что Opus сделала ровно то, о чём её попросили. В двух коротких абзацах она объяснила, что нашла, а затем вернула корректный JSON в блоке кода. Сломала всё одна фраза из пояснения: «в проде единственный вызывающий код передаёт только { db }».
Наш парсер искал в ответе первую { и последнюю } и пытался разобрать всё между ними. Первая открывающая скобка была в { db }, прямо в тексте. Вырезанный фрагмент начинался с середины предложения, JSON.parse выбрасывал исключение, а мы выбрасывали правильное ревью.
Это была первая из трёх находок бенчмарка, которые вообще ничего не говорят о том, какая модель умнее.
Зачем я взялся за бенчмарк
Moonshot выпустила Kimi K3.1 Pro. Судя по независимым тестам, модель стоило попробовать. В индексе Vals AI она заняла первое место среди моделей с открытыми весами (62,5%) и третье на Terminal-Bench 4.0. На экзамене Plotly по анализу данных набрала 42 из 43. В рейтинге веб-разработки Arena поднялась с 17-го места на 8-е. По прайсу миллион входных и выходных токенов стоил соответственно $2 и $10. У Kimi K3, которую мы использовали на старшем тарифе, это $3 и $15.
Но тесты расходились даже между собой. На неделе релиза в обзорах писали, что у модели 55 баллов и четвёртое место в Artificial Analysis. Через несколько дней на странице самой модели было 46 баллов и 22-е место. В одном практическом тесте по программированию она оказалась шестой из одиннадцати, и автор назвал её «болтливой». А как она делает ревью наших PR?
В YAGNI пул-реквесты ревьюит агент Proctor. У нас уже был эвал: пять смерженных PR из нашего репозитория. Для каждого мы заранее описали, что хороший ревьюер должен заметить и каких замечаний делать нельзя. Каждое ревью проходит весь рабочий цикл: глубокий разбор, проверку по отдельным ролям и финальную доработку. Модель-судья сверяет оставшиеся замечания с эталоном. Итоговый балл считаем так:
composite = 100 · (0.7 · recall + 0.3 · precision) − 10 · forbidden_hits
Сначала я по одному разу прогнал K3 и K3.1 Pro. Pro набрала 65,2 балла против 60,2. На одно ревью ей понадобилось 35 секунд вместо 92 и около $0,13 вместо $0,23. Стоимость я посчитал по токенам и прайсу, без скидок за кэш. «Болтливости» здесь тоже не видно: на пяти ревью K3.1 Pro выдала 7,4 тыс. токенов ответа, а K3 — 16,6 тыс.
Один прогон на пяти PR мало о чём говорит. Я расширил тест, и тут началось самое интересное.
Второй баг: Claude вообще не вызывалась
Я добавил Opus 5.5 и Sonnet 5.5. Перед полным прогоном завёл журнал расходов: каждый вызов модели добавляет строку с её именем, количеством токенов и стоимостью по прайсу. Эвал запускается отдельно от сервера, в продовые метрики эти расходы не попадают. Мне хотелось видеть, сколько уже потрачено, пока идёт прогон, и получать предупреждение, когда сумма проходит заданный порог.
В первом пробном прогоне Sonnet в журнале оказалось 11 вызовов. Ни одного к Sonnet:
$0.01 9 calls accounts/fireworks/models/deepseek-v4p1-flash-1017
$0.01 1 calls accounts/fireworks/models/glm-5p3
$0.00 1 calls accounts/fireworks/models/kimi-k3
Наш роутер отправляет запросы в Anthropic, только когда модель явно закреплена за рабочим пространством. Мы специально так сделали. Эвал запросил Claude на уровне отдельного вызова. Роутер по правилам проигнорировал это пожелание, записал предупреждение, которое во время эвала никто не читает, и взял модели по умолчанию. В результате эвал выставлял баллы GLM, DeepSeek и Kimi под именем «Sonnet 5.5».
Если бы я не смотрел расходы в разбивке по моделям, то опубликовал бы под именем Claude чужой результат.
Роутер я оставил как есть. Теперь эвал создаёт тестовое рабочее пространство и закрепляет за ним проверяемую модель. На ревью фикса мне предложили добавить проверку, и сейчас я считаю её важнейшей частью решения: если ответила другая модель, этап падает с ошибкой eval pin not honored. Такой ответ до судьи уже не дойдёт.
Третий баг: Sonnet вызывала инструменты, которых у неё не было
Когда роутинг заработал, Sonnet всё равно потеряла 2 ревью из 15 из-за ошибок парсинга, причём на разных ролях. Я стал сохранять ответы, которые не удавалось разобрать. Вот что увидел в двух сбоях при повторном прогоне:
<invoke name="finish_review">
<parameter name="note">The material I was given had no analyzer entries at or
above ccn 10, so there was nothing to review. ...</parameter>
</invoke>
Обе роли проверки сложности писались для агента, который может вызывать инструменты в цикле. В инструкциях так и сказано: «read_file the FULL method» и «your finish_review note should list each…». Но в эвале эти роли выполняются за один проход без инструментов. В проде при переходе на один проход происходит то же самое. Модели с открытыми весами пропускали упоминания инструментов и возвращали JSON. Sonnet следовала инструкциям буквально и записывала вызов инструмента текстом.
В промпт для одного прохода я добавил абзац: инструментов здесь нет, верни JSON. Правка касается только ролей, в инструкциях которых упоминаются инструменты цикла. Промпты остальных ролей совпадают со старыми побайтно, так что результаты по другим моделям можно сравнивать с предыдущими. В первом раунде Sonnet ещё раз упала на другой роли. Исходного ответа я тогда не сохранил. После фикса сбой не повторился, но его причину я так и не доказал.
Фиксу для Opus тоже понадобилось ревью. На моём PR его делал сам Proctor. В первой версии я пытался разобрать блок кода и только потом искать JSON по скобкам. Proctor заметил дыру: если модель показывает в блоке пример, а ниже даёт ответ, мы примем пример за ответ. Раньше код хотя бы выдавал ошибку. В итоге парсер пробует по порядку весь ответ, фрагмент между крайними скобками, такой же фрагмент текста с удалёнными блоками кода и только потом последний блок кода.
До этих двух фиксов у Opus падали 3 ревью из 15, у Sonnet — 2 из 15. После фиксов у обеих стало 0 из 15. В том раунде Sonnet поднялась со второго места на первое. Сами ревью почти не изменились. Просто мы перестали их терять.
Что показали судьи
Все эти прогоны оценивала Kimi K3. Здесь сразу два возможных конфликта: K3 сама участвует в тесте и приходится родственницей K3.1 Pro, которая тогда лидировала. Первые четыре модели разделяли всего три балла. Даже небольшое предпочтение судьи могло поменять порядок.
Я собрал судей из трёх семейств: Kimi K3, GLM 5.3 и Sonnet 5.5. Каждое ревью оценивают все судьи, кроме самой модели-автора, затем берём среднее. Оценки каждого судьи отдельно сохраняются в CSV: если один из них систематически ставит кому-то больше, это будет видно.
Такого эффекта я не увидел. По каждой модели судьи разошлись максимум на два балла. K3.1 Pro получила 50,4 от всех троих.
- Qwen 3.8 Max — итог 55.4 (разброс между прогонами, SD ±6.3), точность / полнота 0.13 / 0.76, F1 0.20, ~$0.07–0.11 за ревью.
- GLM 5.3 — итог 54.1 (разброс между прогонами, SD ±4.6), точность / полнота 0.11 / 0.73, F1 0.18, $0.09 за ревью.
- Claude Sonnet 5.5 — итог 54.1 (разброс между прогонами, SD ±4.2), точность / полнота 0.27 / 0.68, F1 0.33, $0.20 за ревью.
- Claude Opus 5.5 — итог 52.1 (разброс между прогонами, SD ±1.5), точность / полнота 0.15 / 0.69, F1 0.22, $0.41 за ревью.
- Kimi K3.1 Pro — итог 50.4 (разброс между прогонами, SD ±2.2), точность / полнота 0.23 / 0.62, F1 0.22, $0.12 за ревью.
- DeepSeek V4.1 Flash — итог 49.3 (разброс между прогонами, SD ±3.0), точность / полнота 0.14 / 0.64, F1 0.21, $0.02 за ревью.
- Kimi K3 — итог 43.4 (разброс между прогонами, SD ±4.8), точность / полнота 0.28 / 0.51, F1 0.32, $0.17 за ревью.
Пять PR, по три прогона на модель, оценки от панели из трёх судей. Стоимость взята из раунда с одним судьёй: только этапы ревью, по числу токенов и ценам из прайса, без скидок за кэш. В списке нет MiniMax M3: уже в первом прогоне 36 этапов упёрлись в наш лимит в 16 тыс. токенов ответа, каждое ревью закончилось ошибкой, и я остановил прогон.
Судьи не определили победителя. Зато стало видно, откуда берётся разброс. Между раундом с одним судьёй и раундом с тремя K3.1 Pro сдвинулась с 54,6 до 50,4, а GLM 5.3 — с 50,1 до 54,1. Судьи согласны между собой. Меняются сами ревью: одна и та же модель получает тот же PR и во второй раз пишет другое ревью.
Какие выводы я готов сделать
По итогам обоих раундов, то есть шести прогонов на модель:
- Kimi K3 оказалась слабейшей из работающих моделей оба раза: 49,9 и 43,4. Она стоит у нас на старшем тарифе, так что за этот результат я возьмусь первым.
- K3.1 Pro справляется как минимум на уровне K3, а одно ревью на этих PR обходится примерно на треть дешевле.
- DeepSeek V4.1 Flash держится рядом с основной группой, обходится примерно в пятую часть цены K3.1 Pro и работает быстрее всех. Её стоит попробовать для специализированных ролей с большим числом вызовов.
- Sonnet 5.5 оба раза попала в тройку лидеров: у неё лучший F1 среди моделей с высокой полнотой и самые быстрые ревью среди сильных моделей.
- Opus 5.5 обошлась дороже всех и дала больше всего шума (точность 0,15). Я ещё не подбирал для этого эвала уровень усилий модели, поэтому окончательный вывод об Opus делать рано.
- Результаты от 49 до 55 на пяти PR я считаю ничьей.
Всего я потратил около $51 на вызовы моделей, включая отладочные прогоны.
Открытый вопрос — середина списка. Пяти PR из собственного репозитория мне хватило, чтобы решить судьбу K3. А вот кого поставить вместо неё — Qwen, GLM или Sonnet — пока неясно. Дальше я хочу прогнать AACR-Bench: около 200 PR из публичных репозиториев, проверенных экспертами, и отдельный судья. Наши модели ещё не ревьюили эти PR для нас. Этот тест я пока не запускал.
Из этого раунда я вынес кое-что поважнее впечатлений от Kimi. Прежде чем сравнивать модели на своём пайплайне, проверьте, что он вообще получает их ответы. У двух из восьми моделей ревью терялись из-за нашего парсера и промпта, а до одной из них поначалу даже не доходили запросы.