Modell-Routing: Verwenden Sie nicht ein einzelnes Modell für alles

Das richtige Modell für die richtige Aufgabe.

Inhaltsverzeichnis

Das Ausführen eines Modells mit 70 Milliarden Parametern zur Zusammenfassung einer 200-Wörter-E-Mail ist verschwenderisch. Das Ausführen eines 3-Milliarden-Parametern-Modells zur Überprüfung von Produktionscode ist fahrlässig. Die meisten Systeme liegen irgendwo dazwischen – und genau hier kommt das Modell-Routing ins Spiel.

Es passt die Komplexität der Aufgabe der Modellkapazität an. Die Kompromisse sind real, aber auch die Einsparungen.

Diagramm der LLM-Modell-Routing-Strategien

Das Routing-Problem

Menschen beginnen meist mit einem Modell und bleiben dabei. Das funktioniert, bis man die Kosten, die Latenz oder beides bemerkt. Die Alternative ist der Aufbau eines Routers – etwas, das entscheidet, welches Modell welche Anfrage bearbeitet.

In der Praxis funktionieren vier Strategien:

  1. Fähigkeitsbasiert – Routing basierend auf den Fähigkeiten des Modells
  2. Kostensensibel – Routing basierend auf dem Budget
  3. Latenzsensibel – Routing basierend auf der benötigten Geschwindigkeit
  4. Hybrid – eine Kombination daraus

Jede optimiert etwas anderes. Die Wahl einer Strategie ist meist eine Entscheidung darüber, welcher Aspekt am meisten schmerzt.

Fähigkeitsbasiertes Routing

Der einfachste Ansatz. Klassifizieren Sie die Aufgabe und senden Sie sie an das Modell, das sie bearbeiten kann.

Aufgabe Modellgröße Beispiele
Klassifikation, Tagging 1-3B Qwen2.5-1.5B, Gemma-2-2B
Zusammenfassung, Extraktion 3-7B Qwen2.5-7B, Llama-3.1-8B
Code-Generierung 7-14B Qwen2.5-Coder-7B, DeepSeek-Coder-V2
Komplexe Reasoning-Aufgaben 14-32B Qwen2.5-32B, Llama-3.1-70B
Kreatives Schreiben, Analyse 32B+ Qwen2.5-72B, Claude, GPT-4

Wenn die Aufgabe das größere Modell nicht benötigt, verwenden Sie es nicht. Ein 1.5B-Modell bewältigt die Sentiment-Klassifikation gut. Es wird jedoch keinen kohärenten Aufsatz schreiben.

Die Implementierung ist straightforward (geradlinig):

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"])

Das Problem ist die Klassifizierung selbst. Wenn Sie den Aufgabentyp falsch bestimmen, leiten Sie an das falsche Modell weiter. Ich habe Systeme gesehen, die Code-Reviews als „Zusammenfassung“ klassifiziert und dabei stillschweigend an Qualität verloren haben.

Kostensensibles Routing

Lokale Inferenz glänzt hier. Lokale Modelle sind nach Amortisation der Hardware effektiv kostenlos. Eine RTX 5080 zahlt sich bei moderater API-Nutzung in etwa sechs Monaten selbst zurück.

Modell Input ($/M Token) Output ($/M Token) Lokale Kosten/Stunde
GPT-4o $2.50 $10.00
Claude Sonnet 4 $3.00 $15.00
Qwen2.5-72B (API) $0.50 $2.00
Qwen2.5-32B (lokal) $0.00 $0.00 ~$0.10
Qwen2.5-7B (lokal) $0.00 $0.00 ~$0.05

Wenn Sie pro Sitzung Tausende von Anfragen verarbeiten, schlagen selbst $0,05 Stromkosten $15/M Token.

Budget-basiertes Routing fällt zurück, je mehr Sie ausgeben:

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"]

Die Qualität verschlechtert sich mit jedem Rückgriff. Sie beginnen mit Claude, wechseln zu Qwen-32B und dann zu Qwen-7B. Am Ende einer langen Sitzung ist die Ausgabe spürbar schlechter. Ob das relevant ist, hängt davon ab, was Sie bauen.

Latenzsensibles Routing

Interaktive Tools brauchen schnelle erste Token. Batch-Jobs können warten. Der Unterschied liegt meist in einem Faktor von fünf bei der Modellgröße.

Anwendungsfall Erster Token Komplett Maximale Modellgröße
Echtzeit-Chat < 200ms < 2s < 7B
Interaktive Tools < 500ms < 5s < 14B
Batch-Verarbeitung < 1s < 30s Beliebig
Forschung/Analyse < 2s < 60s Beliebig

Wenn Sie Token an einen Benutzer streamen, ist die Latenz des ersten Tokens das, was der Benutzer spürt. Ein 32B-Modell, das eine halbe Sekunde zum Start braucht, wirkt im Vergleich zu einem 1.5B-Modell, das sofort reagiert, träge.

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"

Die Latenzwerte sind grob – sie hängen von Ihrer Hardware, Quantisierung und Batch-Größe ab. Messen Sie auf Ihrer eigenen Einrichtung.

Fallback-Strategien

Modelle schlagen fehl. APIs raten-limitieren. Timeouts treten auf. Das Muster, das funktioniert, ist eine Fallback-Kette, geordnet vom besten zum zuverlässigsten:

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")

Das letzte Modell in der Kette sollte lokal sein. Es ist langsamer, wird aber nicht aufgrund eines Netzwerkproblems oder eines API-Schlüssels fehlschlagen.

Wann Routing hilft

Routing macht Sinn, wenn Ihre Arbeitslast gemischt ist. Wenn Sie Klassifikation, Zusammenfassung und Reasoning im selben System durchführen, spart ein Router Geld und Latenz.

Es macht keinen Sinn, wenn alles, was Sie tun, die gleiche Komplexität hat. Verwenden Sie einfach das Modell, das für diese Aufgabe gut ist. Der Router fügt Komplexität hinzu, die Sie nicht brauchen.

Frühes Prototyping ist ein weiterer Grund, es zu überspringen. Lassen Sie die Aufgabe mit einem Modell funktionieren und fügen Sie Routing hinzu, wenn Kosten oder Latenz tatsächlich zu einem Problem werden.

Kompromisse

Jede Routing-Strategie optimiert etwas und opfert etwas anderes:

  • Einzelnes Modell – einfachste Lösung, teuerste, konsistente Qualität
  • Fähigkeitsbasiert – bessere Kosten, höhere Qualität pro Aufgabe, moderate Komplexität
  • Kostensensibel – günstigste, variierende Qualität, moderate Komplexität
  • Latenzsensibel – schnellste, kann Qualität opfern, moderate Komplexität
  • Hybrid – das Beste aus allen Welten, komplexeste Implementierung

Produktionssysteme konvergieren meist auf Hybrid. Beginnen Sie mit fähigkeitsbasiertem Routing, fügen Sie Kostensensibilität hinzu, wenn die Rechnung kommt, und Latenzsensibilität, wenn Benutzer über Langsamkeit klagen.

Verwandte Themen

Abonnieren

Neue Beiträge zu Systemen, Infrastruktur und KI-Engineering.