Zum Hauptinhalt springen
Lektion 2 von 20 · API-Tools: Suche, Dateien und Code Interpreter

JSON-Schemas und Validierung

Lektion 2 von 20 Entwickler
Auf dieser Seite
  1. JSON-Schemas und Validierung
  2. Struktur des Funktionsschemas
  3. Strict Mode
  4. Clientseitige Validierung
  5. Effektive Beschreibungen
  6. Verschachtelte Schemas und Referenzen
  7. Kernaussagen

JSON-Schemas und Validierung

Ein Funktionsschema ist keine Validierungs-Infrastruktur: es ist der einzige Vertrag zwischen dem Modell und Ihrem Code. Es gibt keinen anderen Kanal. Das Modell liest Ihre Implementierung nicht, kennt Ihre internen Konventionen nicht und wird nicht erraten, dass ein date-Feld das ISO-Format erwartet statt das französische Format.

Alles, was nicht im Schema geschrieben steht, wird durch die zufälligen Inferenzen des Modells entschieden. Dies erklärt das in dieser Lektion empfohlene Ungleichgewicht der Anstrengung: Es ist besser, zehn Minuten für ein Schema aufzuwenden als zwei Stunden zum Debuggen von willkürlichen Argumenten.

Struktur des Funktionsschemas

Jede in tools deklarierte Funktion folgt dem JSON-Schema-Format. Hier ist die vollständige Struktur:

tool_definition = {
    "type": "function",
    "name": "creer_facture",
    "description": "Erstellen Sie eine Rechnung für einen bestehenden Kunden",
    "parameters": {
        "type": "object",
        "properties": {
            "client_id": {
                "type": "string",
                "description": "Einzigartiger Kundenidentifikator (Format: CLI-XXXXX)"
            },
            "lignes": {
                "type": "array",
                "description": "Liste der Rechnungspositionen",
                "items": {
                    "type": "object",
                    "properties": {
                        "description": {
                            "type": "string",
                            "description": "Produkt- oder Dienstleistungsbeschreibung"
                        },
                        "quantite": {
                            "type": "integer",
                            "minimum": 1,
                            "description": "Anzahl der Einheiten"
                        },
                        "prix_unitaire": {
                            "type": "number",
                            "minimum": 0,
                            "description": "Stückpreis ohne MwSt. in Euro"
                        }
                    },
                    "required": ["description", "quantite", "prix_unitaire"]
                }
            },
            "devise": {
                "type": "string",
                "enum": ["EUR", "USD", "GBP"],
                "default": "EUR"
            },
            "echeance_jours": {
                "type": "integer",
                "enum": [30, 45, 60, 90],
                "description": "Frist für die Zahlung in Tagen"
            }
        },
        "required": ["client_id", "lignes"],
        "additionalProperties": False
    },
    "strict": True
}

Strict Mode

Strict Mode verwandelt Wahrscheinlichkeit in eine Garantie. Ohne sie produziert das Modell normalerweise konforme Argumente, und Sie entdecken die Ausnahmen erst in der Produktion bei Grenzfällen. Mit Strict Mode wird die Konformität auf der Dekodierungsebene durch Konstruktion sichergestellt. Aktivieren Sie es standardmäßig: Die Einschränkungen, die es auferlegt und die im Folgenden detailliert beschrieben werden, sind ein kleiner Preis, um eine ganze Klasse von Fehlern zu eliminieren.

tools = [{
    "type": "function",
    "name": "enregistrer_commande",
    "description": "Erfassen Sie eine neue Bestellung",
    "parameters": {
        "type": "object",
        "properties": {
            "produit": {"type": "string"},
            "quantite": {"type": "integer"},
            "urgent": {"type": "boolean"}
        },
        "required": ["produit", "quantite", "urgent"],
        "additionalProperties": False
    },
    "strict": True
}]

Einschränkungen von Strict Mode

In Strict Mode gelten bestimmte Regeln:

  • Alle Felder müssen in required enthalten sein
  • additionalProperties muss false sein
  • Optionale Typen verwenden anyOf mit null
  • Keine pattern, minLength, maxLength auf der obersten Ebene
# Optionales Feld im Strict Mode
"commentaire": {
    "anyOf": [
        {"type": "string"},
        {"type": "null"}
    ],
    "description": "Optionaler freitextiger Kommentar"
}

Clientseitige Validierung

Strict Mode garantiert die Form, niemals die Bedeutung. Ein wohlbildetes Datum könnte in der Vergangenheit liegen, ein wohntypisierter Identifikator könnte keinem Kunden entsprechen, und ein gültiger Betrag könnte die autorisierte Grenze überschreiten. Diese Regeln sind Geschäftslogik: Kein JSON-Schema kann sie ausdrücken, und sie müssen in Ihrem Code überprüft werden – mit, im Falle einer Ablehnung, einer Fehlermeldung, die an das Modell zurückgesendet wird und erklärt, was schiefgelaufen ist.

import json
from jsonschema import validate, ValidationError

SCHEMA_FACTURE = {
    "type": "object",
    "properties": {
        "client_id": {"type": "string", "pattern": "^CLI-[0-9]{5}$"},
        "lignes": {
            "type": "array",
            "minItems": 1,
            "items": {
                "type": "object",
                "properties": {
                    "description": {"type": "string", "minLength": 1},
                    "quantite": {"type": "integer", "minimum": 1},
                    "prix_unitaire": {"type": "number", "minimum": 0}
                },
                "required": ["description", "quantite", "prix_unitaire"]
            }
        }
    },
    "required": ["client_id", "lignes"]
}

def executer_fonction(name: str, arguments: str) -> str:
    args = json.loads(arguments)

    try:
        validate(instance=args, schema=SCHEMA_FACTURE)
    except ValidationError as e:
        return json.dumps({"error": f"Ungültige Argumente: {e.message}"})

    # Geschäftslogik nach der Validierung
    return creer_facture(**args)

Effektive Beschreibungen

Schreiben Sie eine Funktionsbeschreibung wie Anweisungen für einen neuen Kollegen: Wann soll sie aufgerufen werden, und vor allem, wann sie nicht aufgerufen werden soll. Genau dieser zweite Teil wird systematisch vergessen, löst aber die meisten fehlerhaften Aufrufe – „nicht für archivierten Bestellungen verwenden” verhindert eine unnötige Hin- und Her-Reise, die drei Sätze positiver Beschreibung nicht hätten stoppen können.

# Schlecht: zu vage
{
    "name": "get_data",
    "description": "Daten abrufen"
}

# Gut: spezifisch und kontextbezogen
{
    "name": "rechercher_produits_catalogue",
    "description": "Suchen Sie nach Produkten im E-Commerce-Katalog. "
                   "Gibt Name, Preis, Lagerbestand und Kategorie zurück. "
                   "Verwenden Sie dies für Fragen zur Verfügbarkeit oder zum Preis."
}

Parameterbeschreibungen

Auf der Ebene der Parameter ist der Feind das Implizite. Eine Einheit (Euro oder Cent?), ein Format (ISO oder lokal?), eine Konvention (interne ID oder Kundenreferenz?), die nicht geschrieben wird, wird erraten – manchmal korrekt, manchmal nicht, ohne jegliches Signal in beide Richtungen. Das enum ist Ihr bestes Werkzeug hier: Es beschreibt nicht den erwarteten Wert, es schränkt ihn ein.

"properties": {
    "date_debut": {
        "type": "string",
        "description": "Startdatum im ISO 8601-Format (JJJJ-MM-TT). "
                       "Standard ist das heutige Datum, wenn nicht angegeben."
    },
    "statut": {
        "type": "string",
        "enum": ["actif", "inactif", "suspendu"],
        "description": "Filtern nach Kontostatus. "
                       "'actif' = Konten im Dienst, "
                       "'suspendu' = vorübergehend eingefrorene Konten."
    }
}

Verschachtelte Schemas und Referenzen

Ein tief verschachteltes Schema ist für Sie schwerer zu lesen und für das Modell schwieriger korrekt auszufüllen. Wenn Sie drei Ebenen erreichen, ist die Frage nicht, wie man es besser schreibt, sondern ob die Funktion zu viel tut: Zwei Funktionen mit klarem Umfang sind fast immer vorzuziehen einer konfigurierbaren Funktion, die beide Fälle abdeckt.

adresse_schema = {
    "type": "object",
    "properties": {
        "rue": {"type": "string"},
        "code_postal": {"type": "string"},
        "ville": {"type": "string"},
        "pays": {"type": "string", "enum": ["FR", "BE", "CH", "LU"]}
    },
    "required": ["rue", "code_postal", "ville", "pays"]
}

tools = [{
    "type": "function",
    "name": "creer_livraison",
    "description": "Erstellen Sie eine Lieferung mit Versand- und Zieladressen",
    "parameters": {
        "type": "object",
        "properties": {
            "expedition": adresse_schema,
            "destination": adresse_schema,
            "poids_kg": {"type": "number", "minimum": 0.1}
        },
        "required": ["expedition", "destination", "poids_kg"],
        "additionalProperties": False
    },
    "strict": True
}]

Kernaussagen

  • Aktivieren Sie strict: true, um die Konformität der Argumente zu garantieren
  • Validieren Sie dennoch clientseitig mit jsonschema für Geschäftsregeln
  • Schreiben Sie präzise Beschreibungen: Sie sind der primäre Hebel für Qualität
  • Verwenden Sie enum, um akzeptierte Werte einzuschränken
  • Zerlegen Sie komplexe Schemas in wiederverwendbare Substrukturen