200 OK kommt ohne Inhalt an, ein Stream bricht mitten
in einem Tool-Aufruf ab. Diese Seite beschreibt die verbindliche Behandlung dieser Fälle: was der
Aufrufer erhält, ob GoModel einen Retry oder ein Failover durchführt und wo das Ereignis
in Ihrem Monitoring auftaucht.
Die Einstellungen für Retries und den Circuit Breaker finden Sie unter
Ausfallsicherheit. Zur Wahl eines Backup-Modells siehe
Failover.
Schema-Drift
Dass ein Provider sein Response-Format ändert, ist der Fehler, zu dem Gateways meist schweigen – denn darauf zu reagieren bedeutet, eine Vorstellung davon zu haben, wie eine Response aussehen sollte. Die Vorstellung von GoModel ist das OpenAI-Schema, großzügig angewendet: Unbekannte Elemente bleiben erhalten, bekannte Elemente werden normalisiert, und nur eine Response, die sich überhaupt nicht lesen lässt, wird zum Fehler.
Passthrough-Endpunkte sind von all dem ausgenommen:
/p/{provider}/... leitet
die Bytes des Providers weiter, ohne die Vorstellungen von GoModel anzuwenden. Ein Client, der
mit Drift lieber selbst umgeht, kann das so tun.
Scheinbar erfolgreiche leere Responses
Ein200 ohne brauchbaren Inhalt ist ein Fehler im Gewand eines Erfolgs. Die
Frage ist, ob sich dafür ein Failover lohnt – und für Chat Completions
lautet die Antwort ja.
Jede Zeile protokolliert eine Warnung mit Provider, Modell und Grund und
erhöht
gomodel_empty_responses_total. Da gomodel_requests_total
die ausgelieferten Zeilen als Erfolge zählt, ist dieser Zähler der einzige Ort, an dem die
nicht fehlschlagenden Zeilen auftauchen.
Ein Hintergrund- oder noch laufender
/v1/responses-Aufruf enthält legitimerweise
weder Output noch Usage und wird nie als leer gemeldet.Streaming-Fehler
Ein Stream, der bereits Bytes gesendet hat, kann nicht wiederholt werden – der Client hat schon einen Teil einer Antwort. Die Regel von GoModel lautet daher: Wo möglich, vor dem ersten Byte entscheiden, und wo nicht, das Abschneiden explizit machen.
Die Wartezeit auf das erste Byte zählt nie zum Idle-Timeout, sodass ein langsames
Reasoning-Modell sicher ist, bis der Provider etwas sendet. Danach startet jedes
Byte den Timer – auch ein Keep-Alive-Kommentar –, und jedes weitere Byte
startet ihn neu. Das Limit begrenzt also die Lücke zwischen Lesevorgängen, nicht die Länge
der Response. Sobald das erste Byte gesendet ist, steht die Response auf
200 fest. Deshalb kann ein Hängenbleiben ab diesem Zeitpunkt nur noch In-Band gemeldet werden
und nie als Status. Details:
Stream-Abschluss,
Idle-Timeout,
Failover beim Stream-Start.
Transport- und Statusfehler
Die üblichen Fälle, der Vollständigkeit halber.
Streaming-Requests werden nach dem Absenden nie wiederholt, und Passthrough-Requests
nur, wenn eine Wiederholung sicher ist (
GET, HEAD, OPTIONS, PUT oder jeder
Request mit einem Idempotency-Key).
Stille Fehler erkennen
Die Zeilen oben, bei denen kein Failover erfolgt, sind diejenigen, die einen Alert brauchen, denn per Definition beschwert sich sonst nichts:gomodel.client.empty_responses exportiert,
wobei der Grund als error.type statt als reason ankommt, zusammen mit
gomodel.provider.name und gen_ai.request.model. Siehe
Prometheus-Metriken und
OpenTelemetry.
Das Dashboard liest dieselben Signale: Ein Modell, dessen letzte Requests wiederholt
fehlschlagen, markiert seinen Provider als Degraded, auch wenn die Modellerkennung noch
erfolgreich ist. Genau so fällt ein Upstream auf, der Modelle problemlos auflistet, aber
echte Aufrufe nicht bedient.
Ausfälle der Modellerkennung
Die/models-Liste eines Providers kann fehlschlagen, während die Inferenz weiterhin funktioniert. GoModel
routet dann in dieser Reihenfolge weiter mit:
- Dem letzten Bestand, den es abgerufen oder aus seinem Cache geladen hat.
- Konfigurierten Modellen (
<PROVIDER>_MODELS, sieheCONFIGURED_PROVIDER_MODELS_MODE). - Bei einem Provider mit seiner Standard-Base-URL der Liste aus dem Modellkatalog für seinen Provider-Typ.
PROVIDER_RECHECK_INTERVAL Sekunden erneut geprüft
(Standardwert 60), und die Live-Liste ersetzt den Ersatz, sobald eine Abfrage
erfolgreich ist. Gibt es nichts, womit Requests bedient werden können, liefern sie 503, damit Clients es erneut versuchen, und
/health/ready meldet degraded mit "models": "down", während die Instanz
in der Rotation bleibt.
Um nie von der Modellerkennung abhängig zu sein, listen Sie die Modelle selbst auf und setzen
CONFIGURED_PROVIDER_MODELS_MODE=allowlist:
Wenn GoModel selbst ausfällt
Ein Gateway im Request-Pfad tauscht das Provider-Risiko gegen ein Gateway-Risiko. Ehrliche Zahlen sind daher wichtiger als Beschwichtigung. GoModel fällt laut aus, nicht still: Eine ausgefallene Instanz liefert Ihnen „Connection refused“ oder ein502 von der vorgeschalteten Komponente, nie eine plausibel aussehende falsche Antwort.
Es ist ein einzelnes statisches Binary mit zustandslosem Request-Pfad, den Probes /health und
/health/ready und einem 10-sekündigen Graceful Drain bei SIGTERM. Rollierende
Neustarts und mehrere Replikas hinter einem Load Balancer funktionieren also bereits heute.
Dieser Drain ist eine Grenze, keine Abschlussgarantie: Er ist für die
Requests bemessen, die tatsächlich in zehn Sekunden abgeschlossen werden können, und bei allem, was danach
noch offen ist – vor allem bei einem laufenden Stream –, wird die Verbindung getrennt. Bei
langlebigem Traffic leeren Sie die Verbindungen am Load Balancer, lassen die Replikas
lange genug überlappen, um eine Generierung abzudecken, und lassen Clients Retries durchführen.
Was pro Instanz gilt und daher nicht zwischen Replikas geteilt wird: der Zustand des Circuit
Breakers, Rate-Limit-Zähler, Request-Health-Fenster und Sticky
Sessions. Was das für Ihre Topologie bedeutet, beschreibt der Produktionsleitfaden.
Wenn GoModel ausgefallen ist und Traffic sofort fließen muss, richten Sie
base_url wieder direkt auf den Provider – die API ist in
beide Richtungen OpenAI-kompatibel. Bis GoModel wieder läuft, verlieren Sie Routing, Failover und Logging –
und weil Rate-Limits und Budgetprüfungen im Request-Pfad von GoModel laufen und nicht in dem
des Providers, regeln sie dann überhaupt nichts mehr.