У нас внутри периметра работают открытые модели на ИИ-песочнице: свои видеокарты, свои сервисы, данные наружу не уходят. Регулярно появляется что-то новое, и надо решить, ставить это в контур или нет.
Первое, что приходит в голову: открыть публичный лидерборд и посмотреть, у кого цифра выше. Мы так и попробовали. Не сработало, и в этой статье я расскажу почему, а заодно что мы намерили за полгода собственных прогонов.
Почему чужие цифры не подошли
Причин набралось четыре, и все они выяснились не сразу.
Наших моделей там почти нет. Публичные списки состоят в основном из закрытых облачных моделей. Открытых, тех самых, что реально развёрнуты у нас, либо нет, либо они другой версии. Часть сильных открытых моделей этого года на нужном нам бенчмарке вообще не мерялась: производители публикуют результаты на других наборах, и сравнивать их между собой нельзя.
Одинаковое название не значит одинаковая модель. У нас был показательный случай. Развёрнутая модель для кода дала результат, который совпал не с той версией, что мы ожидали, а с вдвое меньшей. Название при этом было одно и то же. Что именно нам раздают, мы узнали только из замера.
Настройки инференса у всех свои. Квантизация, режим «размышления», размер контекста. Ниже будет табличка, ради которой, собственно, всё и затевалось: одна и та же модель на разных настройках расходится на восемь пунктов. Публичное число получено на чужих настройках, и вы никогда не узнаете, на каких именно.
Формат ответа отличается. Публичные результаты в основном получены в режиме, где модель возвращает правку куском кода. Мы гоняем режим, где она отдаёт файл целиком. Для модели это разные задачи, цифры между ними не переносятся.
Вывод: публичный лидерборд полезен как ориентир масштаба, чтобы понять, где вообще проходит планка. Как основание для решения «ставим эту модель людям» он не годится.
Как измеряем
Бенчмарк открытый, aider-polyglot. Устроен просто: 225 задач на шести языках (C++, Go, Java, JavaScript, Python, Rust). Модель получает условие и готовые тесты, пишет решение, тесты запускаются. Упало, модель видит текст ошибки и правит. Две попытки.
Один полный прогон занимает от полутора до восемнадцати часов, в зависимости от того, насколько модель разговорчива.
Смотрим не на одну цифру, а на семь.
Сколько решено в итоге и сколько с первой попытки. Разрыв между ними это способность модели чиниться по обратной связи. Ориентируемся в основном на итоговую, потому что живая работа выглядит так же: никто не берёт первый ответ и не несёт в прод.
Секунд на задачу и производное от него «сколько успешных решений в час». Для потоковых сценариев вторая цифра важнее первой, и об этом ниже.
Разбивка по языкам. Две модели могут дать одинаковый средний процент и провалиться в совершенно разных местах.
Доля корректно оформленных ответов. Модель может решить задачу верно, но выдать результат в виде, который инструмент не разберёт.
Длина ответов. Отлично объясняет, почему одна модель проигрывает другой. Иногда она просто не разворачивает решение.
Как часто модель переспрашивает вместо того, чтобы решать. У наших это от 65 до 79 процентов задач. То есть в двух случаях из трёх модель начинает с «давайте сначала уточним требования». На итоговый процент не влияет никак, на расход токенов и время очень даже.
Стабильность прогона. Падения, зависания, автоперезапуски. Метрика не модели, а инфраструктуры, но без неё непонятно, чему верить в остальных цифрах.
Теперь к находкам.
Находка первая: один прогон ничего не значит
Начинали мы, как все, с одиночных запусков. Прогнали, записали цифру, пошли дальше.
Потом стали прогонять каждую модель по три раза и усреднять. И увидели, что от запуска к запуску одна и та же модель гуляет на пару пунктов. Сама по себе, без единого изменения.
Это означало, что часть наших предыдущих сравнений вида «эта модель на полтора пункта лучше» была не сравнением, а угадыванием.
Сейчас у нас первые две строчки различаются на полпункта, и в отчёте так и написано: паритет. Никто никого не лучше, выбираем по другим критериям.
Правило: три прогона минимум, разница меньше двух пунктов не считается разницей.
Находка вторая: настройки важнее модели
Вот та самая табличка. Одна модель, один бенчмарк, меняли только настройки запуска.
Настройки |
Решено |
Секунд на задачу |
базовые |
71,6% |
119 |
ускоренная генерация |
73,2% |
93 |
профиль поставщика |
75,0% |
111 |
максимальное «размышление» |
79,6% |
266 |
Восемь пунктов разброса внутри одной модели (например, базовые настройки: 71,6%, максимальное «размышление»: 79,6%). Это больше, чем расстояние между разными моделями в верхней части нашего списка.
Отдельная история была, когда мы прогнали одну модель на двух площадках и получили расхождение в те же восемь пунктов. Искали причину долго. Оказалось, на одной площадке был включён режим «размышления», а на другой нет, и управляли этим не мы.
Правило: в отчёт по каждому прогону идёт полный список настроек. Скучно ровно до того момента, когда через месяц открываешь собственную таблицу и не понимаешь, откуда взялась цифра.
Находка третья: ни размер, ни название ничего не обещают
Три сюжета про одно и то же.
Маленькая догоняет большую. Модель на 27 миллиардов параметров дала практически столько же, сколько модель на 284 миллиарда: 79,1 против 79,6 процента. То есть в пределах шума. Только большая тратит на задачу вдвое больше времени.
Раньше у нас был похожий случай с моделями поменьше, и мы тогда полдня искали ошибку в замере, прежде чем поверить результату.
Модель «для кода» проиграла универсальным. Специализированная coding-модель дала 28,9 процента там, где обычные дают от 64 до 79. Причина видна по длине ответов: она отвечает в пять-восемь раз короче остальных. Её учили дописывать функции, а не вести многоходовой диалог с тестами.
Но она в разы быстрее: 17 секунд на задачу против трёхсот. Мы её оставили, только для другого. Для подсказок прямо в редакторе и «объясни, что делает этот код». Не для задач, где надо править файлы.
Дистиллят сильной модели оказался слабым. Была модель на 14 миллиардов, обученная подражать одной очень сильной, у которой на этом бенчмарке под 90 процентов. У дистиллята вышло 14,8. На Python и Go он не решил вообще ничего.
Прогон остановили на четверти задач, дальше считать было незачем.
Правило: не отсеиваем модели по описанию и не берём по описанию тоже. Гоняем всё, что появилось.
Находка четвёртая: средний процент скрывает главное
Есть задачи, которые не решает вообще никто.
Разбор стековых выражений: провал у всех моделей на всех шести языках. Реактивные структуры данных: провал на четырёх. Логика подсчёта очков в боулинге, казалось бы, школьная задача: провал на пяти.
И отдельно Rust. Он худший язык у каждой модели без исключения, независимо от размера. Заимствования и времена жизни не щадят никого.
Закономерность общая: модели уверенно пишут типовой код и спотыкаются на нестандартной архитектуре. На своих предметных языках, парсерах, машинах состояний. То есть ровно на том, из чего состоит любая живая система, которая старше пары лет.
Правило: смотреть разбивку, а не только среднее. Средняя цифра у двух моделей может совпасть, а провалы будут в разных местах, и для вашей задачи это решающее.
Что в итоге
Универсально лучшей модели у нас нет. Есть распределение по сценариям: одна на максимальное качество, другая на поток задач (она быстрее при почти том же результате), третья на быстрые подсказки в редакторе. Одна уехала в чёрный список.
Но главное не это. Главное вот что: прежде чем сравнивать модели между собой, зафиксируйте настройки. Иначе вы сравниваете конфигурации и не знаете об этом.
Если будете делать похожее у себя, минимальный набор:
Три прогона, не один.
Полный конфиг в каждый отчёт.
Чужие лидерборды для ориентира, не для решений.
Смотреть разбивку по языкам и типам задач, а не только среднее.
Полсотни часов машинного времени, один прерванный эксперимент и несколько разоблачённых гипотез. По-моему, окупилось.
Прогоны, разбор аномалий и вся возня с изолированной инфраструктурой на и ведущим архитекторе программного обеспечения отдела архитектуры @nedlosster и команде отдела ИИ.
ToxaBes
В принципе, все по делу, спасибо вашему архитектору за хороший материал.
Только докину пятую причину почему лидерборды не работают: они построены не на ваших задачах.
Более того, модели часто дообучают под прохождение конкретных бенчмарков (особенно закрытые облачные модели), т. е. ориентироваться на лидерборды можно лишь в первом приближении.