Зачем маршрутизировать LLM-запросы

Обучающий материал: от проблемы к работающему решению. Каждая глава строится на предыдущей. В конце: сквозной пример и чек-лист, с которым можно начинать строить.

Проблема: одна модель на все запросы

Представь: ты запустил AI-продукт. Чат-бот для customer support, или coding assistant, или аналитический инструмент. У тебя 10,000 запросов в день.

Перед тобой выбор: какую модель использовать?

Вариант A: Все через Opus

Качество отличное на любом запросе. Но ты платишь $25/1M output-токенов за каждый ответ, включая "Какой у вас график работы?" и "Спасибо, все понятно".

Стоимость: ~$12,500/мес

Вариант B: Все через Haiku

Дешево. Но на сложных вопросах ("Сравните три тарифных плана с учетом моей ситуации") ответ поверхностный и пользователь уходит недовольным.

Стоимость: ~$2,500/мес, но качество падает

Это ложная дилемма. На практике ~70% запросов в большинстве продуктов простые: фактические вопросы, повторяющиеся сценарии, короткие уточнения. И только ~30% действительно требуют мощной модели.

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

Без routing (все Opus)
$12,500/мес
С routing (70/30 split)
$4,200/мес
Экономия
66%
при сопоставимом качестве

Как работает routing (30 секунд)

Весь механизм сводится к четырем шагам:

  1. Классифицировать входящий запрос: какая сложность (simple / medium / complex)? какой тип (factual / reasoning / creative / code)?
  2. Маршрутизировать: по конфигу (YAML-файл) определить, какая модель обрабатывает эту комбинацию сложности и типа
  3. Подстраховать: если выбранная модель недоступна (timeout, rate limit, outage), автоматически переключить на fallback
  4. Измерить: логировать каждый запрос: какая модель использована, сколько токенов, стоимость, латентность, качество

Дальше мы разберем каждый шаг. Начнем с экономики: нужно понимать, между чем мы выбираем.

Глава 1: Экономика моделей

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

Ландшафт моделей (начало 2026)

У каждого провайдера есть линейка от дорогих и мощных до дешевых и быстрых. Это не случайность: именно этот спектр делает routing возможным.

TierAnthropicOpenAIGoogleХарактер
Flagship Opus 4.6
$5 / $25
GPT-5.4
$2.50 / $15
Gemini 3.1 Pro
$2 / $12
Complex reasoning, agentic coding, hard prompts. Лучшее качество.
Mid-tier Sonnet 4.6
$3 / $15
GPT-4.1 / GPT-5
$2 / $8
Gemini 3 Flash
$0.50 / $3
Баланс. Основная production-модель для большинства задач.
Budget Haiku 4.5
$1 / $5
GPT-4.1 Nano
$0.05 / $0.20
Gemini 2.5 Flash-Lite
$0.10 / $0.40
Classification, extraction, простые Q&A, высокий volume.

Цены: input / output за 1M токенов.

Обрати внимание на разброс
Разница между самым дешевым (GPT-4.1 Nano: $0.20/1M output) и самым дорогим (Opus 4.6: $25/1M output) составляет 125x. Это не 20-30% экономии, это порядки. Вот почему routing имеет смысл: даже неидеальная классификация дает огромную экономию.

Где разница в качестве критична, а где нет

Это центральный вопрос routing. Не "какая модель лучше?", а "на каких задачах дешевая модель выдает результат, неотличимый от дорогой?"

Нужна мощная модель
  • Мультишаговый reasoning с неоднозначностью
  • Архитектурные решения в коде, большие рефакторинги
  • Синтез информации из нескольких доменов
  • Reasoning по 50K+ токенов контекста
  • Creative writing для публикации
Хватит дешевой
  • Sentiment, intent detection, classification
  • Data extraction (имена, даты, суммы)
  • FAQ и фактические вопросы
  • Конвертация форматов (text → JSON)
  • Суммаризация коротких документов

Данные LMSYS Chatbot Arena (крупнейший crowdsourced бенчмарк, где реальные пользователи вслепую сравнивают ответы двух моделей) подтверждают: на factual Q&A и extraction mid-tier модели набирают Elo-рейтинг, статистически неотличимый от flagship. Разрыв проявляется на hard prompts, coding и reasoning.

Как считать стоимость запроса

LLM API тарифицируют по токенам. Формула простая:

Cost = (input_tokens x input_price / 1M) + (output_tokens x output_price / 1M)

Но есть нюанс: output-токены в 3-5x дороже input. Причина техническая: генерация output требует последовательных вычислений, а input обрабатывается параллельно.

Типичные размеры запросов

Тип запросаInputOutputHaiku 4.5Sonnet 4.6Opus 4.6
Classification / extraction30050$0.00055$0.0017$0.0028
Customer support ответ2,5001,200$0.0085$0.026$0.043
Complex reasoning5,0002,000$0.015$0.045$0.075
Code generation (функция)1,000800$0.005$0.015$0.025
RAG с контекстом15,0001,000$0.02$0.06$0.1
Пример: масштаб имеет значение

10,000 запросов/день, средний запрос = customer support:

Экономия routing vs all-Opus: $7,245/мес (56%). И это консервативный split. С оптимизированной классификацией можно довести до 70%+.

Prompt caching и batch API: дополнительная экономия

Помимо routing, есть два механизма снижения стоимости, которые стакаются с ним:

Prompt caching

Если ваш system prompt или контекст повторяется между запросами (а он почти всегда повторяется), провайдер может кэшировать его и брать за повторное чтение в 10x меньше.

ПровайдерСкидка на cache hitНаценка на writeНастройка
Anthropic90%25% (5-мин) или 100% (1-час)Явная: cache_control в API
OpenAI75-90% (зависит от модели)НетАвтоматическая
Google90%Storage: $1-4.50/1M токенов/часЯвная

Batch API

Если запросы не нужно обрабатывать real-time (eval, аналитика, bulk processing), batch API дает 50% скидку у всех трех провайдеров. Комбинация batch + caching может дать до 95% экономии на input-токенах.

Выводы главы 1

Глава 2: Как классифицировать запросы

Routing работает, только если мы можем понять, какой запрос перед нами: простой или сложный, фактический или творческий. Это задача классификации.

Есть три подхода, от простого к сложному. Каждый следующий точнее, но дороже и медленнее. Смысл в том, чтобы выбрать подход, соответствующий стадии продукта.

Подход 1: Rule-based (правила)

Самый простой: набор if/else правил на основе наблюдаемых свойств запроса.

def classify(prompt: str) -> str:
    tokens = prompt.split()

    # Длина как прокси сложности
    if len(tokens) < 15:
        complexity = "simple"
    elif len(tokens) < 80:
        complexity = "medium"
    else:
        complexity = "complex"

    # Ключевые слова для категории
    code_signals = ["code", "function", "debug", "error", "```"]
    if any(s in prompt.lower() for s in code_signals):
        category = "code"
    elif any(s in prompt.lower() for s in ["explain", "compare", "analyze", "why"]):
        category = "reasoning"
    else:
        category = "factual"

    return complexity, category
Плюсы
  • Latency: <1ms
  • Cost: $0
  • Прозрачность: видно почему именно это решение
  • Нет зависимостей
Минусы
  • Accuracy: 60-75%
  • Хрупкость: "What's 2+2?" = simple, но "What's the integral of e^(x^2)?" тоже выглядит коротким
  • Не генерализует на новые формулировки

Когда хватит: MVP, первая неделя разработки, узкий домен с предсказуемыми запросами, или как первый слой в гибридном подходе.

Подход 2: Embedding-based (по похожести)

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

Как это работает

  1. Готовишь примеры: 20-50 запросов на категорию с правильными метками. "Какой курс доллара?" → simple/factual. "Проанализируй динамику за 3 года" → complex/reasoning.
  2. Эмбеддишь: каждый пример превращается в числовой вектор через sentence-transformer модель (например, all-MiniLM-L6-v2: бесплатная, работает локально).
  3. При запросе: входящий промпт эмбеддится, считается cosine similarity со всеми примерами, запрос назначается категории ближайших (kNN).

Готовая реализация: Semantic Router (MIT, open-source). Снижает latency классификации с ~5000ms (LLM) до ~100ms.

Плюсы
  • Accuracy: 75-90%
  • Latency: 50-200ms
  • Cost: ~$0.0001 (локально) или ~$0.0002 (через API)
  • Детерминистично: один запрос → всегда один ответ
Минусы
  • Cold start: нужны labeled примеры
  • Плохо с запросами, непохожими ни на один пример
  • Нужно обновлять примеры по мере изменения паттернов

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

Подход 3: LLM-as-classifier

Используем саму LLM (дешевую и быструю) для классификации запроса. По сути, задаем LLM вопрос: "какой это тип запроса?"

Zero-shot (без примеров)

System: Classify the user query.
Complexity: simple | medium | complex
Category: factual | reasoning | creative | code
Return only JSON: {"complexity": "...", "category": "..."}

User: {query}

Промпт короткий, latency минимальная (200-500ms на Haiku). Хорошо работает, когда категории интуитивно понятные. Accuracy: 70-85%.

Few-shot (с примерами)

Добавляем 3-10 примеров на категорию прямо в промпт. Accuracy растет до 80-92%, но промпт становится длиннее, а значит каждая классификация дороже.

Экономический парадокс
Каждый classification call стоит денег и добавляет latency. При 100K запросов/день стоимость классификации Haiku ($0.001/call) = $100/день = $3,000/мес. Это оправдано только если downstream-экономия больше. Считай ROI классификации как отдельную строку.

Как выбрать подход: decision framework

Чек-лист выбора стратегии классификации

Начни с вопроса: что у тебя уже есть?

Гибридный подход (часто лучший): rule-based как первый фильтр для очевидных случаев, embedding-based для остального. LLM-classifier только для запросов с низким confidence.

Выводы главы 2

Глава 3: Routing-паттерны

Классификация определила, что запрос: medium/reasoning. Теперь нужно решить, какой модели его отправить. Это решение определяется routing-паттерном.

Базовый routing: конфиг-маппинг

Простейший вариант: YAML-файл, который маппит комбинации сложности и типа на конкретные модели.

routing:
  simple:
    factual: haiku-4.5
    reasoning: haiku-4.5
    creative: sonnet-4.6
    code: haiku-4.5

  medium:
    factual: sonnet-4.6
    reasoning: sonnet-4.6
    creative: sonnet-4.6
    code: sonnet-4.6

  complex:
    factual: sonnet-4.6
    reasoning: opus-4.6
    creative: opus-4.6
    code: opus-4.6

Это работает и покрывает 80% потребностей. PM может менять конфиг без деплоя. Но есть паттерны, которые дают больше.

Cascade routing: попробуй дешевую, эскалируй если нужно

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

Как это выглядит
  1. Запрос уходит на Haiku. Haiku отвечает.
  2. Система оценивает ответ: confidence score, полнота, есть ли "не знаю".
  3. Если score > threshold → возвращаем ответ Haiku. Стоимость: $0.001.
  4. Если score < threshold → отправляем тот же запрос на Opus. Стоимость: $0.001 + $0.05.

Как оценивать "достаточно хорош"

Trade-off каскада
На эскалированных запросах ты платишь дважды (cheap + expensive + overhead оценки). Каскад выгоден, когда >60% запросов разрешаются дешевой моделью. Если эскалация происходит в 50%+ случаев, обычный routing дешевле.

ETH Zurich paper (2024) доказывает: комбинация routing + cascading в единый фреймворк теоретически оптимальна по сравнению с каждой стратегией по отдельности.

Confidence-based routing: страховка от ошибок классификатора

Улучшение базового routing: классификатор выдает не только метку, но и confidence score. Routing учитывает оба:

Это простое улучшение, которое значительно снижает under-routing (сложные запросы на дешевую модель). Имплементируется за час поверх базового routing.

RouteLLM и другие решения

RouteLLM (open-source, LMSYS)

Фреймворк от команды Chatbot Arena. GitHub, paper.

Отличие от нашего подхода: RouteLLM обучен на 80K+ реальных human preference comparisons из Arena. Не классифицирует запрос, а напрямую предсказывает, какой модели пользователь предпочтет ответ.

Лучший результат: Matrix Factorization роутер достигает 95% качества GPT-4, отправляя на GPT-4 только 14% запросов. Остальные 86% идут на дешевую модель. Это 85% снижение cost на MT-Bench.

Ограничение: роутит между ровно двумя моделями (strong vs weak). Для multi-model routing (3+ модели) нужна кастомизация.

Коммерческие решения

РешениеПодходОсобенность
MartianMechanistic interpretability: "маппит" трансформеры в программные представленияПредсказывает лучшую модель без inference. Claims: 98% cost savings.
Unify.aiNeural network router + dynamic benchmarks (обновляются каждые 10 мин)Единый API + custom router training на своих данных.
Not DiamondModel router + prompt adaptationПереписывает промпт под target-модель. Powered OpenRouter Auto.

Как выбрать паттерн: decision framework

Чек-лист выбора routing-паттерна

Рекомендация для учебного проекта: начни с конфиг-маппинга, добавь confidence-based routing, сравни с RouteLLM. Каскад имплементируй последним как V2.

Выводы главы 3

Глава 4: Надежность

Routing добавляет зависимость от нескольких провайдеров. Каждый из них может упасть, затормозить, или вернуть ошибку. Если не подстраховаться, routing принесет больше проблем, чем решит.

Три слоя защиты, от мелкого к крупному:

Слой 1: Fallback chains

Для каждой модели определяешь, кто подхватывает при отказе:

# routing config
complex:
  primary: claude-opus-4.6
  fallback:
    - gpt-5.4           # same-tier: другой провайдер
    - claude-sonnet-4.6  # downgrade: слабее, но работает
  timeout_ms: 30000

simple:
  primary: claude-haiku-4.5
  fallback:
    - gpt-4.1-nano
  timeout_ms: 5000

Четыре уровня деградации (в порядке приоритета):

  1. Same-tier: Opus → GPT-5.4. Другой провайдер, аналогичное качество.
  2. Downgrade: Opus → Sonnet. Слабее, но ответ будет.
  3. Cached: если был похожий запрос недавно, вернуть кэшированный ответ.
  4. Graceful failure: понятное сообщение пользователю, не stack trace.
Принцип
Пользователь никогда не видит raw API error. Каждый failure обработан.

Слой 2: Circuit breaker

Проблема: если провайдер лёг на 10 минут, fallback chain будет каждый раз ждать timeout primary-модели (30 секунд) прежде чем переключиться. 10,000 запросов x 30 сек ожидания = пользователи уходят.

Circuit breaker решает это. Паттерн из электротехники: когда downstream-сервис нездоров, "выбиваем автомат" и перестаем к нему обращаться.

Три состояния

СостояниеЧто происходитКогда переключается
Closed (норма)Запросы идут к провайдеру. Считаем failures.→ Open, когда 5+ failures за 60 сек
Open (отключен)Все запросы сразу на fallback. Провайдер не трогаем.→ Half-Open через 30 сек
Half-Open (тест)Пропускаем 1 тестовый запрос к провайдеру.→ Closed если OK, → Open если fail
class CircuitBreaker:
    def __init__(self, provider, threshold=5, timeout=30):
        self.provider = provider
        self.state = "closed"
        self.failures = 0
        self.threshold = threshold
        self.timeout = timeout
        self.opened_at = None

    def call(self, prompt):
        if self.state == "open":
            if time.time() - self.opened_at > self.timeout:
                self.state = "half_open"
            else:
                raise CircuitOpen(self.provider)

        try:
            result = self.provider.complete(prompt)
            if self.state == "half_open":
                self.state = "closed"
                self.failures = 0
            return result
        except (Timeout, RateLimit, ServerError) as e:
            self.failures += 1
            self.opened_at = time.time()
            if self.failures >= self.threshold:
                self.state = "open"
            raise
Важно: breaker per provider
Отдельный circuit breaker для каждого провайдера. OpenAI лёг: breaker OpenAI = open, Anthropic = closed, запросы переключаются мгновенно. Различай transient (429, 503: считаются) и permanent (401, 400: не считаются) ошибки.

Готовые библиотеки: PyBreaker, circuitbreaker.

Слой 3: Retry с backoff и timeout management

Порядок действий при ошибке:

  1. Retry с exponential backoff (1s, 2s, 4s). Тот же провайдер, max 2-3 попытки. Только для transient errors.
  2. Fallback на другой провайдер: та же модель через другой endpoint (Anthropic → AWS Bedrock).
  3. Fallback на другую модель: Opus → Sonnet → Haiku.
  4. Circuit breaker: если провайдер стабильно падает, отключаем его на cooldown.

Timeout по классам моделей

КлассTimeoutПочему
Budget (Haiku, Nano)5-10 секЕсли за 10 сек не ответила, что-то не так
Mid-tier (Sonnet, GPT-4.1)15-30 секБолее сложные запросы, длиннее генерация
Flagship (Opus, o3)30-120 секReasoning-модели объективно думают дольше

Streaming + heartbeat: при streaming, если нет новых токенов 5+ секунд, считай ответ "зависшим" и переключайся. Это ловит partial failures, которые обычный timeout пропускает.

# Полная цепочка обработки ошибок
Request -> Primary (timeout T)
  -> Retry x2 с backoff (если transient error)
    -> Same model, другой провайдер (timeout T/2)
      -> Fallback model (timeout T)
        -> Graceful error + cached response if available
Выводы главы 4

Глава 5: Измерение и observability

Routing внедрен, fallback работает. Но без observability ты не знаешь: экономит ли routing? Где классификатор ошибается? Деградирует ли качество?

Без данных невозможно итерировать. А итерация: это то, что отличает "поставил routing" от "routing приносит результат".

Какие метрики трекать и зачем

Не все метрики одинаково важны. Вот приоритеты:

Tier 1: бизнес-метрики (показываешь на review)

МетрикаЧто показываетКак считать
Cost savings vs baselineСколько сэкономилиActual cost vs "все запросы через Sonnet" cost. Процент.
Quality deltaНе деградировало ли качествоLLM-as-judge score (routed) vs score (single-model). Дельта <5% = OK.
Monthly cost trendКуда идемBurn rate: total_cost за 30 дней, тренд.

Tier 2: операционные (смотришь каждый день)

МетрикаЗачемAlert threshold
Error rate per providerЗдоровье провайдеров>2% за 5 мин
Fallback trigger rateРастет = primary деградирует>5% за час
Latency p50 / p95User experiencep95 > 10s
Model distributionDrift от ожидаемого = classifier regressionОтклонение >15% от baseline

Tier 3: аналитические (смотришь раз в неделю)

МетрикаЗачемКак получить
Over-routing rateSimple на дорогую модель = wasted $Eval set с ground truth labels
Under-routing rateComplex на дешевую = quality lossТот же eval set
Classifier confidence distributionPile-up на low confidence = classifier не справляетсяHistogram confidence scores
Cost per quality-adjusted requestРеальная эффективностьcost / quality_score

Как оценивать качество в production

Три подхода (используй все три):

  1. Heuristic checks (100% трафика): ответ не пустой? JSON парсится? Код компилируется? Нет отказа? Дешево, ловит грубые проблемы.
  2. LLM-as-judge (5-10% sample): дешевая модель оценивает ответы по rubric (helpfulness, relevance, accuracy). Score 0-1. Alignment с human judgment: до 85%.
  3. User feedback: thumbs up/down. Implicit: retry = плохо, copy = хорошо. Самые ценные данные, но мало и biased.

Готовые инструменты

Прежде чем строить свое, стоит знать, что уже существует:

LangSmithLangfuseHelicone
ЧтоObservability от LangChainOpen-source LLM platformLLM proxy с логированием
ЛицензияProprietaryMITOpen source
Self-hostingEnterprise onlyFull parity, бесплатноDocker, одна команда
Как работаетSDK instrumentationSDK / OpenTelemetryProxy: меняешь base URL
LiteLLMЧерез wrapperNative интеграцияNative (proxy)
Quality evalBest: judges, rubrics, annotation queuesLLM-as-judge, RagasMinimal
Free tier5K traces/мес50K units/мес10K req/мес
Best forLangChain stack, нужна полная платформаSelf-hosted, API-firstZero-code, быстрый старт
Что выбрать

Своя observability: что логировать

SQLite-схема, адаптированная для multi-model router:

CREATE TABLE requests (
    id TEXT PRIMARY KEY,
    timestamp_utc TEXT NOT NULL,

    -- Что пришло
    prompt TEXT NOT NULL,
    prompt_tokens INTEGER,

    -- Как классифицировали
    complexity TEXT,                -- simple/medium/complex
    category TEXT,                  -- factual/reasoning/creative/code
    classifier_strategy TEXT,       -- rules/embeddings/llm_classifier
    classifier_confidence REAL,     -- 0.0-1.0

    -- Куда отправили
    target_model TEXT NOT NULL,
    fallback_used BOOLEAN DEFAULT 0,
    fallback_model TEXT,

    -- Что получили
    response TEXT,
    output_tokens INTEGER,
    status TEXT DEFAULT 'success',  -- success/error/timeout/fallback
    error_type TEXT,

    -- Перформанс
    classification_latency_ms INTEGER,
    llm_latency_ms INTEGER,
    total_latency_ms INTEGER,

    -- Деньги
    input_cost REAL,
    output_cost REAL,
    total_cost REAL,

    -- Качество (заполняется асинхронно)
    quality_score REAL,
    user_feedback INTEGER           -- -1/0/1
);
Архитектура
Python tracker (writes) → SQLite (WAL mode) → FastAPI (reads) → React + Recharts (dashboard)

Tracker пишет в SQLite на каждом запросе (sync, <1ms). FastAPI отдает JSON для дашборда. Для тяжелых агрегаций: materialized таблица daily_stats (обновляется cron-ом раз в час).

SQLite с WAL mode нормально работает до ~10M строк. Для учебного проекта: более чем достаточно.

Ключевые views дашборда

  1. KPI cards (top): total requests, total cost, cost savings %, avg latency, error rate
  2. Cost breakdown by model (stacked bar, daily): видишь, куда уходят деньги
  3. Model distribution (pie/donut): % запросов на каждую модель. Drift = проблема.
  4. Latency p50/p95 (line, per model): деградация видна сразу
  5. Routing efficiency (comparison): actual cost vs single-model baseline
  6. Request log (table): searchable, filterable, click to expand
Выводы главы 5

Сквозной пример: от проблемы до результата

Соберем все вместе. Один сценарий, который проходит через каждую главу.

Сценарий

Продукт: AI-ассистент для customer support в e-commerce. 8,000 запросов/день.

Текущее состояние: все через Claude Sonnet 4.6. Работает хорошо, но стоит $6,240/мес и растет.

Задача: снизить расходы на 40%+, не потеряв качество.

Шаг 1: Анализ запросов

Берем выборку из 500 запросов за последнюю неделю. Размечаем вручную (или с помощью LLM + spot-check):

Категория% запросовПримеры
Simple / factual45%"Где мой заказ?", "Какие способы оплаты?", "Есть ли доставка в Ташкент?"
Medium / reasoning35%"Мне не подошел размер, что делать?", "Сравните два тарифа доставки"
Complex / reasoning15%"У меня 3 заказа, один вернули, второй потеряли, третий пришел не тот. Разберитесь."
Creative5%Персонализированные рекомендации, нестандартные запросы

Вывод: 45% запросов (простые, фактические) не требуют Sonnet. Еще 35% (medium) можно попробовать на дешевой модели с confidence-based escalation.

Шаг 2: Routing config

routing:
  simple:
    factual: claude-haiku-4.5    # $1/$5
    reasoning: claude-haiku-4.5
    creative: claude-sonnet-4.6
    code: claude-haiku-4.5

  medium:
    factual: claude-sonnet-4.6   # $3/$15
    reasoning: claude-sonnet-4.6
    creative: claude-sonnet-4.6
    code: claude-sonnet-4.6

  complex:
    factual: claude-sonnet-4.6
    reasoning: claude-opus-4.6   # $5/$25
    creative: claude-opus-4.6
    code: claude-opus-4.6

fallback:
  claude-opus-4.6: [gpt-5.4, claude-sonnet-4.6]
  claude-sonnet-4.6: [gpt-4.1, claude-haiku-4.5]
  claude-haiku-4.5: [gpt-4.1-nano]

Шаг 3: Классификация

MVP: rule-based (длина + keywords). Accuracy ~70%. Через неделю, когда наберется 200+ размеченных запросов: embedding-based через Semantic Router. Accuracy ~85%.

Шаг 4: Считаем экономику

Средний запрос: 2,000 input + 800 output tokens.

Модель% запросовReq/деньCost/reqCost/день
SimpleHaiku 4.545%3,600$0.006$21.60
MediumSonnet 4.635%2,800$0.018$50.40
ComplexOpus 4.615%1,200$0.030$36.00
CreativeSonnet 4.65%400$0.018$7.20
Total/день$115.20
Total/мес$3,456
Было (all Sonnet)
$6,240/мес
Стало (с routing)
$3,456/мес
Экономия
45%
$2,784/мес = $33,400/год

И это без prompt caching (ещё -20-30% на input) и без batch API. С ними реалистично дойти до 60%+ экономии.

Шаг 5: Что на дашборде

Через неделю работы router показывает на дашборде:

Action item: 6% запросов с low confidence. Посмотреть, что это за запросы, добавить примеры в embedding set, пересчитать accuracy.

Итог: что ты теперь знаешь и что делать дальше

Карта знаний

ТемаКлючевой insight
ЭкономикаРазброс цен между моделями до 125x. 70-80% запросов не требуют flagship. Routing дает 40-70% экономии.
КлассификацияТри подхода (rules → embeddings → LLM), выбор зависит от стадии. Классификация сама стоит денег: считай ROI.
RoutingКонфиг-маппинг = 80% результата. Confidence-based = лучшее улучшение за минимум усилий. Cascade + routing = теоретический оптимум.
НадежностьТри слоя: retry → fallback → circuit breaker. Breaker per provider. Tiered timeouts.
ObservabilityГлавная метрика: cost savings vs baseline. Качество: heuristics (100%) + LLM-judge (5-10%) + feedback.

Чек-лист: порядок действий

Последовательность реализации
  1. Собери eval dataset (100+ запросов с ground truth метками). Без этого нельзя ни измерить accuracy классификатора, ни сравнить качество routing.
  2. Имплементируй rule-based classifier как baseline. Замерь accuracy на eval set.
  3. Сделай конфиг-маппинг routing (YAML). Подключи LiteLLM.
  4. Добавь tracker (SQLite). Логируй каждый запрос: модель, токены, стоимость, latency.
  5. Добавь fallback chains + circuit breaker.
  6. Замени rule-based на embedding-based classifier. Сравни accuracy.
  7. Добавь confidence-based routing.
  8. Построй dashboard. Покажи cost savings vs baseline.
  9. Добавь LLM-as-classifier как третью стратегию. Сравни все три.
  10. Оптимизируй: prompt caching, batch eval, cascade routing.

Ресурсы для углубления

Papers

Open-source инструменты

Коммерческие платформы

Бенчмарки и цены

Guides