Modelrouting: Stop met het gebruik van één model voor alles

Het juiste model voor de juiste taak.

Inhoud

Het draaien van een model met 70 miljard parameters om een e-mail van 200 woorden samen te vatten, is een verspilling. Het gebruiken van een model van 3 miljard parameters om productiecode te reviewen, is roekeloos. De meeste systemen zitten ergens tussenin — en daar komt modelrouting om de hoek kijken.

Het koppelt taakcomplexiteit aan modelcapaciteit. De afwegingen zijn reëel, maar ook de besparingen.

Diagram van LLM-modelroutestrategieën

Het routeringsprobleem

Mensen beginnen meestal met één model en blijven daar bij. Dat werkt, totdat je merkt dat de kosten, de latentie, of beide, een probleem vormen. Het alternatief is het bouwen van een router — iets dat beslist welk model welke aanvraag afhandelt.

In de praktijk werken vier strategieën:

  1. Op capaciteit gebaseerd — routeer op basis van wat het model kan
  2. Kostbewust — routeer op basis van wat je wilt uitgeven
  3. Latentiebewust — routeer op basis van hoe snel je het nodig hebt
  4. Hybride — combineer ze

Elke strategie optimaliseert iets anders. Het kiezen van één is meestal een beslissing over wat het meest pijn doet.

Op capaciteit gebaseerde routing

De eenvoudigste aanpak. Classificeer de taak en stuur het door naar het model dat het afhandelt.

Taak Modelgrootte Voorbeelden
Classificatie, tagging 1-3B Qwen2.5-1.5B, Gemma-2-2B
Samenvatting, extractie 3-7B Qwen2.5-7B, Llama-3.1-8B
Codegeneratie 7-14B Qwen2.5-Coder-7B, DeepSeek-Coder-V2
Complexe redenering 14-32B Qwen2.5-32B, Llama-3.1-70B
Creatief schrijven, analyse 32B+ Qwen2.5-72B, Claude, GPT-4

Als de taak het grotere model niet nodig heeft, gebruik het dan niet. Een model van 1,5B parameters hanteert sentimentclassificatie prima. Het zal echter geen coherent essay schrijven.

Implementatie is eenvoudig:

ROUTING_RULES = {
    "classify": {"model": "qwen2.5-1.5b", "max_tokens": 100},
    "summarize": {"model": "qwen2.5-7b", "max_tokens": 500},
    "code_review": {"model": "qwen2.5-coder-7b", "max_tokens": 2000},
    "reason": {"model": "qwen2.5-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"])

De valkuil is de classificatie zelf. Als je het taaktype verkeerd inschat, routeer je naar het verkeerde model. Ik heb systemen zien classificeren code-review als ‘samenvatting’, wat resulteerde in een stille kwaliteitsverlies.

Kostbewuste routing

Lokale inferentie blinkt hier uit. Lokale modellen zijn effectief gratis nadat de hardware is afgeschreven. Een RTX 5080 betaalt zichzelf terug in ongeveer zes maanden bij matig API-gebruik.

Model Input ($/M tokens) Output ($/M tokens) Lokale kosten/uur
GPT-4o $2,50 $10,00
Claude Sonnet 4 $3,00 $15,00
Qwen2.5-72B (API) $0,50 $2,00
Qwen2.5-32B (lokaal) $0,00 $0,00 ~$0,10
Qwen2.5-7B (lokaal) $0,00 $0,00 ~$0,05

Als je duizenden aanvragen per sessie verwerkt, wint zelfs $0,05 aan elektriciteitskosten het van $15/M tokens.

Budgetgebaseerde routing schakelt terug naarmate je meer uitgeeft:

class CostAwareRouter:
    def __init__(self, budget_per_session: float = 0.10):
        self.budget = budget_per_session
        self.spent = 0.0
        self.models = {
            "cheap": {"model": "qwen2.5-7b", "cost": 0.0},
            "medium": {"model": "qwen2.5-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"]

De kwaliteit daalt naarmate je terugvalt. Je begint met Claude, schakelt over naar Qwen-32B, en daarna naar Qwen-7B. Aan het einde van een lange sessie is de output merkbaar slechter. Of dat uitmaakt, hangt af van wat je bouwt.

Latentiebewuste routing

Interactieve tools hebben snelle eerste tokens nodig. Batchtaken kunnen wachten. Het verschil is meestal een factor van vijf in modelgrootte.

Gebruikscasus Eerste token Volledig Maximale modelgrootte
Realtime chat < 200ms < 2s < 7B
Interactieve tools < 500ms < 5s < 14B
Batchverwerking < 1s < 30s Elk
Onderzoek/analyse < 2s < 60s Elk

Wanneer je tokens naar een gebruiker streamt, is de latentie van het eerste token wat ze ervaren. Een model van 32B dat een halve seconde nodig heeft om te starten, voelt traag aan in vergelijking met een model van 1,5B dat direct reageert.

class LatencyAwareRouter:
    def __init__(self):
        self.model_latencies = {
            "qwen2.5-1.5b": {"first_token": 0.05, "complete": 0.5},
            "qwen2.5-7b": {"first_token": 0.15, "complete": 2.0},
            "qwen2.5-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 "qwen2.5-1.5b"

De latentiecijfers zijn ruw — ze hangen af van je hardware, kwantisatie en batchgrootte. Meet ze op je eigen setup.

Terugvalstrategieën

Modellen falen. APIs hanteren limieten. Time-outs gebeuren. Het patroon dat werkt, is een terugvalketen, gesorteerd van beste naar meest betrouwbaar:

class FallbackRouter:
    def __init__(self):
        self.fallback_chain = [
            {"model": "claude-sonnet-4", "timeout": 30},
            {"model": "qwen2.5-72b", "timeout": 60},
            {"model": "qwen2.5-32b", "timeout": 120},
            {"model": "qwen2.5-7b", "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")

Het laatste model in de keten moet lokaal zijn. Het is traager, maar het zal niet falen door een netwerkprobleem of een API-sleutel.

Wanneer routing helpt

Routing heeft zin wanneer je werklast gemengd is. Als je classificatie, samenvatting en redenering in hetzelfde systeem doet, bespaart een router geld en latentie.

Het heeft geen zin als alles wat je doet dezelfde complexiteit heeft. Gebruik dan gewoon het model dat goed is in die taak. De router voegt complexiteit toe die je niet nodig hebt.

Vroege prototyping is een andere reden om het over te slaan. Laat de taak eerst werken met één model, en voeg routing toe wanneer kosten of latentie daadwerkelijk een probleem worden.

Afwegingen

Elke routestrategie optimaliseert iets en offert iets anders op:

  • Enkel model — eenvoudigst, duurste, consistente kwaliteit
  • Op capaciteit gebaseerd — betere kosten, hogere kwaliteit per taak, matige complexiteit
  • Kostbewust — goedkoopst, variërende kwaliteit, matige complexiteit
  • Latentiebewust — snelst, mogelijk ten koste van kwaliteit, matige complexiteit
  • Hybride — het beste van alle werelden, meest complex om te implementeren

Productiesystemen convergeren meestal naar hybride. Begin met op capaciteit gebaseerde routing, voeg kostbewustheid toe wanneer de rekening binnenkomt, en voeg latentiebewustheid toe wanneer gebruikers klagen over traagheid.

Gerelateerd

Abonneren

Ontvang nieuwe berichten over systemen, infrastructuur en AI-engineering.