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

Почему общий бенчмарк часто мешает
Общий бенчмарк удобен, потому что дает одну цифру. Но продукт не живет по одной цифре. У него есть лимит по времени ответа, правила хранения данных, потолок по цене и требования к формату. Таблица лидеров обычно это прячет.
Представьте чат для банка. Модель с верхней строчки отвечает чуть точнее, но под реальной нагрузкой делает это за 4-6 секунд. Если оператор или клиент ждет не дольше 2 секунд, такая победа ничего не стоит. Пользователь видит паузу, а команда получает жалобы.
То же самое с резидентностью. Высокий балл не говорит, где лежат логи, временные файлы и бэкапы. Для российской компании это часто не деталь, а жесткий фильтр. Модель может нравиться команде, но ИБ или юристы снимут ее с рассмотрения еще до пилота.
Длинный контекст тоже легко переоценить. На графике это выглядит как запас: можно отправлять больше документов и реже резать текст. На счете картина другая. Если запросы длинные, цена растет быстро, и задержка часто растет вместе с ней.
Есть и еще одна ловушка - схема ответа. Модель может писать гладкий текст и при этом ломать JSON: пропускать поля, менять типы, путать enum. Для чата это неприятно. Для пайплайна с парсингом, роутингом или автодействиями это уже сбой.
Поэтому модель лучше выбирать не по общему рейтингу, а по ограничениям. Сначала отсеките все, что не проходит ваши рамки по задержке, резидентности, бюджету и формату. И только потом сравнивайте качество внутри этого узкого набора.
Какие ограничения собрать до выбора
До тестов нужен короткий набор цифр и правил. Без него сравнение моделей быстро сводится к общему бенчмарку, а он почти всегда уводит в сторону.
Сначала зафиксируйте не "лучшую" модель, а то, что вашей системе нельзя нарушать. Обычно хватает пяти параметров.
- Лимит по задержке. Запишите p95 для одного ответа, а не среднее время. Среднее выглядит красиво, но пользователи замечают длинные хвосты. Если оператор чата должен получить ответ за 2 секунды, ставьте именно этот предел.
- Резидентность данных. Отдельно отметьте, где могут жить запросы, логи и бэкапы. Эти три пункта часто путают. Запрос может идти через одну страну, а резервные копии лежать в другой.
- Потолок цены. Нужен лимит и на один запрос, и на месяц. Иначе модель проходит тест по качеству, а потом бюджет уходит за неделю из-за длинных промптов и повторных вызовов.
- Размер контекста. Считайте не минимально нужный объем, а объем с запасом. Если сейчас в диалог помещается 24 тысячи токенов, разумно искать вариант хотя бы на 32 тысячи, чтобы не упереться в потолок после пары новых функций.
- Схема ответа. Решите заранее, нужен ли свободный текст или строгий JSON по схеме. Для классификации, маршрутизации заявок, KYC-проверок и любых интеграций схема часто важнее того, насколько "красиво" модель пишет.
Часто самый жесткий фильтр - не качество текста, а сочетание двух ограничений. Например, команде нужен ответ до 1,5 секунды, хранение логов в РФ и строгий JSON без сломанных полей. После этого половина популярных моделей отпадает сама, и длинный список кандидатов резко сужается.
Если вы идете через шлюз вроде RU LLM, эти рамки все равно нужно задать заранее. Единый OpenAI-совместимый эндпоинт упрощает переключение между моделями, но не решает за команду, что важнее: p95, цена, контекст или хранение логов и бэкапов внутри РФ.
Хороший признак простой: любой человек в команде может открыть документ и за минуту ответить на пять вопросов. Сколько секунд можно ждать? Где могут храниться данные? Какой лимит по деньгам? Какой нужен контекст? Нужна ли строгая схема ответа? Если на один вопрос нет точного ответа, выбирать модель рано.
Как собрать матрицу по шагам
Начните с обычной таблицы. В строках разместите модели, в столбцах - ограничения, которые реально влияют на запуск: задержка, цена за вход и выход, длина контекста, резидентность данных, поддержка JSON Schema или function calling, качество на ваших задачах.
Дальше разделите столбцы на две группы. Первая - жесткие фильтры. Если модель не проходит хотя бы один такой пункт, ее не нужно тащить в финальное сравнение. Вторая - желательные свойства. Там уже можно считать баллы и смотреть на компромиссы.
Жесткие фильтры обычно связаны с риском для продукта. Для банка это может быть резидентность данных в РФ и хранение логов внутри страны. Для чат-бота с формами - строгая схема ответа. Для поиска по длинным документам - нужный контекст. Если модель не проходит такой порог, высокий балл в бенчмарке не спасает.
Желательным свойствам дайте вес не по привычке, а по влиянию на сервис. Если пользователи ждут ответ не дольше 2 секунд, задержка весит больше, чем разница в стиле текста. Если бюджет ограничен, цена за 1 млн токенов может весить больше, чем прирост качества на редких сценариях.
Рабочий порядок простой:
- соберите длинный список моделей;
- отсеките все, кто не проходит жесткие фильтры;
- оставьте 5-7 кандидатов на один цикл;
- прогоните одинаковый набор задач и посчитайте итоговый балл.
Не сравнивайте двадцать моделей сразу. Команда потратит больше времени на шум, чем на решение. Один короткий цикл на 5-7 кандидатов почти всегда дает более чистый результат.
Простой пример: для банковского чата можно сразу убрать модели без резидентности в РФ и без надежной схемы ответа. Уже после этого сравнивать цену, задержку и качество. Если команда тестирует варианты через RU LLM, она может гонять разные модели через один OpenAI-совместимый эндпоинт, не меняя SDK и основной код. Это удобно: матрица показывает разницу между кандидатами, а не разницу между интеграциями.
Как мерить задержку честно
Задержку меряют не с ноутбука разработчика, а из той сети, где живет сам сервис. Если продакшен работает в российском ЦОДе, тест из домашнего Wi-Fi даст красивую, но бесполезную цифру. Если приложение ходит в api.rullm.com из Москвы, замеряйте оттуда же или хотя бы из похожего региона и канала.
Среднее время ответа почти всегда прячет проблему. Смотрите p50 и p95: p50 показывает обычный день, p95 - неприятные хвосты, которые ломают чат в пиковые часы. Для саппорта, банковского чата или внутреннего ассистента p95 часто важнее среднего, потому что пользователь запоминает именно долгие ответы.
Не смешивайте два разных показателя в одну цифру. Время до первого токена отвечает за ощущение "модель начала думать", а время до полного ответа - за реальную длительность операции. Модель может быстро выдать первый токен, но тянуть длинный ответ еще 8 секунд. Для чата это терпимо, для синхронной проверки заявки уже хуже.
Хороший замер больше похож на маленький стресс-тест, чем на один удачный запрос. Нужны серия однотипных запросов, ретраи в сценарии, если они есть в вашем коде, отдельный прогон под пиковой нагрузкой и набор из коротких и длинных промптов.
Длина промпта меняет картину сильнее, чем многие ждут. На 300 токенах две модели могут идти почти одинаково, а на 20 000 токенов разрыв станет двукратным. Поэтому стоит мерить хотя бы три сценария: короткий запрос, типичный рабочий и длинный с большим контекстом.
Если после такого теста одна модель проигрывает по p95, но выигрывает в общем бенчмарке, для продакшена лучше взять ту, что ведет себя ровнее. Пользователю нужна не победа в таблице, а предсказуемый ответ за понятное время.
Как считать бюджет без сюрпризов
Цена модели почти никогда не равна цифре из прайса. Считать нужно отдельно входные и выходные токены. У многих моделей вход дешевле, а длинный ответ быстро съедает бюджет. Если команда смотрит только на цену за 1 млн токенов, она почти всегда ошибается.
Начните с реального сценария. Возьмите 1000 диалогов из вашего продукта, а не усредненный запрос из теста. Для каждого диалога посчитайте четыре вещи:
- сколько токенов уходит во вход, включая системный промпт и историю;
- сколько токенов модель обычно возвращает;
- сколько запросов вы повторяете после таймаута, ошибки схемы или срабатывания guardrails;
- есть ли в стеке кэширование промптов и какая часть входа реально читается из кэша.
Потом проверьте дорогие случаи. Часто 90 процентов запросов выглядят дешево, а бюджет ломают оставшиеся 10 процентов: длинная переписка, большой RAG-контекст, повторная генерация после невалидного JSON, второй проход на более сильной модели. Один такой сценарий может стоить как пять обычных.
Простой пример: у вас чат поддержки, средний диалог идет в 6 ходов, история растет, а модель дважды в день на сотню запросов ломает схему ответа. Тогда вы платите не только за успешный ответ, но и за повторный полный прогон с тем же контекстом. Если схема строгая, это нужно закладывать сразу.
Кэширование промптов заметно меняет картину. Если у вас большой системный промпт, правила и шаблон ответа почти не меняются, кэш может снизить цену входа. Но считайте только тот кэш, который ваш стек реально использует, а не тот, что "вроде бы есть" у провайдера.
Финальная метрика проста: цена на 1000 реальных диалогов. Ее удобно сравнивать между моделями и между провайдерами. Если вы работаете через шлюз вроде RU LLM, можно сразу считать по ставкам провайдеров без наценки на API и в рублях. Так бюджет виден до запуска, а не после первого счета.
Как проверить резидентность и хранение данных
Резидентность данных в РФ проверяют не по фразе "данные хранятся в России", а по всей цепочке запроса. Узнайте, через какие страны проходит трафик, где провайдер держит логи и кто видит содержимое промптов и ответов. Если модель хороша на бенчмарке, но уводит журналы или трассировки за пределы РФ, для продакшена это часто сразу стоп.
Отдельно разберите, что происходит после запроса. Многие команды спрашивают только про основное хранилище и забывают про бэкапы, error dumps, APM-трассировки и временные файлы поддержки. Именно там часто остаются куски промптов, номера телефонов, заявки клиентов и внутренние идентификаторы.
Полезно задать провайдеру пять прямых вопросов:
- где проходит сам запрос и где завершается TLS;
- где лежат логи, бэкапы и дампы ошибок;
- что система маскирует до записи в журналы;
- кто из сотрудников имеет доступ к сырым данным;
- как разделены тестовый и боевой контуры.
С маскированием PII лучше не верить общим обещаниям. Попросите показать, какие поля система скрывает до записи лога, а не после. Если пользователь отправил ФИО, телефон и номер договора, журнал не должен хранить их в открытом виде ни в приложении, ни в трассировке, ни в дампе ошибки.
Требования 152-ФЗ зависят от типа данных. Одно дело, если вы обрабатываете обезличенные тексты для внутреннего поиска. Другое - если в запросах есть персональные данные клиентов банка, телеком-абонентов или пациентов. Для второй группы нужны более строгие правила доступа, хранения и аудита.
Тестовый контур тоже часто ломает всю схему. Команда подключает песочницу, гоняет реальные диалоги для отладки и случайно складывает их в общий лог. Так делать не стоит. Тест и прод нужно разделять по данным, доступам и журналам.
Если вы работаете через RU LLM, такую проверку проще формализовать: платформа хранит логи и бэкапы на серверах в РФ, маскирует PII и добавляет аудит-трейлы к каждому запросу. Но и в этом случае стоит письменно сверить состав данных и свой режим обработки.
Когда схема ответа важнее качества текста
Если ответ модели идет не человеку, а в код, качество формулировок быстро уходит на второй план. Красивый текст не спасет, если JSON не парсится, enum сломан, а число пришло строкой. В таких задачах выбор часто упирается в дисциплину структуры, а не в чат-оценки.
Общий бенчмарк часто ставит рядом задачи, где можно простить вольный ответ, и задачи, где ошибка ломает весь сценарий. Поэтому тесты на схему лучше выносить отдельно. Модель может писать убедительно и при этом регулярно терять обязательное поле status или подставлять лишние значения в category.
Хорошая проверка выглядит скучно, и это нормально:
- гоняйте отдельный набор кейсов только на JSON и схемы ответа;
- проверяйте обязательные поля, типы, enum и вложенные объекты;
- сравнивайте два режима: встроенная схема ответа и обычная инструкция в промпте;
- смотрите, что модель делает с пустыми и неизвестными значениями;
- считайте долю ответов, которые проходят строгую валидацию без постобработки.
На практике пустые поля ломают пайплайн чаще, чем редкие фактические ошибки. Одна модель честно вернет null, другая подставит "не указано", третья вообще удалит поле. Для интеграции это три разных исхода, и только первый обычно безопасен.
Разница между встроенной схемой и просьбой "ответь строго в JSON" тоже бывает большой. Если модель умеет нативный structured output, доля валидных ответов обычно выше, а объем костылей ниже. Это особенно заметно в заявках, скоринге, извлечении реквизитов и маршрутизации обращений.
Даже после хороших тестов нужен fallback. Если ответ не проходит схему, система может один раз сделать retry с более жестким промптом, отправить запрос на другую модель или вернуть безопасный статус для ручной проверки. Такой запас лучше заложить сразу, чем потом ловить тихие ошибки в проде.
Пример матрицы для банковского чата
В банковском чате модель часто не общается с клиентом напрямую. Она помогает оператору: читает обращение, вытаскивает факт из внутренних данных и возвращает короткий результат в фиксированной форме. Свободный текст тут почти не нужен. Нужны три поля: status, reason, next_step.
Для такого сценария общий лидер бенчмарка легко проигрывает. Если ответ должен приходить за 2 секунды, а журнал запросов хранится в РФ, часть сильных моделей отпадает сразу. Если к этому добавить лимит по цене на каждое обращение, круг сужается еще сильнее.
| Ограничение | Порог | Кандидат A | Кандидат B |
|---|---|---|---|
| Формат ответа | Строгая схема JSON | Иногда ломает схему | Держит схему стабильно |
| Задержка | До 2 секунд p95 | Выше лимита под нагрузкой | Укладывается |
| Хранение журналов | Только РФ | Не проходит проверку | Проходит |
| Бюджет | Фиксированный лимит на диалог | Слишком дорогой | Вписывается |
| Качество по задаче | Корректный статус и причина | Чуть лучше | Достаточно хорошо |
На бумаге кандидат A может быть первым по общему тесту. Но в работе банка это не спасает. Если модель два раза из десяти ломает JSON, оператор видит ошибку формы. Если она отвечает за 2,7 секунды, очередь растет. Если логирование уходит за пределы РФ, служба комплаенса останавливает запуск.
Кандидат B выглядит скромнее в бенчмарке, зато проходит фильтры и решает задачу без лишнего риска. В этом и смысл матрицы: сначала отсечь все, что ломает процесс, потом сравнивать качество среди оставшихся.
Если команда проверяет такие сценарии через RU LLM, она может гонять несколько моделей через один и тот же API, не меняя SDK и код. Это удобно именно для матрицы: условия теста одинаковые, и разница между кандидатами видна сразу.
Частые ошибки при выборе модели
Самая частая ошибка проста: команда берет победителя из общего рейтинга и считает выбор закрытым. Общий бенчмарк редко совпадает с реальной нагрузкой. Если у вас чат банка, разбор документов, строгая схема ответа и лимит по задержке, лидер таблицы может дать худший результат, чем модель ниже в списке.
Среднее время ответа тоже часто вводит в заблуждение. На дашборде все выглядит прилично, но пользователи сталкиваются не со средним, а с хвостом задержек. Если модель отвечает за 1,8 секунды в среднем, но p95 уходит в 9 секунд, оператору поддержки и клиенту от этого не легче.
С ценой та же история. Команды считают бюджет на коротких промптах из тестового набора, а потом в проде прилетают длинные диалоги, вложенные документы, повторные запросы и ретраи. Так появляется длинный хвост расходов. Модель кажется дешевой в демо и дорогой через две недели работы.
Отдельная ловушка - схема ответа. Текст может выглядеть хорошо, но интеграция ломается на мелочах: JSON не закрыт, обязательное поле пустое, enum пришел в другом значении, сверху добавился лишний ключ. Для пайплайна это не мелочь, а сбой. На таких проверках часто отваливаются даже сильные модели.
Есть и более приземленная ошибка: команда уточняет, где находится сама модель, но не спрашивает, где живут логи, бэкапы и аудит-трейлы. Для российских компаний это прямой риск. Если нужен контур в РФ, проверять надо не только инференс, но и весь след запроса. У RU LLM это прописано явно: логи и бэкапы хранятся в РФ, а маскирование PII встроено в маршрут запроса.
Перед финальным выбором обычно хватает четырех проверок:
- прогнать свой набор задач, а не чужой рейтинг;
- смотреть p95 и p99, а не только среднее;
- валидировать JSON сериями, а не на 3 удачных примерах;
- отдельно проверить хранение логов, бэкапов и метаданных.
Если модель не проходит хотя бы один из этих пунктов, ее место в таблице мало что значит. В проде такие мелочи быстро становятся дорогими.
Быстрая проверка перед запуском
Перед запуском матрица выбора должна превратиться в короткий набор проверок. Если хоть один пункт висит в воздухе, команда почти всегда получает сюрприз уже в проде: ответ стал медленнее, JSON ломается, а счет за трафик вырос сильнее прогноза.
Я бы не выпускал систему без пяти простых подтверждений.
- Лимит по задержке записан в числах. Не "быстро", а, например, p95 до 2,5 секунды для короткого запроса и до 6 секунд для длинного.
- Список допустимых зон хранения данных утвержден заранее. Если у компании только РФ, это должно быть зафиксировано не в переписке, а в требованиях.
- Цена посчитана на реальном трафике. Нужны средняя длина запроса, длина ответа, доля длинных диалогов и запас на пики.
- Модель прошла тесты на длинный контекст и валидный JSON. Один удачный прогон ничего не значит. Нужна серия проверок на ваших сценариях.
- Есть запасной кандидат. Если основная модель замедлится, подорожает или упрется в лимиты провайдера, переключение не должно требовать переделки приложения.
На практике чаще всего проваливают два места. Первое - считают цену по демо-набору, где запросы короткие и аккуратные. Второе - проверяют JSON на десяти примерах, а на тысячном запросе получают лишний текст, пропущенное поле или неверный тип.
Если вы работаете через единый OpenAI-совместимый шлюз вроде RU LLM, запасной кандидат проще держать под рукой: можно менять маршрут к другой модели или провайдеру без переписывания SDK и клиентского кода. Это не отменяет тестов, но сильно снижает риск в день запуска.
Хороший финальный признак простой: любой участник команды может открыть документ и за минуту понять, какая модель идет в прод, при каких лимитах и что включится при росте нагрузки.
Что делать дальше
Соберите рабочую матрицу не на двадцати моделях, а на 3-5 реальных кандидатах. Этого хватает, чтобы убрать шум и увидеть разницу на своих задачах, а не на чужом бенчмарке. Для каждой модели прогоните один и тот же набор сценариев: короткий вопрос, длинный диалог, запрос с большим контекстом, строгий JSON-ответ и один сложный кейс с вашими данными.
В таблице хватит нескольких колонок:
- p50 и p95 по задержке;
- цена за типовой сценарий, а не только за 1M токенов;
- фактический лимит контекста, который вы реально используете;
- правила по хранению логов, бэкапов и резидентности данных;
- проходит ли модель ваш формат ответа без ручных костылей.
Рядом с цифрами запишите причину выбора простыми словами. Например: "прошла JSON без ошибок", "слишком дорогая на длинном контексте", "не подходит по хранению данных". Это кажется мелочью, но именно такие заметки спасают команду от споров через месяц, когда все уже помнят результат по-разному.
Потом назначьте момент для пересмотра матрицы. Цены меняются, лимиты у провайдеров тоже, а требования по данным часто ужесточаются после первого пилота. На практике удобно пересчитывать матрицу после смены тарифа, нового релиза модели, роста нагрузки или новых требований от безопасности и юристов.
Так выбор модели перестает быть спором на уровне вкуса. Он становится обычным инженерным решением с понятными причинами.
Если команде нужен один OpenAI-совместимый эндпоинт и хранение логов и бэкапов внутри РФ, ту же проверку можно провести через RU LLM. В таком случае достаточно поменять base_url на api.rullm.com, оставить прежние SDK, код и промпты и сравнивать несколько моделей в одной схеме, не собирая тестовый контур заново.
Часто задаваемые вопросы
Почему не стоит брать модель с первого места в общем бенчмарке?
Потому что общий рейтинг сжимает все в одну цифру и прячет ваши рамки. Модель может писать чуть точнее, но не уложиться в p95, выйти за бюджет, сломать JSON или не пройти проверку по хранению логов.
Какие ограничения нужно зафиксировать до тестов?
Обычно хватает пяти пунктов: p95 по задержке, допустимые зоны хранения запросов, логов и бэкапов, лимит цены на запрос и на месяц, нужный размер контекста с запасом и формат ответа. Если хотя бы один пункт не записан в числах и правилах, сравнение быстро уйдет в спор о вкусе.
Почему для чата важнее p95, а не среднее время ответа?
Среднее время ответа сглаживает длинные хвосты. Пользователь запоминает не удачные быстрые ответы, а те случаи, где сервис зависает на несколько секунд.
Как посчитать бюджет без сюрпризов?
Считайте не прайс из таблицы, а цену на реальных диалогах. Возьмите историю запросов, посмотрите входные и выходные токены, добавьте ретраи, ошибки схемы, длинные контексты и только потом сравнивайте модели по стоимости на 1000 диалогов.
Когда схема ответа важнее качества текста?
Если ответ идет в код, красивый текст не поможет. Достаточно одного пропущенного поля или неверного типа, чтобы пайплайн упал или отправил заявку не туда.
Что входит в проверку резидентности данных?
Проверьте всю цепочку, а не только место инференса. Нужно отдельно спросить, где проходит трафик, где лежат логи, бэкапы и дампы ошибок, что маскируется до записи и кто видит сырые данные.
Сколько моделей имеет смысл тестировать за один раз?
Лучше брать 5–7 кандидатов за один цикл. Этого хватает, чтобы увидеть разницу на одинаковых сценариях и не утонуть в шуме.
Какой запас по контексту стоит закладывать?
Берите не минимум, а запас. Если сейчас вам хватает 24 тысяч токенов, разумно смотреть на 32 тысячи и выше, чтобы новая функция или длинный диалог не уперлись в лимит.
Нужен ли запасной кандидат перед запуском?
Да, это снижает риск в день запуска. Если основная модель станет медленнее, подорожает или упрется в лимиты провайдера, вы сможете переключиться без срочной переделки приложения.
Чем помогает единый API-шлюз при выборе модели?
Он убирает лишнюю работу на уровне интеграции. Через RU LLM можно прогонять несколько моделей через один OpenAI-совместимый эндпоинт, не менять SDK и сравнивать именно поведение моделей, а не разницу между разными API.