Projektowanie systemów wielomodelowych: Kiedy jeden model to za mało

Wybierz najprostszy wzorzec, który działa.

Page content

Systemy oparte na jednym modelu są proste. Systemy wielomodelowe są potężne. Wyzwanie nie polega na wyborze modeli – chodzi o zaprojektowanie architektury, która je koordynuje.

System wielomodelowy nie oznacza posiadania większej liczby modeli. Oznacza to posiadanie odpowiedniego modelu do odpowiedniego zadania w odpowiednim czasie.

Wzorce projektowe systemów wielomodelowych LLM

Wzorce architektoniczne

Pięć wzorców pokrywa większość przypadków użycia:

Wzorzec Skomplikowanie Kiedy stosować Kompromis
Pojedynczy model Najniższy Prototypowanie, proste zadania Ograniczone możliwości
Sekwencyjny Niski Procesy wieloetapowe Wyższa opóźnienie
Równoległy Średni Zadania niezależne Wyższy koszt
Hierarchiczny Wysoki Skomplikowane wnioskowanie Skomplikowana koordynacja
Ensemble Najwyższy Krytyczne decyzje Najwyższy koszt

Wybierz najprostszy z tych, które działają. Skomplikowanie jest realne i się kumuluje.

Architektura sekwencyjna

Przetwarzaj zadania poprzez łańcuch modeli, z których każdy specjalizuje się w określonym etapie.

Wzorzec 1: Rurociąg

Wzorzec rurociągu — wyjście każdego modelu podaje się jako wejście dla następnego:

class ModelPipeline:
    def __init__(self):
        self.models = [
            {"model": "qwen2.5-1.5b", "task": "classify"},
            {"model": "qwen2.5-7b", "task": "extract"},
            {"model": "qwen2.5-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

Opóźnienia sumują się. Trzy modele w sekwencji oznaczają trzykrotnie dłuższe opóźnienie. Stosuj to tylko wtedy, gdy każdy etap naprawdę wymaga innego modelu.

Wzorzec 2: Router

Wzorzec routera — sklasyfikuj zadanie, przekieruj do specjalisty:

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

    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)

Klasyfikator jest najsłabszym ogniwem. Jeśli popełni błąd w klasyfikacji, prześlesz zapytanie do niewłaściwego modelu i stracisz na jakości. Użyj klasyfikatora, który jest wystarczająco dobry – nawet mały model zadziała, jeśli kategorie są jasno zdefiniowane.

Architektura równoległa

Przetwarzaj niezależne zadania jednocześnie.

Wzorzec 1: Rozszerzanie (Fan-Out)

Rozszerzanie — uruchom ten sam prompt w wielu modelach:

import asyncio

class ModelFanOut:
    def __init__(self):
        self.models = [
            "qwen2.5-7b",
            "qwen2.5-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)

Przydatne do porównań, testów A/B lub gdy chcesz wybrać najlepszy wynik. Jest drogie, ale wzrost jakości jest warty tego dla krytycznych decyzji.

Wzorzec 2: Głosowanie

Głosowanie — łączenie wyników poprzez konsensus:

class ModelVoting:
    def __init__(self):
        self.models = [
            "qwen2.5-7b",
            "qwen2.5-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]

Głosowanie większościowe działa w przypadku klasyfikacji. W zadaniach generatywnych jest trudniej – potrzebujesz podobieństwa semantycznego, a nie dokładnych dopasowań.

Architektura hierarchiczna

Użyj modeli na różnych poziomach abstrakcji.

Wzorzec 1: Planista-Executor

Planista-Executor — silny model planuje, mniejsze modele wykonują:

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

    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"], "qwen2.5-7b")
            result = self.call_model(executor, step["prompt"])
            results.append(result)
        return self.call_model(self.planner, f"Synthesize: {results}")

Planista wykonuje ciężką pracę. Executorzy zajmują się konkretnymi zadaniami. Ten wzorzec działa dobrze, gdy etap planowania jest kosztowny, a etapy wykonania są tanie.

Wzorzec 2: Nadzorujący-Pracownik

Nadzorujący-Pracownik – nadzorujący deleguje zadania i recenzuje:

class SupervisorWorker:
    def __init__(self):
        self.supervisor = "qwen2.5-32b"
        self.workers = ["qwen2.5-7b", "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}")

Nadzorujący jest wąskim gardłem. Planuje, deleguje i recenzuje. Upewnij się, że jest wystarczająco szybki, w przeciwnym razie cały system zwolni.

Architektura Ensemble

Połącz wiele modeli dla krytycznych decyzji.

Wzorzec 1: Ważony Ensemble

Ważony ensemble — oceń wyjście każdego modelu, wybierz najwyższe:

class WeightedEnsemble:
    def __init__(self):
        self.models = {
            "qwen2.5-32b": 0.5,
            "claude-sonnet-4": 0.3,
            "qwen2.5-7b": 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)

Wagi odzwierciedlają Twoje zaufanie do każdego modelu. Dostosuj je na podstawie rzeczywistej wydajności, a nie benchmarków.

Wzorzec 2: Konsensusowy Ensemble

Konsensusowy ensemble – wymóg zgody, eskalacja w przypadku braku zgody:

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

    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("qwen2.5-32b", prompt)

Próg kontroluje, jak surowy musi być konsensus. 0.7 oznacza zgodność dwóch trzecich. Obniż go dla szybszych decyzji, podwyższ dla większego zaufania.

Kiedy systemy wielomodelowe mają sens

Systemy wielomodelowe mają sens, gdy masz mieszane obciążenia, potrzebujesz wysokiej jakości dla krytycznych decyzji lub optymalizujesz pod kątem kosztu lub opóźnienia.

Nie mają sensu, gdy wszystkie zadania mają podobny poziom skomplikowania, prototypujesz lub prostota jest ważniejsza niż optymalizacja.

Zasada kciuka: zacznij od jednego modelu. Dodaj więcej, gdy natkniesz się na realne ograniczenie – koszt, opóźnienie lub jakość. Nie projektuj skomplikowania, dopóki go nie potrzebujesz.

Kompromisy

Wzorzec Koszt Opóźnienie Jakość Skomplikowanie
Pojedynczy model Najniższy Najniższy Zmienna Najniższy
Sekwencyjny Średni Wysoki Wysoka Średni
Równoległy Wysoki Niski Wysoka Średni
Hierarchiczny Wysoki Wysoki Najwyższa Wysoki
Ensemble Najwyższy Średni Najwyższa Najwyższy

Każdy wzorzec wymaga kompromisu. Wybierz ten, który pasuje do Twoich ograniczeń.

Powiązane

Subskrybuj

Otrzymuj nowe wpisy o systemach, infrastrukturze i inżynierii AI.