На этой неделе на Хабре спорили, нужны ли программисту самые умные модели: «Я перестал пользоваться самыми умными ИИ‑моделями». Автор считает, что для рутины хватает дешёвых, а упирается всё теперь в скорость. Под статьёй почти триста комментариев. Я прочитал, наверное, половину: мнений много, замеров на одинаковых задачах не нашёл ни одного. Стало интересно, сел и проверил на своих.
Что мерил
Взял пять задач из тех, что обычно скидываю агенту и иду за кофе. Всё на Python, от одного до пяти файлов:
-
Off-by-one в пагинации, тест падает, надо починить.
-
Переименовать функцию во всём проекте. С подвохом: в одном месте имя лежит строкой в словаре и вызывается через
getattr. -
Нормализация российского номера телефона по описанию словами.
-
Функция на полсотни строк с тройной копипастой. Надо разбить так, чтобы вывод остался байт в байт, а каждая функция влезала в двадцать строк.
-
Делёж счёта на n человек, в котором теряются копейки. В требованиях написано: лишние копейки достаются первым в списке, и для возвратов с отрицательной суммой тоже должно работать.
Модели — четыре штуки из одного семейства, от младшей к старшей: Haiku 4.5, Sonnet 5, Opus 5, Fable 5.1. Агент везде один (Claude Code в режиме -p, MCP отключил), промпт один, на каждый прогон чистая папка. Каждую задачу гонял по два раза на каждой модели, итого сорок прогонов. Проверял скрытым скриптом, которого модель не видит: там мои тесты и проверка, что видимые тесты никто не подправил.
Сразу скажу, чем это плохо. Задачи мелкие. Два прогона на клетку — это ни о чём. Семейство одно. Так что это замер на коленке, на бенчмарк не претендую. Задачи и проверки выложу, если кому-то надо.
Что получилось
|
Модель |
Решено |
Время на 10 прогонов |
Ходов агента |
Токенов вывода |
Цена к младшей |
|---|---|---|---|---|---|
|
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, и дешевле почти на порядок.
Если в требованиях мелькает «и для отрицательных», «и для пустого», «как было раньше», беру старшую. Код дешёвая модель пишет нормально. Она пропускает сам вопрос.
И отчёту «всё работает» верю ровно настолько, насколько сам вижу проверку. Один скрытый тест на граничный случай дешевле любой модели.
А у вас как? Кто гоняет дешёвые модели на рутине, на чём они у вас сыпятся?
Короткие заметки и замеры между статьями пишу в канале: https://t.me/agent_field_notes
Автор: Corkyz0011


