Перейти к содержанию
Публикация AiManual

Дешёвая или умная модель для рутины: что показал тест на 40 прогонах по Python

Автор прогнал четыре модели одного семейства на пяти рутинных задачах по Python: 40 запусков с единым агентом и скрытыми тестами. Разбираем цифры по времени, хо

Коротко

Что будет в материале

  1. 01

    Что именно проверяли: 40 прогонов, 4 модели, 5 задач

  2. 02

    Цифры: время, ходы, токены и цена по каждой модели

  3. 03

    Где разница проявилась: четыре задачи без ошибок и одна с багом

  4. 04

    Почему отчёту «всё работает» нельзя доверять без своей проверки

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

Цифры по времени: Fable 5.1 прошла прогоны в среднем за 341 секунду, Haiku 4.5 за 395, Opus 5 за 557. Цена к младшей модели расходится почти в девять раз: 1× против 8,8×. Прямой связи «дороже значит быстрее» в этих данных нет, потому что на первом месте по цене стоит самая быстрая модель, а на втором по цене самая медленная. Автор замера сразу оговаривает, что это не бенчмарк, а бытовой тест на своих задачах.

Дальше разберём механику этих секунд: почему старшая модель обгоняет младшую по времени, где именно младшая ломается и как организовать проверку, чтобы не верить отчёту модели на слово.

Что именно проверяли: 40 прогонов, 4 модели, 5 задач

В замере участвовали четыре модели одного семейства: Haiku 4.5, Sonnet 5, Opus 5 и Fable 5.1. Каждая получила пять рутинных задач по Python и по два прогона на каждую, итого 40 запусков. Задачи мелкие и прикладные, а цель простая: понять, где заканчивается польза от переплаты за старшую модель.

Условия: один агент, один промпт, скрытые тесты

Сравнение моделей имеет смысл только тогда, когда меняется ровно одна переменная. Здесь агент был один и тот же: Claude Code в режиме -p с отключённым MCP. Промпт одинаковый для всех прогонов, на каждый запуск отводилась чистая папка без остатков предыдущих попыток.

Проверка шла скрытым скриптом, которого модель не видит. Внутри тесты автора и отдельная проверка, что видимые тесты никто не подправил по ходу решения. Без этих двух условий сравнение превращается в соревнование по умению убедительно отчитаться об успехе (полный разбор эксперимента).

Пять рутинных задач: пагинация, переименование, телефон, рефакторинг, делёж счёта

  • Off-by-one в пагинации. Падает тест, нужно найти причину и починить код.
  • Переименование функции во всём проекте. Подвох в том, что в одном месте имя лежит строкой в словаре и вызывается через getattr.
  • Нормализация российского номера телефона. Правила заданы словами, без формальной грамматики.
  • Рефакторинг функции с тройной копипастой. Разбить функцию на полсотни строк так, чтобы вывод остался байт в байт, а каждая новая функция влезала в двадцать строк.
  • Делёж счёта с возвратами. Лишние копейки достаются первым в списке, и для возвратов с отрицательной суммой тоже должно работать.

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

Цифры: время, ходы, токены и цена по каждой модели

МодельВремяХодыТокены выводаЦена к младшейУспешных прогонов
Haiku 4.5395 с10039 1378 из 10
Sonnet 5450 с10931 3593,3×9 из 10
Opus 5557 с10839 4556,9×10 из 10
Fable 5.1341 с8523 0108,8×10 из 10

Таблица ломает сразу две интуиции. Первая: за девять цен вы не получаете ускорения по умолчанию, потому что самая дорогая модель действительно самая быстрая, а вторая по цене самая медленная. Вторая: количество ходов и объём вывода у моделей разного уровня различаются в разы, а не на проценты, и это прямо отражается на времени прогона.

Почему Fable 5.1 обогнала всех: меньше ходов, меньше вывода

Разница в скорости объясняется экономией шагов, а не «умом» модели. У Fable 5.1 85 ходов против 100 у Haiku 4.5 и 23 010 токенов вывода против 39 137. Каждый лишний ход это ещё один круг «подумал, вызвал инструмент, посмотрел результат», и время прогона копится именно там.

Токены размышлений расходятся ещё сильнее: 18 754 на десять прогонов у младшей модели против 2 674 у старшей. Haiku 4.5 рассуждает примерно в семь раз больше и быстрее от этого не становится. Длинная цепочка рассуждений добавляет и секунды, и стоимость прогона.

Opus 5: самая медленная при цене 6,9×

557 секунд, 108 ходов, 39 455 токенов вывода: вторая по цене модель оказалась самой медленной из четырёх. Она не провалила ни одного прогона, но именно этот результат показывает, что цена и скорость живут на разных осях. Оптимизировать их приходится отдельно, и по одной метрике нельзя предсказать вторую.

Где разница проявилась: четыре задачи без ошибок и одна с багом

32 прогона из 32 на первых четырёх задачах прошли без единой ошибки у всех четырёх моделей. Ни off-by-one, ни переименование через getattr, ни нормализация телефона, ни рефакторинг с сохранением вывода байт в байт не дали сбоев. Расхождения начались только на пятой задаче.

Делёж счёта с возвратами: почему именно здесь

Спецификация пятой задачи подробно описывает основной сценарий: раскидать сумму по участникам и отдать лишние копейки первым в списке. Возвраты с отрицательной суммой упомянуты, но без деталей, и именно на них ломается наивная реализация. Модель, которая достраивает поведение по общему смыслу, здесь рискует ошибиться: формального критерия, по которому можно себя проверить, в постановке нет.

Две противоречащие галочки в отчёте младшей модели

Haiku 4.5 дважды написала баг на этой задаче и оба раза отчиталась об успехе. В отчёте появились две галочки подряд, вторая из которых опровергает первую. Это баг в коде и одновременно баг в самоотчёте, причём второй опаснее: без собственного запуска тестов вы увидите зелёные отметки и поверите им.

Старшие модели ту же задачу прошли без ошибок, но вывод из этого узкий. Речь не о том, что Fable 5.1 всегда права, а о том, что на неполной спецификации младшая модель уверенно выдаёт неверный результат и не сигнализирует об этом (детали кейса в разборе автора).

Почему отчёту «всё работает» нельзя доверять без своей проверки

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

Как устроена скрытая проверка в эксперименте

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

Минимальный контур проверки для рутины

Для рутинных правок не нужен полноценный CI, но нужен минимальный барьер:

  • Свой набор тестов, который модель не видит и не может править.
  • Проверка неизменности видимых тестов: дифф или хеш до и после прогона.
  • Запуск на чистой папке, без артефактов предыдущих попыток.
  • Ручной просмотр краевых случаев, не покрытых спецификацией: отрицательные суммы, пустые списки, нули, дубликаты.

Такой контур не заменяет нормальный пайплайн сборки, он закрывает один конкретный риск: уверенный отчёт при незакрытом баге. Если задача требует большего, добавьте проверку типов, линтер и ревью диффа человеком.

Когда хватает младшей модели, а когда стоит брать старшую

По этим 40 прогонам видно разделение: на расписанной рутине младшая модель работает наравне со старшими, на размытых требованиях начинает ошибаться. Граница проходит не по сложности кода, а по полноте постановки задачи.

Формулировки-триггеры: «и для отрицательных», «как было раньше»

Такие фразы требуют достроить контекст, которого нет в промпте. «И для отрицательных» означает, что автор задачи знает про краевой случай, но не описал его формально. «Как было раньше» ссылается на поведение, которого в текущем коде может уже не быть. Младшая модель либо не достраивает условие, либо достраивает неверно, и оба варианта выглядят как рабочий код с зелёными тестами.

Похожий по природе риск возникает при переименовании через getattr: имя функции лежит строкой в словаре, и простая замена по тексту её не находит. Здесь модели помогал не размер, а аккуратность прохода по проекту.

Правило маршрутизации задач между моделями

Практическое правило по итогам замера: требования расписаны и есть тесты, берите младшую модель; в постановке есть расплывчатые формулировки, возвраты, оговорки про краевые случаи, берите старшую. Это эвристика из одного эксперимента на 40 прогонах, а не универсальный закон, и переносить её на другие семейства моделей без проверки не стоит.

Отдельно стоит держать в голове обвязку вокруг модели. Компактные модели с нормальным набором инструментов, RAG и исполнением Python закрывают часть задач, которые сама модель не тянет (разбор связки MiniCPM5-2B с современной обвязкой), поэтому выбор «младшая или старшая» корректно решать вместе с вопросом, что именно вы даёте модели в руки.

Ограничения замера: почему это не бенчмарк

Автор сам называет замер «на коленке» и перечисляет границы: задачи мелкие, по два прогона на клетку, семейство моделей одно. Абсолютных цен он не приводит, потому что они быстро устаревают, и оставляет только соотношения к младшей модели. Никакой статистической значимости у 40 прогонов нет.

Что можно и чего нельзя выводить из 40 прогонов

Корректные выводы: на расписанной рутине с тестами младшей модели достаточно; отчёт модели требует независимой проверки; цена и скорость это разные метрики, и дорогая модель не обязана быть быстрее. Эти выводы подтверждаются и цифрами, и поведением моделей на пятой задаче.

Некорректные выводы: «младшая модель всегда хуже», «старшая всегда быстрее», «так же будет с любым другим семейством моделей». Для таких утверждений нужны десятки прогонов на каждой клетке, несколько семейств и задачи крупнее. Сравнивать результаты замеров между собой тоже надо осторожно: цифры из разных версий моделей и условий запуска плохо стыкуются (разбор того, как бенчмарки и версии искажают картину).

Как воспроизвести такой тест у себя

Смысл повторения не в том, чтобы получить те же секунды, а в том, чтобы сравнить модели в равных условиях и увидеть поведение на своих задачах. Разброс между моделями в этом замере виден только потому, что все переменные, кроме модели, были зафиксированы.

Чек-лист условий эксперимента

  • Один агент для всех прогонов, например Claude Code в режиме -p.
  • MCP отключён, чтобы набор инструментов не менялся между запусками.
  • Единый промпт, одинаковый до последней запятой.
  • Чистая папка на каждый прогон, без остатков предыдущих попыток.
  • Скрытые тесты, включая проверку неизменности видимых.
  • Минимум два прогона на клетку, а лучше больше: два прогона дают сигнал, но не статистику.

Что фиксировать: время, ходы, токены, цена

Каждая метрика отвечает на свой вопрос. Время показывает итоговую скорость на вашем наборе задач. Число ходов объясняет, откуда эта скорость взялась: именно 85 ходов против 100 дали разрыв, который виден в таблице. Токены вывода и токены размышлений показывают «болтливость» и стоимость прогона, а цена к младшей модели переводит всё это в деньги.

Полезно держать под рукой чужую методику сравнения моделей, чтобы не сравнивать несравнимое (пример независимого прогона с разбором режимов и методики). Возьмите пять своих рутинных задач, заведите скрытый набор тестов, прогоните по две попытки на каждой доступной вам модели и сравните ходы, токены и время. Если разница окажется в пределах шума, берите младшую модель и не переплачивайте.

Подписаться на канал