Нужна ли умная модель для рутины? Дал четырём моделям пять одинаковых задач и сравнил

Есть популярное мнение: для рутинных задач самая умная модель не нужна, дешёвой хватит, а упирается всё теперь в скорость. Недавно на Хабре вышла статья ровно об этом — «Я перестал пользоваться самыми умными ИИ‑моделями», и под ней почти триста комментариев. Я прочитал, наверное, половину: мнений много, а замеров на одинаковых задачах не нашёл ни одного. Стало интересно, сел и проверил сам.

Что мерил

Взял пять задач из тех, что обычно скидываю агенту и иду за кофе. Всё на Python, от одного до пяти файлов:

  1. Off-by-one в пагинации, тест падает, надо починить.
  2. Переименовать функцию во всём проекте. С подвохом: в одном месте имя лежит строкой в словаре и вызывается через getattr.
  3. Нормализация российского номера телефона по описанию словами.
  4. Функция на полсотни строк с тройной копипастой. Надо разбить так, чтобы вывод остался байт в байт, а каждая функция влезала в двадцать строк.
  5. Делёж счёта на n человек, в котором теряются копейки. В требованиях написано: лишние копейки достаются первым в списке, и для возвратов с отрицательной суммой тоже должно работать.

Модели — четыре штуки из одного семейства, от младшей к старшей: Haiku 4.5, Sonnet 5, Opus 5, Fable 5.1. Агент везде один (Claude Code в режиме -p, MCP отключил), промпт один, на каждый прогон чистая папка. Каждую задачу гонял по два раза на каждой модели, итого сорок прогонов. Проверял скрытым скриптом, которого модель не видит: там мои тесты и проверка, что видимые тесты никто не подправил.

Сразу скажу, чем это плохо. Задачи мелкие. Два прогона на клетку — это ни о чём. Семейство одно. Так что это замер на коленке, на бенчмарк не претендую. Задачи и проверки выложу, если кому-то надо.

Что получилось

Сводка по десяти прогонам на каждую модель: сколько решено, сколько ушло времени, сколько ходов сделал агент, сколько токенов вывода и во сколько раз дороже младшей модели.

  • Haiku 4.5 — решено 8 из 10, 395 секунд, 100 ходов, 39 137 токенов вывода, цена 1× (точка отсчёта)
  • Sonnet 5 — 9 из 10, 450 секунд, 109 ходов, 31 359 токенов, 3,3×
  • Opus 5 — 10 из 10, 557 секунд, 108 ходов, 39 455 токенов, 6,9×
  • Fable 5.1 — 10 из 10, 341 секунда, 85 ходов, 23 010 токенов, 8,8×

Цену считал сам клиент по списочному прайсу. Абсолютные цифры не пишу: устареют быстрее, чем вы это дочитаете. Соотношение проживёт дольше.

Теперь что меня удивило.

Самая дорогая модель оказалась самой быстрой. 341 секунда против 395 у самой дешёвой. Почему — видно в той же сводке: ходов меньше, текста почти вдвое меньше. Младшая модель очень много рассуждает, 18 754 токена размышлений на десять прогонов, у старшей 2 674. Токены у неё летят быстрее, только их надо больше, и в сумме выходит дольше. Правда, Opus, вторая сверху, вообще самая медленная из четырёх, так что «дороже значит быстрее» тоже неправда. Я для себя решил смотреть на время задачи целиком. Токены в секунду его не предсказывают.

Дальше. Четыре задачи из пяти решили все модели, оба раза. Пагинация, переименование с подвохом, телефон, рефакторинг: 32 прогона из 32. Если у вас рутина примерно такая, девятикратная разница в цене вам ничего не даёт.

И вся разница вылезла на пятой задаче. Причём споткнулись там на чтении требований, с кодом у всех порядок.

Пятая задача

Первое, что приходит в голову:

base, remainder = divmod(total_cents, n)
result = [base] * n
for i in range(remainder):
result[i] += 1

1000 на троих даёт [334, 333, 333], красота. А вот возврат, −1000: деление в Python округляет вниз, и получается [-333, -333, -334]. Лишняя копейка уехала в конец списка. То есть человек заплатил на копейку больше остальных, а при возврате получит на копейку меньше. В требованиях было «лишние копейки достаются первым», так что мимо.

Haiku написала именно так оба раза. Sonnet один раз из двух. Opus и Fable все четыре раза делили модуль суммы, а знак возвращали потом. И в отчёте сами объяснили зачем: если делить отрицательное число в лоб, лишняя копейка упадёт в конец, а в требованиях наоборот. Fable в одном прогоне ещё и скрипт написала, перебрала все суммы от −300 до 299 при n от 1 до 11. Я её об этом не просил.

Но больше всего мне понравился отчёт младшей модели. Цитирую как есть:

✓ Остаток достаётся первым в списке
✓ Работает для возвратов: split_bill(-100, 3) = [-33, -33, -34]

Две галочки подряд, и вторая строка опровергает первую. Видимый тест зелёный, отчёт бодрый, а баг вылезет на первом же возврате.

Справедливости ради: требование про возвраты можно прочитать по‑разному, и кто‑нибудь в комментариях наверняка скажет, что [-333, -333, -334] тоже нормально. Может, и так. Но старшие модели эту развилку увидели и объяснили, что выбрали. Младшая просто поставила галочку.

Что я теперь делаю

Задачи, где всё расписано и есть тесты, отдаю младшей модели. 32 из 32, и дешевле почти на порядок.

Если в требованиях мелькает «и для отрицательных», «и для пустого», «как было раньше», беру старшую. Код дешёвая модель пишет нормально. Она пропускает сам вопрос.

И отчёту «всё работает» верю ровно настолько, насколько сам вижу проверку. Один скрытый тест на граничный случай дешевле любой модели.

А у вас как? Кто гоняет дешёвые модели на рутине, на чём они у вас сыпятся?

11