Multi-Model Systeemontwerp: Wanneer één model niet voldoende is
Kies het eenvoudigste patroon dat werkt.
Single-modelsystemen zijn eenvoudig. Multi-modelsystemen zijn krachtig. De uitdaging ligt niet in het kiezen van modellen, maar in het ontwerpen van de architectuur die ze orchestreert.
Een multi-modelsysteem gaat niet om het hebben van meer modellen. Het gaat om het hebben van het juiste model voor de juiste taak op het juiste moment.

Architectuurpatronen
Vijf patronen dekken de meeste gebruiksscenario’s:
| Patroon | Complexiteit | Wanneer te gebruiken | Trade-off |
|---|---|---|---|
| Single Model | Laagst | Prototyping, eenvoudige taken | Beperkte capaciteit |
| Sequentieel | Laag | Werkflows met meerdere stappen | Hogere latentie |
| Parallel | Midden | Onafhankelijke taken | Hogere kosten |
| Hierarchisch | Hoog | Complexe redenering | Complexe orkestratie |
| Ensemble | Hoogst | Kritieke beslissingen | Hoogste kosten |
Kies het eenvoudigste dat werkt. Complexiteit is echt, en die hoopt zich op.
Sequentiële architectuur
Verwerk taken door een keten van modellen, elk gespecialiseerd in een stap.
Patroon 1: Pipeline
Pipelinepatroon — de output van elk model voert naar de volgende:
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
Latentie telt op. Drie modellen in sequentie betekent drie keer de latentie. Gebruik dit alleen wanneer elke stap daadwerkelijk een ander model nodig heeft.
Patroon 2: Router
Routerpatroon — classificeer de taak, routeer naar de specialist:
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)
De classifier is de zwakke schakel. Als deze verkeerd classificeert, routeer je naar het verkeerde model en verlies je kwaliteit. Gebruik een classifier die goed genoeg is — zelfs een kleine werkt als de categorieën duidelijk zijn.
Parallelle architectuur
Verwerk onafhankelijke taken gelijktijdig.
Patroon 1: Fan-Out
Fan-out — voer dezelfde prompt uit door meerdere modellen:
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)
Nuttig voor vergelijking, A/B-testing, of wanneer je de beste output wilt kiezen. Duur, maar de kwaliteitswinst is het waard voor kritieke beslissingen.
Patroon 2: Voting
Voting — combineer outputs via consensus:
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]
Meerderheidsstemmen werken voor classificatie. Voor generatietaken is het laster — je hebt semantische similariteit nodig, geen exacte matches.
Hierarchische architectuur
Gebruik modellen op verschillende niveaus van abstractie.
Patroon 1: Planner-Executor
Planner-executor — een sterk model plant, kleinere modellen voeren uit:
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}")
De planner doet het zware werk. De executors hanteren specifieke taken. Dit patroon werkt goed wanneer de planstap duur is, maar de uitvoeringsstappen goedkoop.
Patroon 2: Supervisor-Worker
Supervisor-worker — een supervisor delegeert en reviewt:
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}")
De supervisor is de bottleneck. Het plant, delegeert en reviewt. Zorg dat het snel genoeg is, anders vertraagt het hele systeem.
Ensemble-architectuur
Combineer meerdere modellen voor kritieke beslissingen.
Patroon 1: Weighted Ensemble
Gewogen ensemble — score de output van elk model, kies de hoogste:
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)
Gewichten weerspiegelen je vertrouwen in elk model. Pas ze aan op basis van werkelijke prestaties, niet op benchmarks.
Patroon 2: Consensus Ensemble
Consensus ensemble — vereis overeenstemming, escaleer als deze ontbreekt:
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)
De drempel bepaalt hoe streng consensus is. 0.7 betekent twee derde overeenstemming. Verlaag het voor snellere beslissingen, verhoog het voor meer zekerheid.
Wanneer multi-modelsystemen zinvol zijn
Multi-modelsystemen zijn zinvol wanneer je gemengde workloads hebt, hoge kwaliteit nodig hebt voor kritieke beslissingen, of optimaliseert voor kosten of latentie.
Ze zijn niet zinvol wanneer alle taken een vergelijkbare complexiteit hebben, je prototypt, of eenvoud belangrijker is dan optimalisatie.
De vuistregel: begin met één model. Voeg er meer toe wanneer je tegen een echte beperking stoot — kosten, latentie of kwaliteit. Ontwerp geen complexiteit voordat je het nodig hebt.
Trade-offs
| Patroon | Kosten | Latentie | Kwaliteit | Complexiteit |
|---|---|---|---|---|
| Single Model | Laagst | Laagst | Variabel | Laagst |
| Sequentieel | Midden | Hoog | Hoog | Midden |
| Parallel | Hoog | Laag | Hoog | Midden |
| Hierarchisch | Hoog | Hoog | Hoogst | Hoog |
| Ensemble | Hoogst | Midden | Hoogst | Hoogst |
Elk patroon maakt een trade-off. Kies degene die past bij je beperkingen.
Gerelateerd
- Model Routing Strategies — routing op basis van capaciteit, kosten en latentie
- Cost Optimization for LLM Systems — tokenbudgettering, fallbackmodellen, caching
- LLM Guardrails in Practice — invoervalidatie, outputfiltering, veiligheid
- LLM Architecture — systeemontwerppijler: routing, kosten, guardrails en orkestratie