Structured Outputs mit OpenAI-compatible APIs: JSON-Schema-Guide
Praxisleitfaden für strikte JSON Schemas mit Responses und Chat Completions, inklusive Validierung, Fehlerbehandlung und Routentests.
Structured Outputs ermöglichen JSON-Antworten, die einem definierten Schema folgen, statt ein Modell lediglich per Prompt um „JSON“ zu bitten. Bei einer OpenAI-compatible API kann dasselbe JSON Schema über Responses oder Chat Completions verwendet werden. Die äußeren Request-Felder unterscheiden sich jedoch, und Modell sowie Route müssen konkret geprüft werden.
Ein sicheres Produktionsmuster besteht aus drei Schichten: strict verwenden, wenn das Modell es unterstützt, das Ergebnis in der Anwendung erneut parsen und validieren und anschließend deterministische Geschäftsregeln anwenden. Schema-Konformität verhindert viele Formatfehler, beweist aber keine faktische oder semantische Richtigkeit.
Structured Outputs ist nicht dasselbe wie JSON Mode
| Methode | Gültiges JSON | Erzwingt das Schema | Typischer Einsatz |
|---|---|---|---|
| Nur Prompt | Nicht garantiert | Nein | Prototypen, die Parsing-Fehler tolerieren |
| JSON Mode | Bei Support und vollständiger Ausgabe | Nein | Flexibles JSON mit Validierung in der Anwendung |
Structured Outputs mit strict: true |
Mit Completion- und Refusal-Behandlung | Innerhalb des unterstützten Subsets | Typisierte Extraktion und Workflows |
Der OpenAI-Leitfaden zu Structured Outputs empfiehlt diese Variante vor JSON Mode, wenn Modell und Endpoint sie unterstützen. Ein strukturiertes Response Format dient einer vorhersagbaren Datenantwort; Function Calling fordert dagegen eine Aktion der Anwendung an. Strikte Schemas können ähnlich sein, Call IDs und Ergebnisnachrichten gehören aber zu einem anderen Vertrag.
Das Schema vor dem Endpoint definieren
Für die Triage eines Support-Tickets werden vier Felder benötigt:
{
"type": "object",
"properties": {
"category": { "type": "string", "enum": ["billing", "technical", "account"] },
"priority": { "type": "integer", "minimum": 1, "maximum": 3 },
"requires_human": { "type": "boolean" },
"summary": { "type": "string" }
},
"required": ["category", "priority", "requires_human", "summary"],
"additionalProperties": false
}
Required Properties und additionalProperties: false schaffen ein stabiles Objekt. Sie machen jedoch nicht jedes JSON-Schema-Keyword portabel. OpenAI dokumentiert ein Subset; andere OpenAI-compatible Anbieter können ein anderes Subset oder keinen Strict Schema Mode unterstützen.
Das Schema mit der Responses API senden
Responses erwartet das Schema unter text.format:
{
"model": "<MODEL_WITH_VERIFIED_STRUCTURED_OUTPUT_SUPPORT>",
"input": "The customer was charged twice and wants a refund.",
"text": {
"format": {
"type": "json_schema",
"name": "support_ticket",
"schema": {
"type": "object",
"properties": {
"category": { "type": "string", "enum": ["billing", "technical", "account"] },
"priority": { "type": "integer", "minimum": 1, "maximum": 3 },
"requires_human": { "type": "boolean" },
"summary": { "type": "string" }
},
"required": ["category", "priority", "requires_human", "summary"],
"additionalProperties": false
},
"strict": true
}
}
}
Der Request geht mit Authorization: Bearer <YOUR_API_KEY> an POST https://modelflare.dev/v1/responses. Generierter Inhalt befindet sich in typisierten Output Items. SDKs können Helper für aggregierten Text oder Parsed Output anbieten; ein HTTP-Client sollte den fertigen Text dennoch explizit lokalisieren und als JSON parsen.
Dasselbe Schema mit Chat Completions senden
Chat Completions verwendet response_format.json_schema:
{
"model": "<MODEL_WITH_VERIFIED_STRUCTURED_OUTPUT_SUPPORT>",
"messages": [
{ "role": "user", "content": "The customer was charged twice and wants a refund." }
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "support_ticket",
"schema": {
"type": "object",
"properties": {
"category": { "type": "string", "enum": ["billing", "technical", "account"] },
"priority": { "type": "integer", "minimum": 1, "maximum": 3 },
"requires_human": { "type": "boolean" },
"summary": { "type": "string" }
},
"required": ["category", "priority", "requires_human", "summary"],
"additionalProperties": false
},
"strict": true
}
}
}
Der JSON-Text liegt normalerweise in choices[0].message.content und muss geparst werden.
| Zweck | Responses API | Chat Completions |
|---|---|---|
| Schema-Container | text.format |
response_format.json_schema |
| Format-Typ | text.format.type |
response_format.type |
| Name | text.format.name |
response_format.json_schema.name |
| Schema | text.format.schema |
response_format.json_schema.schema |
| Strict | text.format.strict |
response_format.json_schema.strict |
| Ergebnis | Typed Output Items / Helper | choices[0].message.content |
Modelflare konvertiert beide Wrapper auf unterstützten OpenAI/Codex-Routen. Diese Konvertierung erzeugt aber keinen Structured-Outputs-Support in einem Upstream-Modell, das die Funktion nicht besitzt. Bei Raw Chat Completions Pass-through bleibt der Provider-Vertrag maßgeblich.
Struktur und Bedeutung getrennt validieren
{
"category": "billing",
"priority": 2,
"requires_human": true,
"summary": "Customer reports a duplicate charge and requests a refund."
}
Strukturelle Validierung
Ein JSON-Schema-Validator prüft Required Properties, unerwartete Properties, Typen, Enum und Wertebereiche. Auch bei zugesicherter Strict Adherence schützt die Validierung vor inkompatiblen Routen, Integrationsfehlern, Truncation und späteren Vertragsänderungen.
Semantische und geschäftliche Validierung
Das Schema weiß nicht, ob eine Doppelabbuchung wirklich stattgefunden hat, ob priority: 2 korrekt ist oder wer eine Erstattung genehmigen darf. Das Modellobjekt ist ein Vorschlag, der mit autoritativen Daten verglichen werden muss. Berechtigungen, Finanzlimits und Sicherheitsregeln bleiben in deterministischem Code. Ein strukturell gültiges Objekt darf keine solche Grenze umgehen.
Unvollständige und außergewöhnliche Ausgaben behandeln
Refusals
Status und Refusal-Darstellung müssen vor dem JSON-Parsing geprüft werden. Eine Sicherheitsablehnung ist kein Parsing-Fehler.
Truncation und Output Limits
Endet die Generierung vor dem Objektabschluss, kann das Schema die fehlenden Zeichen nicht rekonstruieren. Completion Status und Stop Reason prüfen und ein ausreichend großes, aber begrenztes Output Limit setzen.
Nicht unterstützte Schema-Keywords
Mit Objects, Arrays, Primitive Types, Enums, Required und expliziten Additional Properties beginnen. References, rekursive Strukturen, komplexe Unions und erweiterte Validatoren erst nach Prüfung der aktuellen Provider-Dokumentation einsetzen.
Latenz beim ersten Schema
Ein neuer Schema-Entwurf kann serverseitig vorverarbeitet und gecacht werden. Stabile, versionierte Schemas wiederverwenden und First Use getrennt vom Steady State messen.
Inkompatibles Modell oder Route
Ein Endpoint kann normale Chat Completions akzeptieren, aber json_schema ablehnen oder strict ignorieren. Ein 200 mit JSON beweist keine Strict Adherence. Negative und grenzwertige Inputs gehören zum Test.
Vor Produktion eine Kompatibilitätsmatrix ausführen
| Test | Aufzuzeichnende Evidenz |
|---|---|
| Minimales Required Object | Status, Modell, Route, Parsed Object, Validierung |
| Jeder Enum-Wert | Erzeugung und Parsing aller erlaubten Werte |
| Fehlende Information | Begrenzter Ersatzwert oder Rückfrage |
| Safety Input | Refusal-Darstellung und Anwendungshandling |
| Niedriges Output Limit | Completion Status und Truncation |
| Nicht unterstütztes Feature | Expliziter Fehler oder stilles Ignorieren |
| Responses- und Chat-Wrapper | Gleichwertige Anwendungsobjekte |
| Wiederholtes stabiles Schema | First Use gegenüber Steady State |
Schema, Prompt, Region, Streaming Mode und Output Limit müssen bei Vergleichen konstant bleiben. Da Provider-Verhalten und Modelle sich ändern, gehört das Testdatum zur Evidenz.
Den Endpoint nach dem Workflow-Test wählen
Responses passt zu typisierten Output Items, Responses Streaming oder einem größeren Tool-Workflow. Chat Completions passt zu einer stabilen Message-Integration, wenn response_format auf der konkreten Route unterstützt wird. Siehe Responses API vs. Chat Completions.
Unabhängig vom Endpoint:
- eine versionierte Source of Truth für JSON Schema behalten;
- nur den Wrapper, nicht die Bedeutung ändern;
- die vollständige Antwort validieren;
- danach deterministische Geschäftsregeln anwenden;
- Parsing-, Refusal-, Truncation- und Kompatibilitätsfehler getrennt überwachen.
Für die Migration dient der OpenAI-Compatible API Guide, für unvollständige Streams der AI API Streaming Guide. Unter Models & Pricing die aktuelle Oberfläche prüfen und Structured Outputs auf genau der Route testen, die der API Key verwendet.
Structured Outputs machen eine Modellantwort zu einer verlässlicheren Anwendungsschnittstelle. Sie ersetzen keine Faktenprüfung, Autorisierung oder Billing-Logik. „OpenAI-compatible“ bleibt eine pro Feature zu prüfende Aussage.