JSON-Schemas und Validierung
Auf dieser Seite
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
requiredenthalten sein additionalPropertiesmussfalsesein- Optionale Typen verwenden
anyOfmitnull - Keine
pattern,minLength,maxLengthauf 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
jsonschemafü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