Kvmzen Blog
← Zurück zu Technologie in der Praxis

OpenAI Structured Outputs: So erzeugen Sie JSON, das wirklich zum JSON Schema passt

Technologie in der Praxis ·ca. 12 Min. Lesezeit

JSON Schema und eine strukturierte Datenpipeline im Code-Editor

Sobald Sie die Modellausgabe in eine Datenbank, ein Formular oder einen nachgelagerten Agent einspeisen, reicht der Prompt-Hinweis „bitte JSON zurückgeben“ nicht mehr. OpenAI Structured Outputs zwingt die Ausgabe per eingeschränkter Dekodierung auf das von Ihnen gelieferte JSON Schema: Felder fehlen nicht, Enums werden nicht frei erfunden, Typen wechseln nicht zwischen String und Zahl. Dieser Leitfaden richtet sich an Teams, die Extraktion, Ticket-Klassifikation, Bewertungen und mehrstufige Workflows bauen – vom JSON Mode bis zu strict: true.

100%
Schema-Konformität auf unterstützten Modellen
2
Einstiege: Chat Completions / Responses
10
Maximale Objektschachtelung

Warum JSON Mode nicht reicht

JSON Mode (type: "json_object") garantiert nur, dass ein JSON-Parser die Antwort einlesen kann. Schlüsselnamen, Pflichtfelder, Enum-Mengen und Zahlentypen sind nicht abgesichert. In der Produktion kippt die Pipeline typischerweise an drei Stellen: severity fehlt, 42 kommt als "42", oder das Modell erfindet außerhalb des enum einen Wert wie urgent-plus. Sobald ein typsicherer Parser folgt, scheitert der Lauf an zufälligen Samples.

Fähigkeit JSON Mode Structured Outputs
Gültiges JSON Ja Ja
Einhaltung Ihres JSON Schema Nein (nur Prompt) Ja (eingeschränkte Dekodierung)
Aktivierung json_object json_schema + strict: true
Typische Modelle Frühere GPT-4o- / GPT-3.5-Varianten gpt-4o-2024-08-06, gpt-4o-mini und neuere Snapshots
Ablehnungen Kann weiterhin „JSON-ähnliche“ Ablehnungstexte liefern Eigenes Feld refusal

Offiziell gilt Structured Outputs als Weiterentwicklung von JSON Mode: neue Projekte sollten ein Schema setzen, statt nach Parserfehlern dreimal zu wiederholen. Wenn Sie Token-Kosten verschiedener Modelle vergleichen, hilft der API-Kostenvergleich von Kimi K3 und GPT-5.5 – strukturierte Ausgabe selbst bläht die Antwort kaum auf; teuer werden Wiederholungen und zu lange Reasoning-Ketten.

Zwei Einstiege, dieselben Schema-Regeln
Chat Completions legt das Schema in response_format ab; die Responses API in text.format. Die Feldpfade unterscheiden sich, die Constraints zu strict, additionalProperties: false und „alles required“ sind identisch.

Minimale lauffähige Anfrage

Das folgende Ticket-Extraktionsschema deckt rund 80 % der Produktionsfälle ab: String, Enum, Integer und optionale Felder als Union mit null. Das Modell muss alle Schlüssel liefern; fehlt eine Konto-ID, kommt explizit null – der Schlüssel darf nicht fehlen.

Chat Completions · response_format
{
  "model": "gpt-4o-2024-08-06",
  "messages": [
    {"role": "system", "content": "Extrahieren Sie die Nutzerbeschreibung als Support-Ticket-Objekt."},
    {"role": "user", "content": "Checkout-Seite liefert 500 bei gespeicherter Karte. Seit heute. Konto 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": { "type": ["string", "null"] }
        },
        "required": ["summary", "category", "severity", "account_id"],
        "additionalProperties": false
      }
    }
  }
}

In der Responses API liegt dasselbe Schema in text.format; type, name, schema und strict stehen als Geschwisterfelder. Beim ersten Einsatz kompiliert der Server die Constraints – die Latenz kann etwas höher liegen. Danach wird dasselbe Schema gecacht, und folgende Anfragen kehren auf das übliche Niveau zurück.

Notebook mit Code und einer Umgebung zum Debuggen strukturierter APIs
Behandeln Sie das Schema als Schnittstellenvertrag: zuerst lokal mit derselben Definition Unittests fahren, dann das Modell erzeugen lassen

Regeln für ein strict Schema

Mit strict: true senden Sie kein lockeres JSON Schema mehr, sondern die offiziell unterstützte Teilmenge. Verstöße führen zu HTTP 400, nicht zu einem „wir versuchen es trotzdem“.

  • Wurzel muss ein object sein: Kein anyOf und kein Array an der Wurzel. Erzeugt Zod discriminatedUnion ein Top-Level-anyOf, packen Sie es in ein Objekt, etwa { "result": ... }.
  • Jedes object braucht additionalProperties: false: auch verschachtelte Objekte. Ein einziges fehlendes Flag reicht für die Ablehnung.
  • Jeder Schlüssel in properties muss in required stehen: optionale Semantik über "type": ["string", "null"] oder anyOf plus null.
  • Unterstützte Typen: string, number, integer, boolean, object, array, enum, anyOf.
  • String-Constraints: pattern, format (email, date-time, uuid, ipv4 und ähnliche).
  • Zahlen und Arrays: minimum / maximum / multipleOf; minItems / maxItems.
  • Ausdrücklich nicht unterstützt: Kombinationsschlüssel wie allOf, not, if/then/else, dependentRequired.
  • Größengrenzen: insgesamt etwa 5000 Objekteigenschaften, 10 Schachtelungsebenen; Summe der Zeichen in Eigenschaftsnamen, Definitionsnamen und Enum-Werten höchstens 120.000; höchstens 1000 Enum-Werte.
Feinabgestimmte Modelle sind strenger
Auf Fine-Tuning-Modellen können pattern, format, minLength, minimum, minItems und ähnliche Constraints derzeit weiterhin fehlen. Validieren Sie das Schema zuerst auf einem Basis-Snapshot, bevor Sie feinabstimmen.

Tool-Aufruf vs. Antworttext

Dieselbe strict-Logik gilt auch für Funktions- und Tool-Parameter. Der Unterschied ist die Absicht: ein Tool-Schema beschreibt, was das Modell aufrufen soll; response_format / text.format beschreibt die Form der Nutzerantwort. Extraktion, Scoring und UI-Zustand gehören zur zweiten Gruppe; Wetterabfrage, Dateischreiben und Befehle zur ersten. Wenn Sie Terminal-Agents mit GUI-Steuerung vergleichen, lesen Sie wie Claude Code und OpenAI Computer Use zusammenhängen – das ist die Handlungsschicht. Dieser Artikel klärt den Datenvertrag davor und danach.

Direkt ins Objekt parsen mit dem SDK

Handgeschriebenes JSON Schema vergisst gern required. Die offiziellen SDKs liefern Helfer für Pydantic und Zod: Schema aus Typen, geparstes Objekt in der Antwort. Typisch in Python:

Python · Pydantic
from typing import Literal, Optional
from pydantic import BaseModel
from openai import OpenAI

class SupportTicket(BaseModel):
    summary: str
    category: Literal["billing", "bug", "account", "other"]
    severity: int
    account_id: Optional[str]

client = OpenAI()
completion = client.beta.chat.completions.parse(
    model="gpt-4o-2024-08-06",
    messages=[
        {"role": "system", "content": "Extrahieren Sie das Support-Ticket."},
        {"role": "user", "content": "Checkout-Seite 500, Konto acct_8842."},
    ],
    response_format=SupportTicket,
)
ticket = completion.choices[0].message.parsed
if completion.choices[0].message.refusal:
    raise RuntimeError(completion.choices[0].message.refusal)
print(ticket.category, ticket.severity)
Ein Schema als einzige Quelle der Wahrheit
Dasselbe Pydantic- oder Zod-Modell speist API-Request, Unittest und nachgelagerte Validierung. Kopieren Sie die Feldliste nicht noch einmal in den Prompt – sonst veraltet die Dokumentation vor dem Code.

Fehler, Ablehnungen und Checkliste

Gehen Sie diese Liste vor dem Go-live durch. Sie beseitigt die meisten Fälle, in denen lokales curl funktioniert und die Pipeline 400 liefert.

  • 400 Unsupported schema: fehlendes additionalProperties: false, nicht required gesetzte Felder, Wurzel als anyOf oder Verwendung von allOf.
  • Modell lehnt ab: bei Sicherheitsfiltern landet der Inhalt nicht im Schema. Lesen Sie refusal, zeigen Sie den Text in der UI und behandeln Sie ihn nicht als JSON-Parsefehler mit Retry.
  • Optionale Felder werden leere Strings: steht null im Vertrag, akzeptieren Sie null. Vor dem Speichern auf SQL NULL mappen, nicht erneut raten.
  • Enums zu breit: Geschäftsstatus auf 5–8 Werte begrenzen. Hunderte Enums fressen Kontext und nähern sich der 1000er-Grenze.
  • Schlüsselreihenfolge: die Ausgabe folgt der Reihenfolge im Schema; beim Streaming können Sie felderweise parsen.
  • Prompts bleiben nützlich: das Schema steuert die Form, der Prompt die Semantik. „severity 1–5, 5 ist ein Standortausfall“ gehört ins System-Prompt; den Integer-Bereich können Sie zusätzlich mit minimum / maximum festziehen.

In der Praxis lohnt es sich, drei Dinge festzuzurren: Schema ins Git; Metriken getrennt für Ablehnung, 400 und Timeout; eine Regression mit echten Tickets statt Spielzeug-Prompts wie „Hello, gib JSON zurück“. Erst wenn die Parserschicht ruhig ist, können Sie Genauigkeit und Latenz verbessern – statt jede Woche eine Regex zu flicken.

Extraktionspipelines auf dem Mac mini: weniger Reibung in der Umgebung

Der Debug-Zyklus bei Structured Outputs ist kurz: Schema ändern, eine kleine Sample-Charge fahren, das geparste Objekt prüfen. Unter macOS stehen Python, Node.js, Docker und Homebrew bereit, ohne zuerst WSL aufzusetzen. Der Unified Memory von Apple Silicon hält Editor, lokale Validierungsskripte und lange Kontext-Evals gleichzeitig im RAM, statt beim Type-Check ins Swap zu rutschen.

Ein Mac mini M4 liegt im Leerlauf bei etwa 4 W – geeignet, um Regressionssamples über Nacht laufen zu lassen. macOS stürzt selten ab; Gatekeeper und SIP senken das Risiko, dass Abhängigkeits-Skripte unbemerkt verändert werden. Gegenüber einem vergleichbar teuren Windows-Rechner sind Stabilität und Stromkosten bei unbeaufsichtigten Agent-Evals oft freundlicher.

Wenn Sie einen dauerhaft erreichbaren Knoten für JSON-Regression und Modellvergleiche wollen, sehen Sie sich die Kvmzen-Tarife an und legen Sie den Schema-Vertrag von einem Notebook auf einen Cloud-Mac mit fester Spezifikation.

Zeitlich begrenztes Angebot

Mehr als ein Mac – Ihre Entwicklungsbasis in der Cloud

Dedizierte Rechenleistung · Globale Knoten · Monatsabonnement · Keine Hardware nötig

Zur Startseite
Zeitl. begr. Angebot Pläne ansehen