Проектирование многомоделевых систем: когда одной модели недостаточно

Выберите самый простой работающий паттерн.

Содержимое страницы

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

Система с несколькими моделями — это не просто наличие большего количества моделей. Это использование правильной модели для правильной задачи в правильное время.

Многомодельные LLM-системы

Архитектурные паттерны

Пять паттернов покрывают большинство случаев использования:

Паттерн Сложность Когда использовать Компромисс
Одна модель Наименьшая Прототипирование, простые задачи Ограниченные возможности
Последовательная Низкая Многошаговые рабочие процессы Большая задержка
Параллельная Средняя Независимые задачи Высокая стоимость
Иерархическая Высокая Сложное рассуждение Сложная оркестрация
Ансамблевая Наивысшая Критические решения Наивысшая стоимость

Выбирайте самый простой работающий вариант. Сложность реальна и имеет свойство накапливаться.

Последовательная архитектура

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

Паттерн 1: Конвейер (Pipeline)

Паттерн конвейера — вывод одной модели становится входом для следующей:

class ModelPipeline:
    def __init__(self):
        self.models = [
            {"model": "qwen3-1.7b", "task": "classify"},
            {"model": "qwen3-8b", "task": "extract"},
            {"model": "qwen3-32b", "task": "reason"},
        ]

    def process(self, input: str) -> str:
        current = input
        for model_config in self.models:
            current = self.call_model(
                model_config["model"],
                self.create_prompt(model_config["task"], current)
            )
        return current

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

Паттерн 2: Маршрутизатор (Router)

Паттерн маршрутизации — классифицируйте задачу и направьте к специалисту:

class ModelRouter:
    def __init__(self):
        self.classifier = "qwen3-1.7b"
        self.specialists = {
            "code": "qwen2.5-coder-7b",
            "math": "qwen3-32b",
            "creative": "claude-sonnet-4",
            "general": "qwen3-8b",
        }

    def route(self, prompt: str) -> str:
        task_type = self.classify(prompt)
        model = self.specialists.get(task_type, self.specialists["general"])
        return self.call_model(model, prompt)

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

Параллельная архитектура

Обработка независимых задач одновременно.

Паттерн 1: Веерное распространение (Fan-Out)

Веерное распространение — пропустите один и тот же промпт через несколько моделей:

import asyncio

class ModelFanOut:
    def __init__(self):
        self.models = [
            "qwen3-8b",
            "qwen3-32b",
            "claude-sonnet-4",
        ]

    async def process(self, prompt: str) -> list[str]:
        tasks = [self.call_model(model, prompt) for model in self.models]
        return await asyncio.gather(*tasks)

Полезно для сравнения, A/B тестирования или когда вы хотите выбрать лучший результат. Дорого, но прирост качества оправдан для критических решений.

Паттерн 2: Голосование (Voting)

Голосование — объединение выводов через консенсус:

class ModelVoting:
    def __init__(self):
        self.models = [
            "qwen3-8b",
            "qwen3-32b",
            "claude-sonnet-4",
        ]

    def vote(self, prompt: str) -> str:
        responses = [self.call_model(model, prompt) for model in self.models]
        from collections import Counter
        votes = Counter(responses)
        return votes.most_common(1)[0][0]

Большинство голосов работает для задач классификации. Для задач генерации это сложнее — вам нужна семантическая сходство, а не точное совпадение.

Иерархическая архитектура

Использование моделей на разных уровнях абстракции.

Паттерн 1: Планировщик-Исполнитель

Планировщик-исполнитель — сильная модель планирует, а меньшие модели выполняют:

class PlannerExecutor:
    def __init__(self):
        self.planner = "qwen3-32b"
        self.executors = {
            "code": "qwen2.5-coder-7b",
            "search": "qwen3-8b",
            "math": "qwen3-8b",
        }

    def process(self, task: str) -> str:
        plan = self.call_model(self.planner, f"Plan: {task}")
        results = []
        for step in self.parse_plan(plan):
            executor = self.executors.get(step["type"], "qwen3-8b")
            result = self.call_model(executor, step["prompt"])
            results.append(result)
        return self.call_model(self.planner, f"Synthesize: {results}")

Планировщик выполняет основную работу. Исполнители обрабатывают конкретные задачи. Этот паттерн хорошо работает, когда шаг планирования дорогой, а шаги выполнения дешевы.

Паттерн 2: Супервизор-Рабочий

Супервизор-рабочий — супервизор делегирует и проверяет:

class SupervisorWorker:
    def __init__(self):
        self.supervisor = "qwen3-32b"
        self.workers = ["qwen3-8b", "qwen2.5-coder-7b"]

    def process(self, task: str) -> str:
        assignments = self.call_model(self.supervisor, f"Assign: {task}")
        results = []
        for assignment in self.parse_assignments(assignments):
            result = self.call_model(
                assignment["worker"], assignment["task"]
            )
            results.append(result)
        return self.call_model(self.supervisor, f"Review: {results}")

Супервизор является узким местом. Он планирует, делегирует и проверяет. Убедитесь, что он достаточно быстр, иначе вся система замедлится.

Ансамблевая архитектура

Объединение нескольких моделей для критических решений.

Паттерн 1: Взвешенный ансамбль

Взвешенный ансамбль — оцените вывод каждой модели, выберите наилучший:

class WeightedEnsemble:
    def __init__(self):
        self.models = {
            "qwen3-32b": 0.5,
            "claude-sonnet-4": 0.3,
            "qwen3-8b": 0.2,
        }

    def decide(self, prompt: str) -> str:
        responses = {
            model: self.call_model(model, prompt)
            for model in self.models
        }
        scores = {}
        for model, response in responses.items():
            score = self.evaluate(response) * self.models[model]
            scores[response] = scores.get(response, 0) + score
        return max(scores, key=scores.get)

Веса отражают вашу уверенность в каждой модели. Настраивайте их на основе фактической производительности, а не бенчмарков.

Паттерн 2: Ансамбль консенсуса

Ансамбль консенсуса — требуйте согласия, эскалируйте, если его нет:

class ConsensusEnsemble:
    def __init__(self, threshold: float = 0.7):
        self.threshold = threshold
        self.models = [
            "qwen3-32b",
            "claude-sonnet-4",
            "qwen3-8b",
        ]

    def decide(self, prompt: str) -> str:
        responses = [
            self.call_model(model, prompt)
            for model in self.models
        ]
        from collections import Counter
        votes = Counter(responses)
        max_votes = max(votes.values())

        if max_votes / len(self.models) >= self.threshold:
            return votes.most_common(1)[0][0]

        return self.call_model("qwen3-32b", prompt)

Порог определяет строгость консенсуса. 0.7 означает согласие двух третей. Уменьшайте его для более быстрых решений, увеличивайте для большей уверенности.

Когда многомодельные системы имеют смысл

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

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

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

Компромиссы

Паттерн Стоимость Задержка Качество Сложность
Одна модель Наименьшая Наименьшая Переменная Наименьшая
Последовательная Средняя Высокая Высокое Средняя
Параллельная Высокая Низкая Высокое Средняя
Иерархическая Высокая Высокая Наивысшее Высокая
Ансамблевая Наивысшая Средняя Наивысшее Наивысшая

Каждый паттерн что-то жертвует. Выберите тот, который соответствует вашим ограничениям.

Связанные материалы

Подписаться

Получайте новые материалы про системы, инфраструктуру и AI engineering.