Каскад моделей LLM: дешёвая модель сначала, сильная — по эскалации

Как устроить каскад: дешёвая модель отвечает первой, сложные случаи уходят сильной. Код на Python, калибровка порога и расчёт стоимости по формуле.

5 мин · · разработка · экономия

Каскад моделей LLM — приём для потоков однотипных запросов: классификации обращений, извлечения полей из документов, модерации. Большую часть запросов обрабатывает дешёвая модель, а к сильной уходят только те, где ответ не прошёл проверку или модель не уверена. Ниже — как устроить такую схему на Python через один ключ Zukko, как подобрать порог и как посчитать стоимость по формуле, а не на глаз.

Как работает каскад моделей LLM

Схема из трёх частей:

  1. Первая попытка — дешёвая модель. Например, deepseek-v4.1-flash ($0.013 за 1M входа, $0.038 за 1M выхода).
  2. Проверка ответа. Код решает, принять ответ или эскалировать. Сигналы для эскалации:
    • ответ не разбирается как JSON или не соответствует схеме;
    • значение вне допустимого набора (метка, которой нет в списке);
    • нарушено бизнес-правило (сумма позиций не равна итогу, дата в будущем);
    • самооценка уверенности ниже порога.
  3. Вторая попытка — сильная модель. Например, claude-opus-5-5 ($0.4 / $2 за 1M). Если и её ответ не прошёл проверку, запрос уходит на ручной разбор.

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

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

Код на Python

Пример: классификация обращений в поддержку по четырём темам.

bash
import json
from openai import OpenAI

client = OpenAI(base_url="https://api.zukko.pro/v1", api_key="fetch_...")

CHEAP = "deepseek-v4.1-flash"
STRONG = "claude-opus-5-5"
LABELS = {"billing", "bug", "feature_request", "other"}

SYSTEM = (
    "Определи тему обращения клиента. Ответь только JSON без пояснений: "
    '{"label": "billing" | "bug" | "feature_request" | "other", '
    '"confidence": число от 0 до 1}'
)

Что здесь важно:

  • Обе модели вызываются через OpenAI SDK с base URL https://api.zukko.pro/v1; шлюз сам конвертирует запрос к Claude.
  • Сильная модель получает тот же вход, что и дешёвая. Можно передать ей и ответ первой модели, но тогда вход станет больше — учтите это в расчёте.
  • Для Claude в OpenAI-формате весь вход оплачивается по цене входа, кэш не учитывается. Для коротких запросов, как здесь, это неважно. Если у сильной модели длинный общий системный промпт, вызывайте её через Anthropic SDK (Anthropic(base_url="https://api.zukko.pro", ...)): в Anthropic-формате чтение кэша оплачивается по своей, более низкой цене.

Подробнее о клиенте на Python — в документации.

Как подобрать порог

Порог уверенности определяет долю эскалаций и долю ошибок среди принятых ответов дешёвой модели. Подберите его на 200–500 обращениях с известной правильной меткой:

bash
def calibrate(samples: list[tuple[str, str]], thresholds=(0.5, 0.6, 0.7, 0.8, 0.9)):
    answers = [(ask(CHEAP, text), gold) for text, gold in samples]
    for t in thresholds:
        accepted = [(a, gold) for a, gold in answers if is_valid(a) and a["confidence"] >= t]
        r = 1 - len(accepted) / len(answers)
        errors = sum(a["label"] != gold for a, gold in accepted)
        err_rate = errors / len(accepted) if accepted else 0.0
        print(f"порог {t}: эскалаций {r:.0%}, ошибок среди принятых {err_rate:.1%}")

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

Сколько стоит каскад: формула

Обозначения:

  • C₁ — средняя стоимость запроса к дешёвой модели;
  • C₂ — средняя стоимость запроса к сильной модели;
  • r — доля запросов, ушедших на эскалацию (от 0 до 1).

Эскалированный запрос оплачивается дважды: сначала дешёвая попытка, потом сильная. Поэтому:

стоимость каскада на запрос = C₁ + r × C₂ всё на сильной модели = C₂ каскад дешевле, если r < 1 − C₁ / C₂

Пример на условном потоке

100 000 обращений, в каждом в среднем 800 токенов на входе (системный промпт плюс текст) и 150 на выходе.

  • C₁ (deepseek-v4.1-flash) = 800 × $0.013 / 1 000 000 + 150 × $0.038 / 1 000 000 = $0.0000104 + $0.0000057 = $0.0000161
  • C₂ (claude-opus-5-5) = 800 × $0.4 / 1 000 000 + 150 × $2 / 1 000 000 = $0.00032 + $0.0003 = $0.00062

На 100 000 запросов: дешёвая модель — $1.61, сильная — $62.00. Стоимость каскада = $1.61 + r × $62.00:

Доля эскалаций rКаскадВсё на Opus 5.5Разница
10%$1.61 + $6.20 = $7.81$62.00$54.19
30%$1.61 + $18.60 = $20.21$62.00$41.79
50%$1.61 + $31.00 = $32.61$62.00$29.39

Точка безубыточности: r = 1 − 0.0000161 / 0.00062 ≈ 0.974. Пока эскалируется меньше 97.4% запросов, каскад дешевле, чем отправлять всё на Opus 5.5. Значения r в таблице — примеры для подстановки, а не обещание. Свою долю вы получите из калибровки.

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

Три ступени

Между дешёвой и сильной моделью можно поставить среднюю, например claude-sonnet-5. Формула расширяется так:

стоимость на запрос = C₁ + r₁ × C₂ + r₂ × C₃

где r₁ — доля запросов, дошедших до второй ступени, r₂ — до третьей. Третья ступень имеет смысл, только если на калибровке видно, что средняя модель закрывает заметную часть эскалаций.

Что проверить перед запуском

  • Качество принятых ответов. Ответы дешёвой модели, прошедшие порог, никто не перепроверяет. Раз в неделю берите случайную выборку из 50–100 принятых ответов и сверяйте вручную или с сильной моделью.
  • Фактическую стоимость. Сверьте C₁ и C₂ с реальными списаниями в кабинете, раздел «Использование», или через API истории списаний: фактический размер ответов может отличаться от оценки.
  • Ограничения ключа. Для пайплайна удобно завести отдельный ключ с разрешёнными моделями (только две модели каскада) и дневным лимитом в долларах. Создать ключ можно в кабинете.
  • Актуальность моделей. Набор и цены меняются: актуальный список — GET https://api.zukko.pro/v1/models или страница «Модели» в кабинете.

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

Частые вопросы

Чем каскад отличается от маршрутизации?

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

Можно ли доверять полю confidence?

Только после калибровки на размеченных данных. Формальные проверки — схема ответа, допустимые значения, бизнес-правила — надёжнее и должны идти первыми.

Какую дешёвую модель взять?

Из самых недорогих в каталоге — deepseek-v4.1-flash и gemini-3.8-flash. Какая лучше подходит вашей задаче, покажет та же калибровка: сравните долю эскалаций и ошибок у обеих. Цены и расчёты по всем дешёвым моделям — в статье о самых дешёвых моделях для массовых задач.

Сколько я сэкономлю?

Это зависит от доли эскалаций r. Посчитайте по формуле C₁ + r × C₂ со своими C₁, C₂ и r, измеренным на калибровке.

zukko

Платите в 25×
меньше

за Claude Code & ChatGPT

Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.

Каскад моделей LLM: эскалация на сильную модель · Zukko