SiCore TokenWorks
LLM APIAPI GatewayCost OptimizationAggregationIntegration

Wie Sie zwischen LLM-Anbietern wechseln, ohne Ihren Code zu ändern

SiCore TokenWorks Team·2026-09-03

Die meisten Menschen beginnen ein Projekt nicht mit dem Gedanken an Anbieterportabilität. Sie holen sich einen Schlüssel von dem Anbieter, bei dem die Anmeldung am einfachsten ist, schreiben die Integration und liefern aus. Ein paar Monate später lesen sie einen Benchmark, oder sie öffnen eine Rechnung, oder sie stoßen an ein Rate Limit, und sie wollen etwas anderes ausprobieren. Genau dann zeigt sich der Schmerz, weil sie Annahmen über den ersten Anbieter in die HTTP-Schicht eingebaut haben.

Die Lösung ist keine Abstraktionsbibliothek. Es ist ein Wire-Format. Die OpenAI Chat Completions API ist still und leise zum Standardprotokoll für die Kommunikation mit LLMs geworden, und sobald Sie dagegen schreiben, ist der Wechsel des Anbieters größtenteils eine Sache von zwei Strings, die geändert werden müssen.

Die API, die alle kopiert haben

OpenAI hat einen einfachen Vertrag definiert: Sie senden JSON per POST an /v1/chat/completions, und Sie erhalten einen choices[0].message.content-String zurück. Die Anfrage sieht so aus:

curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Explain DNS in one paragraph"}]
  }'

Fast jedes große Modell spricht jetzt diesen Dialekt. DeepSeek, Qwen, ERNIE, Doubao und die anderen stellen alle einen Endpunkt bereit, der denselben Body akzeptiert und dieselbe Struktur zurückgibt. Das bedeutet, dass Ihr Client-Code sich nicht darum kümmert, wer auf der anderen Seite steht. Sie können den model-String und den Endpunkt austauschen, und sonst ändert sich nichts.

Hier ist derselbe Aufruf, gerichtet an einen Aggregator, der mehrere dieser Modelle unter einer einzigen Base-URL führt:

curl https://api.token8341.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKENWORKS_API_KEY" \
  -d '{
    "model": "deepseek-chat",
    "messages": [{"role": "user", "content": "Explain DNS in one paragraph"}]
  }'

Ein Client, viele Modelle

In Python instanziieren Sie normalerweise das OpenAI SDK einmal und übergeben pro Anfrage einen Modellnamen. Wenn Ihr Anbieter die kompatible API unterstützt, setzen Sie base_url einmal und lassen alles andere identisch:

from openai import OpenAI

client = OpenAI(
    base_url="https://api.token8341.com/v1",
    api_key="sk-your-tokenworks-key",
)

def ask(model: str, prompt: str) -> str:
    resp = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": prompt}],
    )
    return resp.choices[0].message.content

# Same function, three different model families.
print(ask("gpt-4o", "Summarize this log for me."))
print(ask("deepseek-chat", "Summarize this log for me."))
print(ask("qwen-max", "Summarize this log for me."))

Die Funktion ändert sich nicht. Der Modell-String ändert sich. Das ist der ganze Trick. Streaming funktioniert auf dieselbe Weise:

stream = client.chat.completions.create(
    model="deepseek-chat",
    messages=[{"role": "user", "content": "Write a haiku about databases"}],
    stream=True,
)
for chunk in stream:
    delta = chunk.choices[0].delta.content or ""
    print(delta, end="")

Function Calling, JSON-Modus und Embeddings laufen alle über dieselbe kompatible Oberfläche, sodass Sie beim Wechsel nicht auf einfachen Chat beschränkt sind.

Was Ihnen der Wechsel nicht bringt

Ich möchte klarstellen, welcher Teil sich nicht von selbst ändert. Der Transport ist portabel; die Modelle sind es nicht.

Verschiedene Modelle reagieren unterschiedlich auf Prompts. Ein System-Prompt, der auf GPT-4o abgestimmt ist, kann bei einem Reasoning-Modell, das eine andere Struktur möchte, schlechter abschneiden. Kontextfenster unterscheiden sich, manchmal erheblich: Ein Modell nimmt vielleicht 128k Tokens auf, während ein anderes 32k aufnimmt. Auch die Tokenizer unterscheiden sich, sodass dasselbe Dokument bei jedem Modell eine unterschiedliche Anzahl von Tokens kostet. Die maximale Ausgabelänge ist ein weiterer Parameter, der pro Modell gilt, nicht pro Protokoll.

„Wechseln ohne Codeänderung" bedeutet also eigentlich „Wechseln ohne Neuschreiben Ihres HTTP-Clients". Sie schulden sich selbst trotzdem einen Evaluierungslauf, bevor Sie Produktionsverkehr auf ein neues Modell richten. Die gute Nachricht ist, dass die kompatible API diese Evaluierung günstig durchzuführen macht, weil das Harness nur eine Schleife über Modellnamen ist.

Ein praktisches Muster

Was ich in Nebenprojekten tatsächlich mache, ist, eine kleine Konfigurationstabelle zu pflegen, nicht Codeänderungen:

MODELS = {
    "fast": "deepseek-chat",
    "smart": "qwen-max",
    "frontier": "gpt-4o",
}

def run(task, prompt):
    return ask(MODELS[task], prompt)

Sie wollen für die fast-Spur ein günstigeres Modell ausprobieren? Ändern Sie eine Zeile. Sie wollen auf einen zweiten Anbieter zurückfallen, wenn der erste rate-limited ist? Fangen Sie die Exception ab und versuchen Sie es mit dem nächsten Modell-String erneut. Nichts davon berührt die Konstruktion der Anfrage.

Dieses Fallback-Muster ist der Punkt, an dem ein Multi-Modell-Endpunkt seinen Wert beweist. Mit einer Base-URL und einem Schlüssel können Sie über Anbieter hinweg routen, wiederholen und A/B-testen, und das alles über dieselben zwei Zeilen Client-Setup, die Sie am ersten Tag geschrieben haben.

Antwort-Eigenheiten, auf die Sie achten sollten

Der Transport ist kompatibel, aber ein paar Unterschiede auf Antwortebene schlagen dennoch durch. Reasoning-Modelle geben manchmal ein zusätzliches Feld wie reasoning_content neben der normalen Nachricht zurück. Code, der choices[0].message.content liest, funktioniert unabhängig davon weiter, aber Sie möchten diesen Reasoning-Text möglicherweise in einer Debug-Ansicht sichtbar machen. Auch Fehlermeldungen variieren: Ein Anbieter gibt einen hilfreichen insufficient_quota-String zurück, ein anderer gibt einen bloßen 429 ohne Body zurück. Wenn Sie Retries bauen, behandeln Sie jeden 429 oder 5xx als „zurückziehen und erneut versuchen", anstatt anbieterspezifischen Text zu parsen.

Nichts davon ist ein Grund, an einen einzigen Anbieter gebunden zu bleiben. Es ist ein Grund, Ihre Fehlerbehandlung generisch zu halten und Ihre Modellwahl zu einer Variable zu machen.

Das ist die Position von SiCore TokenWorks: ein OpenAI-kompatibler Endpunkt unter https://api.token8341.com/v1, bei dem der Modell-String das Einzige ist, was sich ändert, wenn Sie zwischen GPT-4o, Claude, Gemini, DeepSeek, Qwen, ERNIE, Doubao, Spark und Pangu wechseln.