Vergleich strukturierter Ausgaben bei führenden LLM-Anbietern – OpenAI, Gemini, Anthropic, Mistral und AWS Bedrock

„Sich leicht unterscheidende APIs erfordern einen besonderen Ansatz.“

Inhaltsverzeichnis

Hier ist ein direkter Vergleich der Unterstützung für strukturierte Ausgabe (verlässliche Rückgabe von JSON) bei populären LLM-Anbietern, ergänzt um minimale Python-Beispiele.

colorised bars standing

Wir haben bereits untersucht, wie man strukturierte Ausgabe von einem auf Ollama gehosteten LLM anfordert. Sobald JSON über die Leitung zurückkommt, erläutert Validierung der strukturierten LLM-Ausgabe in Python, die standhält, den Prozess des Parsens, Pydantic-Checks, Wiederholungsversuchen (Retries) und Tests in Ihrer Service-Schicht. Hierüber hinaus prüfen wir, wie dieselbe Anforderung bei anderen Anbietern gestellt wird.

TL;DR Matrix

Anbieter Nativer „JSON-Modus“ Durchsetzung des JSON-Schemas Typischer Parameter Anmerkungen
OpenAI Ja Ja (Erstkategorie) response_format={"type":"json_schema", ...} Funktioniert über die Responses API oder Chat Completions; ermöglicht auch Function Calling.
Google Gemini Ja Ja (Erstkategorie) response_schema= + response_mime_type="application/json" Gibt streng validiertes JSON zurück, wenn ein Schema gesetzt ist.
Anthropic (Claude) Indirekt Ja (über Tool Use mit JSON-Schema) tools=[{input_schema=...}] + tool_choice Erzwingt, dass das Modell Ihr schema-definiertes Tool „aufruft“; liefert Argumente in der Schema-Struktur.
Mistral Ja Teilweise (nur JSON; kein serverseitiges Schema) response_format={"type":"json_object"} Stellt JSON sicher, die Validierung gegen Ihr Schema erfolgt jedoch clientseitig.
AWS Bedrock (Plattform) Je nach Modell Ja (über Tool/Converse-Schema) toolConfig.tools[].toolSpec.inputSchema Die Converse API von Bedrock validiert Tool-Eingaben gegen ein JSON-Schema.

Strukturierte LLM-Ausgabe – Allgemeine Informationen

Strukturierte LLM-Ausgabe bezieht sich auf die Fähigkeit großer Sprachmodelle (LLMs), Antworten zu generieren, die strikt einem vordefinierten, spezifischen Format oder einer Struktur folgen, anstatt freien Text zu produzieren. Diese strukturierte Ausgabe kann Formate wie JSON, XML, Tabellen oder Templates annehmen, was die Daten maschinenlesbar, konsistent und leicht für Software in verschiedenen Anwendungen parsebar macht.

Strukturierte Ausgaben unterscheiden sich von traditionellen LLM-Ausgaben, die typischerweise offenen, natürlichen Text generieren. Stattdessen erzwingen strukturierte Ausgaben ein Schema oder Format, wie z. B. JSON-Objekte mit definierten Schlüsseln und Wertetypen oder spezifische Klassen in der Ausgabe (z. B. Multiple-Choice-Antworten, Sentiment-Klassen oder Datenbankzeilenformate). Dieser Ansatz verbessert die Zuverlässigkeit, reduziert Fehler und Halluzinationen und vereinfacht die Integration in Systeme wie Datenbanken, APIs oder Workflows.

Die Generierung strukturierten Outputs in LLMs beinhaltet oft Techniken wie:

  • Das Festlegen detaillierter Prompt-Anweisungen, um das Modell zur Ausgabe im gewünschten Format zu führen.
  • Die Verwendung von Validierungs- und Parsing-Tools wie Pydantic in Python, um sicherzustellen, dass die Ausgabe dem Schema entspricht.
  • Gelegentliches Erzwingen von Decodierungseinschränkungen basierend auf Grammatik oder endlichen Automaten, um die Token-Ebene-Konformität mit dem Format sicherzustellen.

Vorteile strukturierten LLM-Outputs umfassen:

  • Maschinenlesbarkeit und einfache Integration.
  • Reduzierte Variabilität und Fehler.
  • Verbesserte Vorhersagbarkeit und Verifizierbarkeit für Aufgaben, die konsistente Datenformate erfordern.

Herausforderungen beinhalten das Entwerfen effektiver Schemata, die Handhabung komplexer verschachtelter Daten und potenzielle Einschränkungen in den Reasoning-Fähigkeiten im Vergleich zur Generierung freien Texts.

Insgesamt ermöglicht strukturierte Ausgabe LLMs, in Anwendungen nützlicher zu sein, die präzise, formatierte Daten erfordern, anstatt ausschließlich menschenlesbaren Text.

Beispiele für strukturierte Ausgabe in Python

Alle Snippets extrahieren Event-Informationen als JSON: {title, date, location}. Passen Sie Schlüssel/Modelle nach Belieben an.

1) OpenAI — JSON Schema (strikt)

from openai import OpenAI
import json

client = OpenAI()

schema = {
    "name": "Event",
    "schema": {
        "type": "object",
        "properties": {
            "title": {"type": "string"},
            "date":  {"type": "string", "description": "YYYY-MM-DD"},
            "location": {"type": "string"}
        },
        "required": ["title", "date", "location"],
        "additionalProperties": False
    },
    "strict": True
}

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "user", "content": "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}
    ],
    response_format={"type": "json_schema", "json_schema": schema},
)

data = json.loads(resp.choices[0].message.content)
print(data)

OpenAIs Feature Structured Outputs erzwingt dieses Schema auf der Serverseite.


2) Google Gemini — Response Schema + JSON MIME

import google.generativeai as genai
from google.genai import types

# Konfigurieren Sie mit Ihrem API-Schlüssel
# genai.configure(api_key="your-api-key")

schema = types.Schema(
    type=types.Type.OBJECT,
    properties={
        "title": types.Schema(type=types.Type.STRING),
        "date": types.Schema(type=types.Type.STRING),
        "location": types.Schema(type=types.Type.STRING),
    },
    required=["title", "date", "location"],
    additional_properties=False,
)

resp = genai.generate_content(
    model="gemini-2.0-flash",
    contents="Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'",
    generation_config=genai.GenerationConfig(
        response_mime_type="application/json",
        response_schema=schema,
    ),
)

print(resp.text)  # bereits valides JSON gemäß Schema

Gemini wird striktes JSON zurückgeben, das dem response_schema entspricht.


3) Anthropic (Claude) — Tool Use mit JSON-Schema

from anthropic import Anthropic
import json

client = Anthropic()

tool = {
    "name": "extract_event",
    "description": "Return event details.",
    "input_schema": {
        "type": "object",
        "properties": {
            "title": {"type": "string"},
            "date": {"type": "string"},
            "location": {"type": "string"}
        },
        "required": ["title", "date", "location"],
        "additionalProperties": False
    }
}

msg = client.messages.create(
    model="claude-3-5-sonnet-20241022",
    max_tokens=256,
    tools=[tool],
    tool_choice={"type": "tool", "name": "extract_event"},  # Schema erzwingen
    messages=[{"role": "user", "content":
        "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
)

# Claude wird das Tool „aufrufen“; holen Sie sich die Argumente (die Ihrem Schema entsprechen)
tool_use = next(b for b in msg.content if b.type == "tool_use")
print(json.dumps(tool_use.input, indent=2))

Claude verfügt nicht über einen generischen „JSON-Modus“-Schalter; stattdessen gibt Ihnen Tool Use mit einem input_schema validierte, schema-geformte Argumente (und Sie können dessen Nutzung erzwingen).


4) Mistral — JSON-Modus (Validierung clientseitig)

from mistralai import Mistral
import json

client = Mistral()

resp = client.chat.complete(
    model="mistral-large-latest",
    messages=[{"role":"user","content":
        "Return JSON with keys title, date (YYYY-MM-DD), location for: "
        "'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
    response_format={"type": "json_object"}  # garantiert valides JSON
)

data = json.loads(resp.choices[0].message.content)
print(data)
# Tipp: Validieren Sie `data` lokal gegen Ihr Pydantic-/JSON-Schema.

Mistrals json_object erzwingt die JSON-Struktur (nicht Ihr exaktes Schema) – validieren Sie clientseitig.


5) AWS Bedrock — Converse API Tool-Schema (modellagnostisch)

import boto3, json

bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
model_id = "anthropic.claude-3-5-sonnet-20240620-v1:0"

tools = [{
    "toolSpec": {
        "name": "extract_event",
        "inputSchema": {
            "json": {
                "type": "object",
                "properties": {
                    "title": {"type": "string"},
                    "date": {"type": "string"},
                    "location": {"type": "string"}
                },
                "required": ["title","date","location"],
                "additionalProperties": False
            }
        }
    }
}]

resp = bedrock.converse(
    modelId=model_id,
    toolConfig={"tools": tools},
    toolChoice={"tool": {"name": "extract_event"}},  # Schema erzwingen
    messages=[{"role":"user","content":[{"text":
        "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}]}],
)

# Hole toolUse-Inhalt
tool_use = next(
    c["toolUse"] for c in resp["output"]["message"]["content"] if "toolUse" in c
)
print(json.dumps(tool_use["input"], indent=2))

Bedrock validiert Tool-Eingaben gegen Ihr JSON-Schema und viele gehostete Modelle (z. B. Claude) unterstützen dies über Converse.


Praktische Anleitung und Validierung

  • Wenn Sie die stärksten serverseitigen Garantien wünschen: OpenAI Structured Outputs oder Gemini Response Schema.
  • Wenn Sie bereits Claude/Bedrock nutzen: Definieren Sie ein Tool mit einem JSON-Schema und erzwingen Sie dessen Nutzung; lesen Sie die Argumente des Tools als Ihr typisiertes Objekt.
  • Wenn Sie Mistral nutzen: Aktivieren Sie json_object und validieren Sie lokal (z. B. mit Pydantic).

Validierungsmuster (funktioniert für alle)

from pydantic import BaseModel, ValidationError

class Event(BaseModel):
    title: str
    date: str
    location: str

try:
    event = Event.model_validate(data)  # `data` von beliebigem Anbieter
except ValidationError as e:
    # behandeln / wiederholen / Modell bitten, mit e.errors() zu korrigieren
    print(e)

Abonnieren

Neue Beiträge zu Systemen, Infrastruktur und KI-Engineering.