Как проектировать cost-aware routing (дешёвая модель для простых запросов, дорогая — для сложных)?
Краткий тезис
routing|Cost-aware routing — это архитектурный паттерн в Agentic RAG, при котором система на основе лёгкого классификатора оценивает сложность пользовательского запроса и направляет его к модели с оптимальным соотношением цена-качество. Такой подход позволяет снизить затраты на инференс на 50–70% при минимальной потере точности (1–5%). Ключевые компоненты: классификатор сложности, пул моделей разного размера и фолбэк-механизм для перевызова на уровень выше при неудаче.
1. Термин: Cost-aware routing (роутинг с учётом стоимости)
routing|Cost-aware routing — это компонент системы, который перед вызовом LLM решает, какую модель использовать для данного запроса. Решение принимается на основе предсказанной сложности запроса, стоимости модели и требуемого качества. Цель — минимизировать среднюю стоимость одного запроса, сохраняя приемлемое качество ответа.
Основные метрики
- Average cost per query (ACP) — средняя стоимость одного запроса после роутинга.
- Quality degradation — падение метрик (точность, faithfulness, answer relevance) по сравнению с использованием только лучшей модели.
- Cost saving — процент экономии относительно baseline (только дорогая модель).
2. Зачем нужен cost-aware routing
В реальных RAG-системах запросы сильно различаются:
- Простые запросы (30–50% трафика): фактологические вопросы, извлечение информации из одного документа, суммаризация коротких текстов. Для них достаточно небольшой модели (8B параметров).
- Сложные запросы (20–30%): multi-hop рассуждения, сравнение нескольких документов, аналитические вопросы. Требуют мощной модели (GPT-4, Claude 3.5).
- Средние запросы (20–30%): запросы, требующие некоторого анализа, но не экстремально сложные.
Без роутинга вы платите максимальную цену за каждый запрос, хотя 60–70% из них могли бы быть обработаны дешёвой моделью. Cost-aware routing позволяет снизить затраты в 2–3 раза.
3. Архитектура: классификатор сложности
Основной компонент — легковесный текстовый классификатор, который присваивает запросу метку сложности (обычно 3–5 классов). Типичные реализации:
3.1. Классификатор на основе эмбеддингов + линейный слой
Используется предобученный энкодер (например, all-MiniLM-L6-v2) или BERT (tiny или base). Вектор запроса подаётся на softmax-классификатор с 3–5 классами.
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification
model_name = "bert-tiny-finetuned-complexity"
tokenizer = AutoTokenizer.from_pretrained(model_name)
classifier = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=5)
def predict_complexity(query: str) -> int:
inputs = tokenizer(query, return_tensors="pt", truncation=True, max_length=128)
with torch.no_grad():
logits = classifier(**inputs).logits
return torch.argmax(logits).item() # 0-4
3.2. Rule-based классификатор (без ML)
Простые эвристики: длина запроса, количество вопросительных слов, наличие специфических паттернов ("сравни", "объясни", "почему"). Может использоваться как fallback или для zero-shot старта.
3.3. LLM-as-Judge (гибридный)
Сначала пытается классифицировать быстрый эмбеддинг-классификатор, при низкой уверенности (confidence < 0.7) запрос направляется на крошечную модель (например, GPT-3.5-turbo-mini) для оценки сложности. Это дороже, но повышает точность роутинга.
4. Методы оценки сложности запроса
Для классификации используются следующие признаки:
| Признак | Описание | Пример простого | Пример сложного |
|---|---|---|---|
| Длина запроса | Количество токенов | 10-20 | 50-200 |
| Количество сущностей | Именованные сущности (NER) | 1-2 | 5+ |
| Тип вопроса | Фактологический (who, what, where) vs аналитический (why, how, compare) | "Сколько стоит?" | "Сравните эффективность методов" |
| Необходимость multi-hop | Требуется объединить информацию из нескольких документов | Нет | Да |
| Наличие таблиц/кода | Запрос требует понимания структурированных данных | Нет | Да |
Для обучения классификатора нужно размеченное множество: на 500–2000 запросах аннотаторы ставят метку сложности (1–5). Затем fine-tune BERT-tiny на этой разметке.
5. Стратегии роутинга: три уровня моделей
Типичная схема с тремя уровнями (аналогично multi-model orchestration):
| Уровень | Модели (пример) | Стоимость за 1K токенов (вход/выход) | Применение |
|---|---|---|---|
| Light (дешёвая) | Llama-3-8B (Groq), GPT-3.5-turbo-mini, Mistral-7B | $0.00005 - $0.0001 | Простые фактологические вопросы, суммаризация коротких документов |
| Medium (средняя) | Mistral-8x22B, GPT-3.5-turbo, Claude-3-Haiku | $0.001 - $0.002 | Средняя сложность, требующая небольшого анализа |
| Heavy (дорогая) | GPT-4-turbo, Claude-3-Opus, Llama-3-405B (через API) | $0.01 - $0.03 | Многошаговые рассуждения, глубокий анализ, запросы с кодом или таблицами |
Выбор модели может быть гибким если запрос относится к классам 1-2 → Light, класс 3 → Medium, классы 4-5 → Heavy.
6. Фолбэк и обработка ошибок классификатора
Даже лучший классификатор может ошибаться. Если простую модель отправили на сложный запрос, она может:
- Сгенерировать неточный ответ (hallucination)
- Не справиться с multi-hop
- Вернуть "I don't know"
Стратегии фолбэка
- Наивный: после ответа дешёвой модели запускается фильтр качества (например, confidence score выходного логита или небольшой LLM-as-Judge). Если качество ниже порога → перезапрос на модель уровнем выше.
- Прогрессивный: всегда сначала вызывается Light, если ответ признан неудовлетворительным → Medium, затем Heavy. Это гарантирует минимальную стоимость при максимальном качестве, но увеличивает latency.
- Direct fallback: если классификатор даёт класс 3, но уверенность < 0.8 → сразу Heavy (без Medium).
def route_with_fallback(query: str) -> str:
complexity = predict_complexity(query)
if complexity <= 2:
answer = call_light_model(query)
if quality_check(answer, query) > 0.8: # произвольный порог
return answer
else: # fallback на Medium
return call_medium_model(query)
elif complexity == 3:
return call_medium_model(query)
else: # 4-5
return call_heavy_model(query)
7. Метрики и эффект
Реальный эффект от внедрения cost-aware routing (данные из статей и практики):
- Снижение затрат: 50–70% (в среднем -60%)
- Падение качества: -2%..-5% (зависит от порога фолбэка)
- Увеличение latency: +20% из-за классификатора и фолбэка (однако для простых запросов ответ приходит быстрее)
Таблица сравнения baseline vs routing
| Метрика | Baseline (только GPT-4) | Cost-aware routing |
|---|---|---|
| Average cost per query | $0.02 | $0.008 |
| Accuracy (на тестовом датасете) | 94% | 92% |
| P50 latency | 1.2 сек | 0.9 сек |
| P95 latency | 3.5 сек | 4.0 сек (из-за фолбэков) |
8. Инструменты и библиотеки
- Router LLM — открытая библиотека для построения мультимодельных роутеров (поддерживает классификаторы на основе эмбеддингов и rule-based).
- LiteLLM Router — встроенный роутер в
litellmс поддержкой fallback и cost-лимитов. - OpenAI Router (Assistants API) — позволяет задавать несколько моделей в одном Assistants, хотя управление сложностью ограничено.
- LangChain / Haystack — имеют экспериментальные модули
RouterChainилиAgentс выбором инструмента, можно адаптировать под cost-aware.
9. Альтернативные подходы
- Speculative decoding — ускоряет генерацию дорогой модели за счёт дешёвого драфтера, но не снижает cost (только latency).
- Cascading — последовательный вызов моделей (сначала маленькая, потом большая при ошибке), похож на наш фолбэк, но без классификатора. Может быть медленнее.
- Mixture of Agents (MoA) — несколько моделей голосуют, но стоимость выше.
- Adaptive context — уменьшает количество токенов контекста для простых запросов, косвенно снижая cost.
10. Практические рекомендации
- Начните с лейблов — соберите 1000 запросов, вручную назначьте классы сложности.
- Используйте BERT-tiny — он достаточно быстрый (10-20 мс на классификацию) и точный.
- Храните кэш — для повторяющихся запросов можно кешировать ответ дешёвой модели.
- Мониторьте долю фолбэков — если >20% запросов уходят на Medium после Light, значит классификатор плохо обучен.
- A/B тестируйте — запускайте cost-aware routing на 10% трафика, сравнивайте с 100% Heavy моделью.
Пет-проект для закрепления
Задача: Реализовать cost-aware routing для RAG-системы на документах Wikipedia о животных (500 статей).
Инструменты: Python, Hugging Face (BERT-tiny, sentence-transformers), FastAPI, litellm (для вызова моделей).
Шаги:
- Сгенерировать 500 синтетических запросов с помощью GPT-4, разбить на 5 уровней сложности (по длине, типу, multi-hop).
- Разметить каждый запрос меткой сложности (1-5) через аннотатора (можно с помощью LLM).
- Обучить
bert-tiny-finetuned-complexityна этой разметке (эпохи=5, lr=2e-5). - Поднять FastAPI-сервис с эндпоинтом
/classify. - Создать роутер, который вызывает:
- Groq (Llama-3-8B) для class 1-2,
- GPT-3.5-turbo для class 3,
- GPT-4-turbo для class 4-5.
- Добавить fallback: если ответ от Llama-3-8B имеет низкий confidence (средняя вероятность токенов < 0.6) → перезапрос на GPT-3.5-turbo.
- Замерить cost (счёт от API) и точность (сравнить с ответами только GPT-4) на 200 тестовых запросах.
Ожидаемый результат: экономия cost ~55% при падении accuracy не более 5%. Демо-приложение с визуализацией пути каждого запроса.
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 775 | Как проектировать routing в Agentic RAG |
| 776 | Что такое dynamic routing и зачем он нужен |
| 777 | Как балансировать между несколькими LLM в одной системе |
| 779 | Как оценивать стоимость инференса LLM |
| 780 | Как организовать fallback при отказе одной модели |
| 781 | Как использовать LLM-as-Judge для контроля качества |
Навигация
- Предыдущий: 777
- Следующий: 779
- Индекс: 00. Индекс разборов