Die meisten Teams stoßen auf dasselbe Problem ungefähr in der dritten Woche der Arbeit mit LLMs: Das Modell antwortet fast richtig. Der JSON enthält einen Kommentar. Oder die abschließende geschweifte Klammer fehlt. Oder — das ist das Heimtückische — es wurde valides JSON zurückgegeben, nur mit dem Feld status auf "ok" gesetzt statt "approved", was Ihre nachgelagerte Logik nicht erkennt. Die Anwendung fällt vier Stunden später ab, wenn dieser spezielle Code-Branch endlich aufgerufen wird. Im Produktivbetrieb.
Das Problem liegt nicht darin, dass LLMs unzuverlässig sind. Das Problem liegt darin, dass Textformatierung und semantische Korrektheit zwei verschiedene Dinge sind, und die meisten Deployments vermischen sie. Dieser Artikel erklärt, wo die Grenze zwischen beiden liegt, welche Werkzeuge es gibt, um syntaktische Korrektheit sicherzustellen, und wie man eine Validierungsschicht aufbaut, die den Rest abfängt.
Warum „Antworte im JSON-Format" im Prompt nicht ausreicht
Wenn Sie in den Prompt "Respond in JSON format" schreiben, geben Sie dem Modell eine Anweisung, keine Garantie. Autoregressive Sprachmodelle generieren Token für Token nach Wahrscheinlichkeit — jedes weitere Token ist das Ergebnis einer Verteilung, die auf allem Vorherigen bedingt ist. Das Modell „sieht" keine „offene Klammer, die ich schließen muss". Es sieht Wahrscheinlichkeiten der nächsten Token.
Daraus ergeben sich drei Fehlerkategorien:
- Syntaktischer Fehler — ungültiges JSON, überflüssiger Text vor/nach dem JSON, Markdown-Blöcke `
`json ...`` um den Output gewickelt, Steuerzeichen, Unicode-Escape-Fehler - Schema-Fehler — valides JSON, aber ein Pflichtfeld fehlt, ein Feld hat den falschen Datentyp (String statt Int), ein Enum-Wert liegt außerhalb der erlaubten Liste, eine verschachtelte Struktur ist flach
- Semantischer Fehler — valides JSON, korrektes Schema, aber der Inhalt ist falsch (falsche Klassifikation, erfundener Wert, logischer Widerspruch zwischen Feldern)
Prompt Engineering kann die erste Kategorie teilweise unterdrücken. Für die zweite und dritte reicht es allein nicht aus.
JSON-Modus vs. Constrained Decoding — der Unterschied, auf den es ankommt
Wenn Anbieter von „JSON-Modus" sprechen, meinen sie üblicherweise eines von zwei Dingen, die sich technisch stark unterscheiden.
JSON-Modus (Token-Level-Bias): Über einen API-Parameter wird die Wahrscheinlichkeit von Token, die zur JSON-Grammatik gehören, erhöht und Token, die die Validität verletzen würden, werden unterdrückt. Das Ergebnis ist fast immer syntaktisch valides JSON, aber das Modell entscheidet nach wie vor selbst über die Struktur. Sie können nicht garantieren, dass das Ergebnis ein Feld invoice_number enthält — nur dass es parsierbar ist.
Constrained Decoding / Grammar-Based Generation: Das Modell generiert ausschließlich Token, die im aktuellen Zustand gemäß einer formalen Grammatik (z. B. JSON Schema, RegEx, kontextfreie Grammatik) erlaubt sind. Die Implementierung verwendet typischerweise einen endlichen Automaten (FSM — Finite State Machine) oder eine ähnliche Struktur, die den Parse-Zustand verfolgt und in jedem Schritt die Token-Auswahl auf erlaubte Werte einschränkt. Das Ergebnis garantiert die Übereinstimmung mit der Grammatik — einschließlich eines konkreten Schemas mit Pflichtfeldern und Datentypen.
Der Unterschied in der Praxis: JSON-Modus liefert ein parsierbares Ergebnis, Grammar-Based Generation liefert ein Ergebnis, das mit Ihrem Pydantic- oder zod-Schema übereinstimmt.
XGrammar: der aktuelle Standard für Constrained Decoding
Für die meisten produktiven Serving-Frameworks — vLLM, SGLang, TensorRT-LLM — ist seit Anfang 2026 XGrammar das Standard-Backend für eingeschränktes Dekodieren. Gegenüber dem älteren Ansatz (die Bibliothek Outlines, die den FSM-Ansatz als Erste einführte, aber Probleme mit Kompilierungszeiten bei komplexen Schemata hatte) erreicht XGrammar einen Overhead von unter 40 Mikrosekunden pro Token — praktisch keinen Einfluss auf die Latenz. Wenn Sie also einen modernen Self-Hosted-Serving-Stack verwenden, haben Sie Constrained Decoding ohne weitere Konfiguration verfügbar.
Für Cloud-APIs (OpenAI, Anthropic, Google) ist Constrained Decoding typischerweise nicht direkt exponiert — Sie haben JSON-Modus oder einen „Response-Format"-Parameter mit Schema, der ähnlich funktioniert, aber die Implementierung liegt auf der Seite des Anbieters.
Mehr zum Self-Hosted Serving: vLLM vs. SGLang vs. Ollama — wann was einsetzen.
Schema-Definition: Pydantic und zod als Single Source of Truth
Wenn Constrained Decoding von einem formalen Schema abhängt, müssen Sie dieses Schema irgendwo definieren und pflegen. In der Praxis gibt es zwei dominante Wege:
Python — Pydantic v2:
from pydantic import BaseModel, Field
from enum import Enum
class RiskLevel(str, Enum):
low = "low"
medium = "medium"
high = "high"
class SupplierAssessment(BaseModel):
supplier_name: str
risk_level: RiskLevel
score: int = Field(ge=0, le=100)
flags: list[str]
summary: str = Field(max_length=300)Das Pydantic-Modell wird direkt in ein JSON Schema serialisiert, das die meisten LLM-Frameworks akzeptieren. Die Validierung beim Parsen (model.model_validate(json_data)) deckt Schema-Fehler mit genauer Ortsangabe auf.
TypeScript / Node.js — zod:
import { z } from "zod";
const SupplierAssessment = z.object({
supplier_name: z.string(),
risk_level: z.enum(["low", "medium", "high"]),
score: z.number().int().min(0).max(100),
flags: z.array(z.string()),
summary: z.string().max(300),
});Zentrales Prinzip: Das Schema ist die einzige Quelle der Wahrheit. Definieren Sie es nicht einmal im Prompt und einmal im Code — die beiden werden auseinanderdriften. Generieren Sie die Schemabeschreibung für den Prompt dynamisch aus der Pydantic- oder zod-Definition selbst.
Validierung und Retry — die Produktionsschicht
Weder Constrained Decoding noch JSON-Modus schützen vor semantischen Fehlern. Und bei Cloud-APIs können trotz JSON-Modus gelegentlich syntaktische Anomalien auftreten (Netzwerkunterbrechungen, Kürzung bei max_tokens). Ein Produktions-Pipeline benötigt daher eine Validierungsschicht mit Retry-Logik.
Grundlegendes Muster:
import json
from pydantic import ValidationError
async def call_with_validation(prompt: str, schema: type[BaseModel], max_retries: int = 3):
for attempt in range(max_retries):
raw = await llm_call(prompt)
try:
data = json.loads(raw)
return schema.model_validate(data)
except (json.JSONDecodeError, ValidationError) as e:
if attempt == max_retries - 1:
raise
# Vrátiť chybu do promptu pre opravu
prompt = repair_prompt(prompt, raw, str(e))
raise RuntimeError("Max retries exceeded")Einige praktische Hinweise:
- Retry mit Fehler im Kontext: Beim nächsten Versuch fügen Sie die genaue Fehlerausgabe des Validators in den Prompt ein. Das Modell korrigiert den Fehler typischerweise, wenn es weiß, wo der Fehler liegt — nicht wenn es lediglich „versuche es erneut" erhält.
- Exponential Backoff: Bei API-Rate-Limits oder instabiler Netzwerkverbindung.
- Retry-Limit: In der Praxis reichen 2–3 Versuche. Wenn das Modell nach drei Versuchen weiterhin ungültige Ausgaben liefert, liegt das Problem in Ihrem Schema oder Prompt, nicht im Zufall.
- Jeden fehlgeschlagenen Versuch loggen: Ohne Log wissen Sie nicht, wie oft es passiert oder warum.
Zuverlässigkeit beim Tool-Calling — ein eng verwandtes Problem — behandeln wir im Artikel Tool-Calling zuverlässig in der Produktion.
Warum selbst hohe Zuverlässigkeit nicht ausreicht — und was zu tun ist
Die Zuverlässigkeit eines "Respond in JSON"-Prompts ohne weitere Infrastruktur hängt stark vom Modell, der Schemakomplexität und dem Prompt ab — und sinkt bei anspruchsvolleren Schemata häufig unter ein im Produktivbetrieb nutzbares Niveau. JSON-Modus (Token-Bias) verbessert die Situation deutlich. Grammar-Based Generation + Pydantic-Validierung + Retry-Schicht hebt die Zuverlässigkeit auf ein Niveau, bei dem die meisten Teams aufhören, syntaktische Fehler zu lösen, und sich auf die semantische Korrektheit konzentrieren können.
Für viele Use-Cases klingt das gut. Aber stellen Sie sich einen Pipeline vor, der tausendmal täglich läuft: Bei 99 % Zuverlässigkeit haben Sie 10 Fehler pro Tag. Wenn jeder Fehler einen manuellen Eingriff des Operators oder ein falsch verarbeitetes Dokument bedeutet, werden diese 10 Fälle pro Tag schnell zum Problem.
Praktische Maßnahmen jenseits von Retry:
- Einfache Schemata: Jede Verschachtelungsebene und jedes neue Feld senkt die Zuverlässigkeit. Wenn Sie ein komplexes Schema benötigen, teilen Sie es in mehrere sequenzielle Aufrufe mit einfacheren Ausgaben auf.
- Enum statt Freitext: Ersetzen Sie freien Text, wo möglich, durch eine feste Werteliste. Das Modell muss aus
["approved", "rejected", "pending"]wählen, nicht selbst ein Format erfinden. - Niedrige Temperaturen:
temperature=0oder nahe null für Extraktionsaufgaben. Kreativität ist hier nicht erwünscht. - Explizite Beispiele im Prompt: Few-Shot-Beispiele valider JSON-Ausgaben sind nach wie vor einer der wirksamsten Tricks.
Semantische Korrektheit: die Grenze, wo Technologie nicht ausreicht
Constrained Decoding garantiert, dass die Ausgabe syntaktisch und schema-konform ist. Es garantiert nicht, dass sie inhaltlich korrekt ist.
Beispiele für semantische Fehler, die alle technischen Schichten passieren:
- Klassifikation einer Rechnung als
"approved", obwohl der Betrag das genehmigte Limit überschreitet — weil das Modell nicht auf Ihren internen Regeln nachtrainiert wurde - Extraktion eines falschen Datums aus einem Dokument (vertauschtes Feld)
- Sentiment
"positive"für einen Text, der ironisch kritisch ist - Wert
score: 87, der nicht aus dem Text abgeleitet wird, sondern als „vernünftige Zahl" generiert wird
Diese Fehler lösen Sie anders: durch Evals, Tests an repräsentativen Ausgabe-Stichproben, und wo das Risiko hoch ist — durch eine Human-in-the-Loop-Schicht. Wie man die Qualität von LLM-Ausgaben einschließlich der semantischen Dimension systematisch misst, beschreiben wir im Artikel Wie man die Qualität einer LLM-Anwendung misst (Evals).
Structured Outputs über API-Anbieter vs. Self-Hosted
Wenn Sie Cloud-APIs verwenden, stehen Ihnen folgende Optionen zur Verfügung:
- OpenAI: Parameter
response_formatmittype: "json_schema"und einer Inline-JSON-Schema-Definition. Ab einer bestimmten API-Version wird die Übereinstimmung mit dem Schema auf Grammatikebene garantiert (nicht nur Token-Bias). - Anthropic Claude: Native strukturierte Ausgaben über den
output_format-Parameter — eingeschränktes Dekodieren direkt auf Token-Ebene, garantiert Übereinstimmung mit JSON Schema. Auch striktes Tool-Use mit genau definiertem Eingabeschema verfügbar. - Google Gemini:
responseMimeType: "application/json"+responseSchema-Parameter.
Alle drei Ansätze funktionieren gut für typische Use-Cases. Ein praktischer Unterschied entsteht bei:
- Sehr komplexen Schemata (tiefe Verschachtelung,
oneOf/anyOf) — Cloud-APIs können Einschränkungen bei den unterstützten JSON-Schema-Features haben - Hohem Durchsatz — bei Tausenden von Requests pro Minute ist Self-Hosted
vLLM+XGrammarwirtschaftlich vorteilhafter, vgl. den Vergleich in vLLM vs. SGLang vs. Ollama - Sensiblen Daten — wenn Eingabedokumente PII oder Geschäftsgeheimnisse enthalten, erzeugen Cloud-APIs ein Data-Egress-Risiko; Self-Hosted on-prem eliminiert es
Für regulierte Branchen (Gesundheitswesen, Finanzen, Recht) ist der On-Prem-Weg fast immer relevant — mehr dazu in Lokale LLMs vs. Cloud: wann was sinnvoll ist.
Strukturierte Ausgabe in RAG- und agentischen Pipelines
Structured Outputs sind nicht nur für Extraktionsaufgaben gedacht. In jedem Pipeline, in dem ein LLM eine Zwischenausgabe generiert, die eine weitere Komponente konsumiert, ist das strukturierte Format eine Voraussetzung für Zuverlässigkeit.
In einem RAG-Pipeline benötigen Sie typischerweise strukturierte Ausgabe für:
- Query Planning — das Modell entscheidet, welche Quellen abgefragt werden, mit welchem Filter, wie viele Ergebnisse
- Reranking-Entscheidung — bei agentic RAG bewertet das Modell die Relevanz eines Chunks und gibt einen Score zurück
- Zitate — wo im Quelldokument die Antwort zu finden ist (Chunk-ID, Offset, Konfidenz)
- Finale Ausgabe für Downstream — wenn ein RAG-Pipeline von einem anderen System konsumiert wird, nicht nur Text anzeigt
In agentischen Pipelines gilt dasselbe für jeden Tool-Aufruf — der Agent muss eine strukturierte Aktionsauswahl (Tool-Name + Parameter) zurückgeben, damit der Orchestrator weiß, was auszuführen ist. Ein Strukturverlust bedeutet hier nicht nur einen Parse-Fehler — er kann die Ausführung der falschen Aktion bedeuten.
Praktische Erfahrung: In einem Pipeline mit mehr als drei Werkzeugen lohnt es sich, jede Tool-Eingabe über ein Pydantic-Modell zu validieren und nicht nur ein freies Dict zu verwenden. Fehler werden dadurch an der Eingabegrenze des Tools aufgedeckt, nicht tief in dessen Logik.
Monitoring und Drifting im Produktivbetrieb
Strukturierte Ausgabe funktioniert nach dem Deployment tendenziell gut und verschlechtert sich allmählich — wenn das Modell auf der Seite des Anbieters geändert wird (Cloud-APIs aktualisieren das Modell stillschweigend), wenn sich die Verteilung der Eingabedaten ändert oder wenn das Schema um neue Felder erweitert wird, ohne dass der Prompt aktualisiert wird.
Das Mindestmaß an Monitoring, das wir empfehlen:
- Parse-Error-Rate: Wie viel Prozent der Aufrufe enden nach dem ersten Versuch mit einem Validierungsfehler? Wenn diese Zahl steigt, hat sich etwas geändert.
- Retry-Rate: Wie viel Prozent der Aufrufe benötigten mehr als einen Versuch? Über 5 % ist ein Signal.
- Field-Level-Null/Default-Rate: Wenn das Feld
invoice_numberin 30 % der Fälle null ist, enthalten die Eingaben es entweder nicht, oder das Modell hört auf, es zu extrahieren. - Schema-Version-Tracking: Jede Schema-Änderung ist ein Deploy-Ereignis — loggen Sie die Schema-Version bei jedem Aufruf, damit Sie Qualitätsänderungen korrelieren können.
Ohne dieses Monitoring wird die Degradation erst erkannt, wenn das nachgelagerte System im Produktivbetrieb versagt — nicht wenn sie eintritt.
Häufige Fragen
Was ist der Unterschied zwischen JSON-Modus und Structured Outputs?
JSON-Modus (Token-Level-Bias) garantiert nur die syntaktische Validität — das Ergebnis ist parsierbares JSON, aber ohne Garantie einer konkreten Struktur. Structured Outputs (Grammar-Based / Schema-Constrained) garantieren die Übereinstimmung mit einem definierten Schema einschließlich Pflichtfeldern und Datentypen. Für Produktions-Pipelines benötigen Sie den zweiten Ansatz.
Beeinflusst Constrained Decoding die Qualität oder Geschwindigkeit des Modells?
Bei modernen Implementierungen (XGrammar) liegt der Overhead unter 40 Mikrosekunden pro Token — in der Praxis nicht messbar. Die Antwortqualität kann sich leicht unterscheiden, da das Modell nicht frei formulieren kann — bei engen Schemata mit langen Textfeldern ist das vernachlässigbar, bei sehr einschränkenden Schemata (z. B. kleines Enum als Antwort in natürlicher Sprache) kann die Ausgabe weniger natürlich wirken.
Kann ich Structured Outputs mit einem lokal laufenden Modell verwenden?
Ja, mit vLLM oder SGLang ist XGrammar out-of-the-box verfügbar. Ollama unterstützt JSON-Modus, aber nicht Grammar-Based Constrained Decoding im vollen Umfang — für Produktions-Pipelines mit präzisem Schema ist vLLM die bessere Wahl. Mehr dazu in vLLM vs. SGLang vs. Ollama.
Was tun, wenn das Modell trotz korrektem Format weiterhin falsche Werte zurückgibt?
Das ist ein semantischer, kein syntaktischer Fehler — Constrained Decoding löst ihn nicht. Lösungen: Few-Shot-Beispiele mit korrekten/inkorrekten Mustern, explizite Regeln im System-Prompt, Fine-Tuning auf einer Domain-Stichprobe oder eine Human-in-the-Loop-Schicht für kritische Entscheidungen.
Wie definiert man ein Schema, damit das Modell keine Fehler bei Datentypen macht?
Seien Sie explizit: Statt score: number verwenden Sie score: integer, minimum: 0, maximum: 100. Statt date: string verwenden Sie date: string, format: date (ISO 8601). Enum-Werte immer definieren — ein freier String ist eine Einladung zu Variationen. Jede Präzisierung im Schema senkt die Fehlerwahrscheinlichkeit.
*MP Industrial Solutions hilft Unternehmen, produktive LLM-Pipelines zu entwerfen und einzusetzen — von der Ausgabevalidierung bis zum Monitoring im realen Betrieb. Wenn Sie die Zuverlässigkeit strukturierter Ausgaben in Ihrem System verbessern möchten, schauen wir uns die konkrete Architektur gerne gemeinsam an.*
