Strukturierte Ausgabe (englisch Structured Output) ist eine Antwort in einer Form, die du vorher festgelegt hast: ein JSON-Objekt mit benannten Schlüsseln, eine Tabelle mit festen Spalten oder eine Vorlage mit jedes Mal denselben Überschriften. Du brauchst sie immer, wenn ein Programm die Antwort liest, und sie hilft auch, wenn ein Mensch liest, weil dann jede Antwort gleich aussieht und sich leicht überfliegen oder vergleichen lässt.
Der Kniff besteht darin, die Form so genau zu beschreiben, dass dem Modell nichts mehr zu entscheiden bleibt. Das Wort "JSON" allein ist keine Beschreibung. Der Block unten zieht Details aus einem Bug-Report. Vergleich eine Bitte um "die wichtigsten Details" mit einer, die das Schema ausbuchstabiert.
Hier sind die wichtigsten Details aus dem Bug-Report:
- Problem: Die App stürzt beim Exportieren von Projekten ab
- Auslöser: Tippen auf Exportieren bei Projekten mit mehr als 50 Fotos
- Seit: Dem letzten Update
- Plattform: Android 14
- App-Version: 3.2.0
- Auswirkung: Hoch, da es eine Lieferung an einen Kunden blockiert
Kleinere Projekte scheinen sich ohne Probleme exportieren zu lassen.
Die Freitext-Antwort ist korrekt und gut lesbar, aber keine zwei Durchläufe verwenden dieselben Labels, der Schweregrad ist ein Satz statt eines Werts, und ein Programm müsste raten, wo jedes Feld beginnt. Die JSON-Antwort kann direkt in einen Bug-Tracker. Beachte, dass die Antwort trotzdem in einem Codeblock ankam: Chat-Apps verpacken JSON meist so, und das spielt eine Rolle, wenn du es im Code parst.
Wie du nach JSON fragst
Eine gute JSON-Anfrage beantwortet jede Frage, die das Modell sonst für dich beantworten würde:
- Jeder Schlüssel, exakt geschrieben. Schreib die Schlüsselnamen in Anführungszeichen, so wie sie erscheinen müssen. Sag "genau diese Schlüssel", damit das Modell keine zusätzlichen einfügt.
- Der Typ jedes Werts. String, Zahl, Boolean, Array von Strings, verschachteltes Objekt.
- Die erlaubten Werte für jedes Feld mit fester Auswahl, etwa Schweregrad oder Kategorie. Ohne die Liste bekommst du über vier Durchläufe "High", "high", "severe" und "P1".
- Was passiert, wenn im Input ein Wert fehlt. Wenn du nicht "null, wenn nicht angegeben" sagst, füllt das Modell die Lücke gern mit einer plausiblen Vermutung, und eine geratene App-Version sieht genauso aus wie eine echte.
- Nichts drumherum. "Gib nur das JSON zurück, ohne Text davor oder danach" entfernt den freundlichen Einleitungssatz.
Wenn die Form verschachtelt oder ungewöhnlich ist, funktioniert ein vollständiges Beispielobjekt besser als eine Beschreibung. Das ist Few-Shot-Prompting, angewendet aufs Format. Halte die Werte im Beispiel klar verschieden vom echten Input, damit das Modell sie nicht kopiert.
Ein wiederverwendbarer Extraktions-Prompt
Dieser Block enthält dieselbe Art Anfrage, aufgeteilt in Bausteine. Schalte den Format-Baustein aus, und das Modell liefert trotzdem JSON, weil die Vorgaben es verlangen, aber es wählt eigene Schlüsselnamen, etwa title statt job_title, und Code, der deine Schlüssel erwartet, bricht. Der Vorgaben-Baustein hält das Modell davon ab, eine halbe Telefonnummer zu ergänzen oder eine Firma aus einer E-Mail-Domain abzuleiten. Füg eine echte Signatur ins Input-Feld ein, um es zu testen.
{
"name": "string",
"job_title": "string or null",
"company": "string or null",
"email": "string or null",
"phone": "string or null"
}{
"name": "Priya Nair",
"job_title": "Leiterin Data",
"company": "Northwind Labs",
"email": "priya.nair@northwind.example",
"phone": null
}
Tabellen und feste Vorlagen
Strukturierte Ausgabe ist nicht nur etwas für Programme. Wenn du die Antwort selbst liest, bringt eine Markdown-Tabelle oder eine feste Vorlage denselben Vorteil: Du weißt, wo jede Information stehen wird, bevor du hinschaust.
| Typ | Geordnet | Veränderbar | Erlaubt Duplikate | Typische Verwendung |
|---|---|---|---|---|
| list | Ja | Ja | Ja | Eine Folge, die du erweiterst, kürzt oder sortierst |
| tuple | Ja | Nein | Ja | Eine feste Gruppe von Werten, etwa Koordinaten |
| set | Nein | Ja | Nein | Duplikate entfernen und schnell prüfen, ob etwas enthalten ist |
Eine Vorlage funktioniert bei längerem Text genauso: Gib die Überschriften in ihrer Reihenfolge vor und sag, was unter jede gehört. "Antworte mit drei fetten Labels: Ursache, Lösung, So prüfst du es" liefert jedes Mal dieselben drei Labels, und dadurch lässt sich ein Stapel Antworten leicht vergleichen.
JSON-Modus in der API
Mehrere Modell-APIs haben eine Einstellung, die syntaktisch gültiges JSON erzwingt. Im OpenAI Python SDK ist das response_format. Der JSON-Modus verlangt, dass das Wort "JSON" irgendwo in deinen Nachrichten vorkommt, deshalb nennt der System-Prompt unten es und listet die Schlüssel auf.
import json
from openai import OpenAI
client = OpenAI()
MODEL = "your-model-id" # e.g. from your provider's model list
report_text = "Since yesterday's update the app crashes when I tap Export..."
response = client.chat.completions.create(
model=MODEL,
response_format={"type": "json_object"},
messages=[
{
"role": "system",
"content": (
"Extract the bug report into JSON with the keys "
"summary (string), severity (one of low, medium, high, critical) "
"and steps_to_reproduce (array of strings)."
),
},
{"role": "user", "content": report_text},
],
)
data = json.loads(response.choices[0].message.content)
Der JSON-Modus stellt sicher, dass sich der Text parsen lässt (außer die Antwort wird am Token-Limit abgeschnitten), nicht dass er zu deinem Schema passt. Ein Schlüssel kann trotzdem fehlen, oder ein Schweregrad kann trotzdem "urgent" lauten. Mehrere Anbieter akzeptieren außerdem ein vollständiges JSON Schema, als Ausgabeformat oder als Eingabeschema einer Tool-Definition (Function Calling), und manche dieser Modi beschränken die Antwort auf das Schema. Schau in der Dokumentation deines Anbieters nach dem genauen Parameter, denn diese Funktionen unterscheiden sich zwischen den APIs.
Validiere das Ergebnis im Code
Behandle das JSON des Modells wie jeden Input von außerhalb deines Programms: Parse es, dann prüf es. Das Parsen fängt kaputte Syntax ab. Die Prüfung fängt ein gültiges Objekt mit falschem Inhalt ab.
ALLOWED_SEVERITIES = {"low", "medium", "high", "critical"}
def problems(data):
if not isinstance(data, dict):
return ["the answer must be a JSON object"]
found = []
if not isinstance(data.get("summary"), str):
found.append("summary must be a string")
if data.get("severity") not in ALLOWED_SEVERITIES:
found.append("severity must be low, medium, high or critical")
steps = data.get("steps_to_reproduce")
if not isinstance(steps, list) or not all(isinstance(s, str) for s in steps):
found.append("steps_to_reproduce must be an array of strings")
return found
Wenn die Prüfung fehlschlägt, behebt ein einziger neuer Versuch das oft: Schick dem Modell seine eigene Ausgabe zusammen mit der Liste der Probleme und bitte um korrigiertes JSON. Begrenze die Zahl der Versuche und protokolliere die Fehlschläge, denn ein Feld, das oft scheitert, ist ein Zeichen, dass der Prompt unklar ist. In größeren Projekten ersetzt eine Validierungsbibliothek wie Pydantic oder ein JSON-Schema-Validator die handgeschriebene Funktion.
Zwei weitere Gewohnheiten verhindern stille Fehler. Setz das Token-Limit der Ausgabe hoch genug für die größte Antwort, die du erwartest, denn ein abgeschnittenes Objekt lässt sich nie parsen. Und wenn der Input lang ist oder von Nutzern kommt, grenz ihn mit Trennzeichen oder XML-Tags von deinen Anweisungen ab, damit Text darin seltener als Anweisung gelesen wird. Wenn ein Prompt sowohl nachdenken als auch JSON erzeugen muss, denk an Prompt Chaining: Lass einen Schritt im Freitext denken und einen zweiten das Ergebnis in die Struktur überführen.
Häufig gestellte Fragen
Wie bringe ich ChatGPT dazu, JSON auszugeben?
Sag, dass die Antwort JSON sein muss, liste jeden Schlüssel mit seinem Typ auf und nenn die erlaubten Werte für jedes Feld mit fester Auswahl. Ergänze "Gib nur das JSON zurück, ohne Text davor oder danach." Schalte in der API außerdem den JSON-Modus mit response_format={"type": "json_object"} ein; dafür muss das Wort JSON in deinen Nachrichten vorkommen.
Warum schreibt das Modell Text um das JSON herum?
Chatmodelle sind auf Gespräche trainiert, deshalb beginnen sie oft mit einem Satz wie "Hier ist das JSON" oder packen das Objekt in einen Markdown-Codeblock. Bitte nur um das JSON, und nutz im Code entweder den JSON-Modus der API oder entfern einen umgebenden Codeblock vor dem Parsen.
Was ist der JSON-Modus?
Der JSON-Modus ist eine API-Einstellung, die das Modell syntaktisch gültiges JSON erzeugen lässt, solange die Antwort nicht am Token-Limit der Ausgabe abgeschnitten wird. Er sorgt nicht dafür, dass das Modell deinem Schema folgt: Schlüssel können trotzdem fehlen, falsch geschrieben sein oder den falschen Typ haben. Manche Anbieter bieten zusätzlich einen strengeren Modus an, der ein vollständiges JSON Schema annimmt und die Ausgabe darauf beschränkt.
Kann ein LLM immer gültiges JSON zurückgeben?
Nicht allein durch einen Prompt. Auch eine klare Anweisung scheitert hin und wieder, und eine Antwort, die am Token-Limit abgeschnitten wird, ist immer ungültig. Parse jede Antwort mit einem echten JSON-Parser, prüf die Felder, die du brauchst, und versuch es erneut oder brich deutlich ab, wenn die Prüfung fehlschlägt.