Самая большая статья экономии в LLM-системах появляется, когда дорогую модель перестают вызывать для простой работы. Разница в цене между маленькой и флагманской моделью одного провайдера достигает 10–50 раз. Кэш и сокращение prompt полезны, но такой порядок дают редко.
Ситуация из реальной команды
Команда сделала триаж тикетов на флагманской модели: «чтобы точно работало». Работает отлично, accuracy 96%. Стоимость: $3800 в месяц. Кто-то предлагает попробовать маленькую модель. Команда сопротивляется: «качество упадёт». Наконец пробуют на golden dataset: маленькая модель даёт 91%.
Дальше начинается инженерия. Анализ ошибок показывает: маленькая модель уверенно ошибается на 2% тикетов и неуверенно: ещё на 7%. Решение: маленькая модель обрабатывает всё; тикеты, где она не уверена, уходят на флагманскую. Итог: 93% трафика: дешёвая модель, 7%: дорогая, суммарная accuracy 95.5%, стоимость $700 в месяц. Качество упало на полпроцента. Стоимость: в пять раз.
Три схемы маршрутизации
1. Каскад (escalation). Дешёвая модель первой, дорогая: при неуверенности или невалидном результате:
async def classify_with_cascade(text: str) -> TicketClassification:
small = await classify(text, model=settings.SMALL_MODEL)
if small is not None and small.confidence >= 0.8:
return small
return await classify(text, model=settings.STRONG_MODEL)Плюс: простота, дорогая модель получает только сложные случаи. Минус: сложные запросы платят дважды (сначала неудачный дешёвый вызов) и получают двойную latency. Работает, когда эскалируется меньше ~20% трафика: иначе каскад дороже честного роутинга.
2. Роутер (upfront routing). Отдельный быстрый шаг решает, куда отправить запрос, до обработки:
- по эвристикам: длина входа, язык, тип клиента, наличие вложений;
- по дешёвому классификатору (в том числе не-LLM: логрег на embeddings трудно превзойти по цене);
- по типу задачи: перефразирование: всегда маленькая, юридический анализ: всегда большая.
Плюс: нет двойной оплаты и двойной latency. Минус: роутер сам может ошибаться, и его ошибки молчаливые: сложный запрос ушёл в слабую модель, и вы узнаете об этом из жалобы.
3. Статическое разделение по шагам. Самая недооценённая схема: в пайплайне из главы 13 у каждого шага своя модель. Классификация и извлечение: маленькая, генерация клиентского текста: большая, проверка формата: маленькая. Никакой динамики, только здравый смысл и evals по шагам.
Начинайте со схемы 3. Она даёт большую часть экономии бесплатно. Схемы 1–2 добавляйте, когда один шаг с большим трафиком остаётся дорогим.
На чём решать «уверена / не уверена»
Поле confidence в ответе модели: самооценка, а не вероятность. Использовать его можно, но только после калибровки на данных:
- Прогоните golden dataset через маленькую модель.
- Постройте таблицу: заявленный confidence → фактическая accuracy.
- Выберите порог, при котором ошибки ниже порога уходят на эскалацию, и посчитайте долю эскалируемого трафика.
Если связи между заявленным confidence и фактической точностью нет (бывает), сигналы надёжнее: невалидный ответ по схеме, ответ «other/не знаю», расхождение двух дешёвых вызовов, длина и язык входа.
Роутинг: это контракт, который надо охранять
Маршрутизация добавляет системе два новых режима отказа:
- дрейф качества: маленькую модель обновил провайдер, accuracy просела, каскад начал эскалировать 40% трафика: стоимость тихо утроилась. Ловится метрикой «доля эскалаций» с alert-ом;
- дрейф трафика: изменился профиль входа (новый клиент, новый язык), и пороги, откалиброванные на старых данных, перестали работать. Ловится регулярным прогоном evals по обеим веткам.
Поэтому правило: у каждой ветки роутинга: своя метрика качества, у самого роутера: метрика распределения трафика, и обе видны на дашборде рядом со стоимостью.
Правило главы
Не спрашивайте «какая модель лучше». Спрашивайте: «Какая самая дешёвая модель достаточна для этого шага на моих данных?» Отвечайте измерением на golden dataset, а не ощущением. Дорогая модель нужна для эскалации, а не как default.
Чеклист главы
- Для каждого шага пайплайна выбрана самая дешёвая достаточная модель, и «достаточная» подтверждена на golden dataset.
- Пороги эскалации откалиброваны на данных, а не выбраны «0.8, вроде норм».
- Доля эскалируемого трафика: метрика с alert-ом.
- Качество каждой ветки измеряется отдельно; смена модели провайдером не пройдёт незамеченной.
- Экономия от роутинга посчитана и сверена с фактом из
llm_call_log. - Имена моделей: в конфигурации; связка «шаг → модель» меняется без деплоя.
Практикум
Задача 45.1: каскад с калибровкой порога. ⭑⭑
Возьмите классификатор тикетов из задачи 1.2 и golden dataset из 60+ размеченных примеров (сгенерируйте и разметьте руками). Измерьте accuracy и стоимость: только маленькая модель, только большая, каскад с порогами 0.6 / 0.7 / 0.8 / 0.9.
Критерии приёмки:
- Есть таблица: конфигурация → accuracy → стоимость на 100 000 тикетов → доля эскалаций.
- Построена калибровочная таблица confidence → фактическая accuracy для маленькой модели.
- Выбран рабочий порог с обоснованием: сколько качества покупается за сколько денег.
- Найден хотя бы один пример, где маленькая модель ошибается с высоким confidence, и сформулировано, чем вы это ловите (или почему принимаете риск).
Подсказки:
- Размечайте dataset до экспериментов, не глядя на ответы моделей, иначе вы разметите «как модель», а не «как правильно».
- Если confidence не коррелирует с точностью, это главный результат эксперимента, а не провал задачи. Перейдите на сигнал «невалидный ответ или категория other».
Задача 45.2: роутинг по шагам в пайплайне. ⭑⭑
Возьмите пайплайн из задачи 13.2 (или 43.1) и назначьте каждому шагу модель по принципу «дешёвая из достаточных»: прогоните каждый шаг на обеих моделях по своему мини-dataset-у.
Критерии приёмки:
- Для каждого шага есть измеренная пара «качество на маленькой / качество на большой» и решение с обоснованием.
- Хотя бы один шаг остался на большой модели: и вы можете объяснить, почему именно он.
- Посчитана суммарная экономия против «всё на большой» и против «всё на маленькой» показано, что теряется.
- Связка «шаг → модель» вынесена в конфиг и логируется в
llm_call_log.
Подсказки:
- Типичный результат: извлечение и классификация переезжают на маленькую безболезненно, генерация человекочитаемого текста: нет. Если у вас иначе: тем интереснее, разберитесь почему.