Tutorial
Was ist AI Structured Output? Wie JSON Schema LLM-JSON zuverlässig macht
„Nur JSON“ im Prompt senkt nur die Wahrscheinlichkeit. Structured Output nagelt die Form beim Dekodieren fest; JSON Schema macht Felder, Typen und Enums zum Vertrag.
Ein Modell in die Pipeline zu hängen, das Unheimliche ist nicht schwache Prosa — es ist ein Rückgabewert, den der Code nicht fressen kann: fehlendes Komma, umbenanntes Feld, Zahl als Zeichenkette. Genau dafür gibt es Structured Output: Das Modell spricht die deklarierte Form, während es Tokens ausgibt, statt Prosa zu schreiben, aus der Sie JSON per Regex kratzen. JSON Schema ist die übliche schriftliche Form dieser Form. Danach wissen Sie, ob Sie an Syntax, Form oder fachlicher Wahrheit hängen — und dass ein Schema trotzdem eine lokale Prüfung braucht.
Warum JSON nur per Prompt unzuverlässig ist
„Nur JSON, keine Erklärung“ ist der häufigste Behelf. Manchmal wirkt er, weil er eine Präferenz in den Kontext schreibt. Unzuverlässig ist er, weil eine Präferenz keine Bindung ist: Das Modell kann das Objekt trotzdem in einen Markdown-Zaun packen, ein Pflichtfeld weglassen oder priority in das „natürlichere“ urgency verwandeln. Sobald der Downstream JSON.parse ausführt, ist der Fehler kein Textproblem — die ganze Kette steht.
Der leisere Fehler: „es parst, aber die Form stimmt nicht“. Sie erwarten, dass items ein Array ist, und bekommen ein Objekt; eine Zahl als Score, und bekommen "0.91". Der Code liest undefined oder konkateniert Strings, und der Bug knallt viel später. Ein Prompt stoppt diese Drift nicht, weil er illegale Tokens beim Dekodieren nie ablehnt.
Halten Sie Structured Output deshalb nicht für „einen strengeren Prompt“. Es ist Teil der Generierung: Der Server kompiliert das Schema zur Menge erlaubter Folgetokens, und das Modell kann keine unpassenden Klammern oder einen Schlüssel außerhalb der Liste ausgeben. Der Prompt erklärt die Aufgabe; das Schema besitzt die Form.
Welche Schicht Structured Output wirklich bindet
Denken Sie in drei Schichten. Mischen Sie zwei, und es wirkt, als „spinne das Modell“. Erste Schicht: Syntax — JSON, das parst. Zweite: Form — Namen, Typen, Pflichtfelder, Enums passen zum Schema. Dritte: Bedeutung — stimmt die Klasse, ist der Betrag echt? Structured Output deckt die ersten beiden. Die dritte bleibt immer Ihre.
| Stufe | Was Sie setzen | Was Sie wirklich bekommen |
|---|---|---|
| Prompt-Vereinbarung | „Nur JSON“ | Eine Präferenz, kein Vertrag |
| JSON-Modus | MIME-Typ oder json_object |
Wahrscheinlich gültiges JSON; Feldnamen bestimmt weiter das Modell |
| Schema-Modus | JSON Schema plus Strict-Schalter | Form, Typen, Pflichtfelder und Enums folgen dem Schema |
OpenAI beschreibt Structured Outputs als nächsten Schritt nach dem JSON-Modus: Beide können gültiges JSON liefern; nur Ersteres garantiert das gelieferte Schema. Offizieller Vergleich: Structured model outputs. Gemini zieht dieselbe Linie zwischen „nur JSON“ und „Felder laut Schema“; die Schalter stehen in der Gemini-API-JSON-Anleitung — dieser Artikel wiederholt die SDK-Details nicht.
Eine leicht übersehene Grenze: Sicherheitsablehnung, Abbruch oder fehlender Tool-Aufruf passen oft nicht in Ihr Erfolgsobjekt. Manche APIs liefern ein eigenes refusal oder leeren Inhalt. Das Schema bindet die Strecke, die „im Format spricht“, nicht „dieser Aufruf gelingt“.
Wie JSON Schema zum Vertrag wird
JSON Schema ist ein Vokabular für JSON-Dokumente: Typen, Pflichtfelder, Enums, Zahlenbereiche, Array-Elemente. Der Standardrundgang: Understanding JSON Schema. Am Modell bekommt dasselbe Vokabular einen zweiten Job: Es ist nicht mehr nur eine Nachprüfung — es verengt den Suchraum während der Generierung.
Für Engineering ist das Schema ein Vertrag von Compile- und Laufzeit. Pydantic, Zod und Swifts generierbare Typen landen meist in einem sprachunabhängigen JSON Schema, das Sie dem Cloud-Modell geben, loggen und als Fixture abspielen. Eine Feldtabelle, damit die App nicht totalCents, die API amount und der Prompt „Betrag“ sagt.
Schreiben Sie das Objekt, das Sie wirklich lesen, nicht ein Weltmodell. Jedes überflüssige optionale Feld ist eine Chance, es falsch oder leer zu füllen. Pflichtfelder gehören in required, geschlossene Mengen in enum, Zahlengrenzen in minimum / maximum. Ein description am Property ist meist stabiler als die Erklärung noch einmal im Prompt, weil Bindung und Dekodierung zusammenhängen.
Im Strict-Modus kommt oft eine Regel dazu: Objekte müssen additionalProperties: false setzen, und jedes deklarierte Feld kommt in required. Wirklich optionale Werte nicht „aus required streichen“ — erlauben Sie null. Sonst lässt das Modell den Schlüssel weg, während Ihr Code noch obj.field voraussetzt.
Wie die APIs ein Schema anbinden
Alle Anbieter sagen Structured Output; die Hüllfelder unterscheiden sich. Fragen Sie zuerst zwei Dinge: Bindet dieses Schema die Endantwort oder die Tool-Argumente? Unterstützt dieser Modell-Snapshot wirklich den Strict-Modus? Glauben Sie nicht, ein Doc-Schlüsselwort verhalte sich auf jedem Endpoint gleich.
OpenAI: json_schema plus strict
In Chat Completions setzen Sie response_format auf json_schema und schalten strict: true ein. Die Responses-API schreibt dasselbe unter ein Textformat-Feld. Die Schema-Regeln sind gleich, nur die Hülle ändert sich. Die Anfrage unten zieht ein Ticket: Kategorie als Enum, Konto nullable.
{
"model": "gpt-4o-2024-08-06",
"messages": [
{ "role": "system", "content": "Extract the ticket into the schema." },
{ "role": "user", "content": "Checkout 500s on a saved card. Account acct_8842." }
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "support_ticket",
"strict": true,
"schema": {
"type": "object",
"properties": {
"summary": { "type": "string" },
"category": {
"type": "string",
"enum": ["billing", "bug", "account", "other"]
},
"severity": { "type": "integer" },
"account_id": {
"anyOf": [{ "type": "string" }, { "type": "null" }]
}
},
"required": ["summary", "category", "severity", "account_id"],
"additionalProperties": false
}
}
}
}
Behandeln Sie die Antwort als „alles ist JSON“. Kratzen Sie nicht zuerst einen Codezaun per Regex. Der Parse-Helfer im SDK deserialisiert in ein typisiertes Objekt; behandeln Sie auch den Ablehnungszweig — ein Safety-Trip muss nicht zum Erfolgsschema passen.
Gemini und die anderen Stacks
Gemini erklärt „das ist JSON“ per MIME-Typ und zieht Felder mit responseSchema oder responseJsonSchema fest. Letzteres liegt näher am Standard-JSON-Schema und passt zu anyOf, $ref und Zahlenbereichen. Details und Python-/JS-Beispiele: das Gemini-Structured-Output-Tutorial.
Apples On-Device-Modelle nutzen @Generable — eine Form zur Compile-Zeit, keine per Hand getippte JSON-Schema-Datei. Sobald Sie den Prozess verlassen, HTTP rufen oder loggen, brauchen Sie weiter serialisierbares JSON. Wie sich die drei Ketten teilen: Apple-AI-Agenten und JSON. Nutzt ein externer Agent MCP oder REST, ist die Nutzlast fast immer JSON, und das Schema bleibt die Tabelle, die der Adapter ausrichten sollte.
Ein Schema, das Sie ausrollen können
Das Schema unten modelliert Ticket-Klassifikation: geschlossene Kategorie, ganzzahlige Priorität, String-Zusammenfassung. Das soll ein Schema besitzen — Form, nicht „muss dieses Ticket fachlich dringend sein“.
{
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": ["billing", "bug", "feature"],
"description": "Ticket category"
},
"priority": {
"type": "integer",
"minimum": 1,
"maximum": 5
},
"summary": {
"type": "string"
}
},
"required": ["category", "priority", "summary"],
"additionalProperties": false
}
Array-Elemente beschreiben Sie mit items. Für eine fest lange, tupelartige Liste sehen Sie im JSON-Schema-Pfad prefixItems an. Verschachtelte Objekte zuerst inline. Greifen Sie zu $defs + $ref erst, wenn dieselbe Struktur zum dritten Mal kommt oder ein Baumknoten auf sich zeigt. Zu frühe Abstraktion macht Fehler unlesbar: Lehnt der Server das Schema ab, starren Sie auf ein expandiertes Klumpenobjekt.
Beschreiben Sie die Struktur nicht einmal im Prompt und einmal im Schema. Doppelte Texte lassen das Modell zwischen zwei Geschichten schwanken und verbrennen Input-Tokens. Die Aufgabe bleibt im Prompt; Namen und Typen nur im Schema. Ändern lokale Typen ein Feld, muss das Request-Schema mit — sonst wachsen in Prod still extra oder fehlende Schlüssel.
Nach der Bindung trotzdem lokal prüfen
Structured Output beruhigt die Parse-Schicht stark. Es garantiert weder die richtige Klasse noch eine Zahl unter Ihrer Fachobergrenze. Ein Enum begrenzt die Menge; es verhindert keine falsche Wahl. Priorität 5 ist gültig; „eigentlich 2“ auch. Den kritischen Pfad stichproben oder Regeln drauflegen.
Im Betrieb behandeln Sie die Modellausgabe als gewöhnliches JSON. Zuerst JSON-Formatierung, um die Verschachtelung zu sehen, dann JSON validieren, um das Parsen zu bestätigen, und dasselbe Objekt in JSON Schema für eine zweite lokale Prüfung. Gegen einen Goldsatz JSON Diff, um Schlüsselreihenfolge oder nullable Drift auf einen Blick zu sehen.
Legen Sie drei Fixtures an: ticket.valid.json, ticket.missing-field.json, ticket.wrong-enum.json. Die erste bestätigt den Happy Path; die nächsten zwei, dass Ihre lokale Prüfung wirklich ablehnt. Fehler, die die Modellseite schon bindet, müssen lokal reproduzierbar bleiben — sonst merkt die Pipeline es offline, wenn Sie das Modell tauschen oder Strict ausmachen.
Häufige Fragen FAQ
Worin unterscheiden sich Structured Output und JSON-Modus?
Der JSON-Modus garantiert parsebares JSON. Structured Output garantiert zusätzlich das gelieferte JSON Schema: Namen, Typen, Pflichtfelder und Enums folgen dem Vertrag. Liest Ihr Code benannte Felder, nehmen Sie Letzteres.
Brauche ich bei einem Schema noch „nur JSON“?
Ein kurzer Satz ist in Ordnung. Kopieren Sie die Feldtabelle nicht in den Prompt. Die Form gehört dem Schema. Zwei Beschreibungen senken Qualität und verbrennen Kontingent.
Wie stelle ich optionale Felder im Strict-Modus dar?
Die meisten Strict-Implementierungen schließen Extra-Properties und machen jedes gelistete Feld Pflicht. Optionale Werte nullable machen — eine Union aus String oder null — statt den Schlüssel aus required zu streichen.
Kann das Fachliche falsch sein, obwohl das Schema passt?
Ja. Ein Schema besitzt Form, nicht Wahrheit. Falsche Klasse, halluzinierter Betrag, hartes Ausfüllen statt Ablehnung: alles kann gültiges JSON sein. In Prod bleiben Regeln, Stichproben oder ein menschlicher Blick.
Fazit und nächste Schritte
Structured Output ist kein Texttrick. Es macht JSON-Form aus einem Wunsch zur Dekodierbindung. JSON Schema ist die gängigste Schreibweise: Pflichtfelder, Enums, Bereiche und keine Extra-Schlüssel entscheiden, ob der Downstream stabil JSON.parse und die erwarteten Felder lesen kann. Schalternamen unterscheiden sich je API; die Schichten nicht — Syntax, Form, Bedeutung. Nicht vermischen.
Als Nächstes: ein kleines Schema schreiben, das Sie wirklich lesen, einen Extraktions- oder Klassifikationspfad im Strict-Modus durchziehen, dann den Rückgabewert im Browser lokal prüfen. Gemini-Request-Beispiele stehen in der vorigen Anleitung; wie Agent-Argumente zu JSON werden, im Apple-Stück.