Маршрутизация моделей: перестаньте использовать одну модель для всего
Правильная модель для правильной задачи.
Запуск модели с 70 миллиардами параметров для суммаризации электронного письма из 200 слов — это расточительство. Запуск модели с 3 миллиардами параметров для ревью продакшн-кода — это безрассудство. Большинство систем находятся где-то посередине, и именно здесь в игру вступает роутинг моделей (маршрутизация запросов).
Он сопоставляет сложность задачи с возможностями модели. Компромиссы реальны, но и экономия тоже.

Проблема маршрутизации
Обычно люди начинают с одной модели и придерживаются ее. Это работает, пока вы не заметите стоимость, задержку или и то, и другое. Альтернатива — создание роутера, то есть механизма, который решает, какая модель будет обрабатывать тот или иной запрос.
На практике работают четыре стратегии:
- Основанная на возможностях — маршрутизация по тому, что модель умеет делать
- С учетом стоимости — маршрутизация по тому, сколько вы готовы потратить
- С учетом задержки — маршрутизация по тому, насколько быстро вам нужен результат
- Гибридная — их комбинация
Каждая оптимизирует что-то свое. Выбор одной обычно означает решение о том, какая проблема болит больше всего.
Маршрутизация, основанная на возможностях
Самый простой подход. Классифицируйте задачу и отправьте ее на модель, которая с ней справится.
| Задача | Размер модели | Примеры |
|---|---|---|
| Классификация, тегирование | 1-3B | Qwen3-1.7B, Gemma-2-2B |
| Суммаризация, извлечение | 3-7B | Qwen3-8B, Llama-3.1-8B |
| Генерация кода | 7-14B | Qwen2.5-Coder-7B, DeepSeek-Coder-V2 |
| Сложное рассуждение | 14-32B | Qwen3-32B, Llama-3.1-70B |
| Творческое письмо, анализ | 32B+ | Qwen2.5-72B, Claude, GPT-4 |
Если задаче не нужна большая модель, не используйте ее. Модель на 1.5B параметров отлично справляется с классификацией тональности. Просто она не напишет связное эссе.
Реализация проста:
ROUTING_RULES = {
"classify": {"model": "qwen3-1.7B", "max_tokens": 100},
"summarize": {"model": "qwen3-8B", "max_tokens": 500},
"code_review": {"model": "qwen2.5-coder-7b", "max_tokens": 2000},
"reason": {"model": "qwen3-32b", "max_tokens": 4000},
"creative": {"model": "claude-sonnet-4", "max_tokens": 8000},
}
def route_request(task_type: str) -> dict:
return ROUTING_RULES.get(task_type, ROUTING_RULES["reason"])
Ловушка — это сама классификация. Если вы неверно определите тип задачи, вы направите запрос на неправильную модель. Я видел системы, которые классифицировали ревью кода как «суммаризацию» и тихо теряли качество.
Маршрутизация с учетом стоимости
Локальный инференс сияет здесь. Локальные модели фактически бесплатны после амортизации оборудования. RTX 5080 окупается примерно за шесть месяцев при умеренном использовании API.
| Модель | Вход ($/M токенов) | Выход ($/M токенов) | Локальная стоимость/час |
|---|---|---|---|
| GPT-4o | $2.50 | $10.00 | — |
| Claude Sonnet 4 | $3.00 | $15.00 | — |
| Qwen2.5-72B (API) | $0.50 | $2.00 | — |
| Qwen3-32B (локально) | $0.00 | $0.00 | ~$0.10 |
| Qwen3-8B (локально) | $0.00 | $0.00 | ~$0.05 |
Если вы обрабатываете тысячи запросов за сессию, даже $0.05 на электричество лучше, чем $15 за миллион токенов.
Маршрутизация, основанная на бюджете, переходит на резервные варианты по мере расходов:
class CostAwareRouter:
def __init__(self, budget_per_session: float = 0.10):
self.budget = budget_per_session
self.spent = 0.0
self.models = {
"cheap": {"model": "qwen3-8B", "cost": 0.0},
"medium": {"model": "qwen3-32b", "cost": 0.0},
"expensive": {"model": "claude-sonnet-4", "cost": 0.000015},
}
def route(self, task: str) -> str:
ratio = self.spent / self.budget
if ratio < 0.5:
return self.models["expensive"]["model"]
elif ratio < 0.8:
return self.models["medium"]["model"]
return self.models["cheap"]["model"]
Качество ухудшается по мере перехода на резервные варианты. Вы начинаете с Claude, переходите на Qwen3-32B, затем на Qwen3-8B. К концу длинной сессии результат заметно хуже. Имеет ли это значение, зависит от того, что вы создаете.
Маршрутизация с учетом задержки
Интерактивным инструментам нужны быстрые первые токены. Пакетные задачи могут подождать. Разница обычно составляет фактор в пять в размерах модели.
| Сценарий использования | Первый токен | Завершение | Макс. размер модели |
|---|---|---|---|
| Чат в реальном времени | < 200 мс | < 2 с | < 7B |
| Интерактивные инструменты | < 500 мс | < 5 с | < 14B |
| Пакетная обработка | < 1 с | < 30 с | Любая |
| Исследования/анализ | < 2 с | < 60 с | Любая |
Когда вы транслируете токены пользователю, именно задержка первого токена ощущается ими. Модель на 32B, которой требуется полсекунды для старта, кажется медленной по сравнению с моделью на 1.5B, которая отвечает мгновенно.
class LatencyAwareRouter:
def __init__(self):
self.model_latencies = {
"qwen3-1.7b": {"first_token": 0.05, "complete": 0.5},
"qwen3-8B": {"first_token": 0.15, "complete": 2.0},
"qwen3-32b": {"first_token": 0.5, "complete": 10.0},
"claude-sonnet-4": {"first_token": 0.3, "complete": 5.0},
}
def route(self, target_latency: float) -> str:
for model, latencies in sorted(
self.model_latencies.items(),
key=lambda x: x[1]["complete"]
):
if latencies["complete"] <= target_latency:
return model
return "qwen3-1.7b"
Значения задержки приблизительны — они зависят от вашего оборудования, квантования и размера батча. Измеряйте на своей собственной конфигурации.
Стратегии резервного перехода
Модели ошибаются. API ограничивает частоту запросов. Происходят тайм-ауты. Рабочий паттерн — это цепочка резервных переходов, упорядоченная от лучшего к наиболее надежному:
class FallbackRouter:
def __init__(self):
self.fallback_chain = [
{"model": "claude-sonnet-4", "timeout": 30},
{"model": "qwen2.5-72b", "timeout": 60},
{"model": "qwen3-32b", "timeout": 120},
{"model": "qwen3-8b", "timeout": 300},
]
def route_with_fallback(self, prompt: str) -> str:
for config in self.fallback_chain:
try:
return self.call_model(
config["model"], prompt,
timeout=config["timeout"]
)
except (TimeoutError, APIError) as e:
log.warning(f"Model {config['model']} failed: {e}")
continue
raise RuntimeError("All fallback models failed")
Последняя модель в цепочке должна быть локальной. Она медленнее, но не откажет из-за сетевых проблем или ошибки ключа API.
Когда маршрутизация помогает
Маршрутизация имеет смысл, когда ваша нагрузка смешанная. Если вы выполняете классификацию, суммаризацию и рассуждения в одной системе, роутер экономит деньги и снижает задержки.
Она не имеет смысла, когда все, что вы делаете, имеет одинаковую сложность. Просто используйте модель, которая хорошо справляется с этой задачей. Роутер добавляет сложность, которая вам не нужна.
Ранний прототип — еще одна причина пропустить этот шаг. Сначала заставьте задачу работать с одной моделью, а затем добавьте маршрутизацию, когда стоимость или задержка действительно станут проблемой.
Компромиссы
Каждая стратегия маршрутизации оптимизирует что-то одно и жертвует чем-то другим:
- Одна модель — самая простая, самая дорогая, стабильное качество
- Основанная на возможностях — лучшая стоимость, более высокое качество для каждой задачи, средняя сложность
- С учетом стоимости — самая дешевая, качество варьируется, средняя сложность
- С учетом задержки — самая быстрая, возможно, снижает качество, средняя сложность
- Гибридная — лучшее из всего, самая сложная в реализации
Продакшн-системы обычно сходятся к гибридной. Начните с маршрутизации, основанной на возможностях, добавьте учет стоимости, когда придет счет, добавьте учет задержки, когда пользователи будут жаловаться на медленность.
См. также
- Оптимизация затрат для LLM-систем — бюджетирование токенов, кэширование, резервные модели
- LLM Guardrails в практике — валидация ввода, фильтрация вывода, безопасность
- Проектирование многомодельных систем — архитектура для нескольких моделей
- Архитектура LLM — столп проектирования системы: маршрутизация, стоимость, guardrails и оркестрация