Naar de inhoud
maarten.
Alle posts

Gestructureerde AI-uitvoer met JSON Schema

Maarten Soetens 12 min lezen

Een taalmodel kan gegevens opleveren in JSON, maar een syntactisch correct antwoord voldoet niet automatisch aan de eisen van een applicatie. Lees hoe JSON Schema de vorm van AI-uitvoer afbakent en hoe validatie, foutafhandeling en keuzes rond optionele waarden voorkomen dat onbetrouwbare gegevens verder het systeem in gaan.

Waarom AI-uitvoer een vast gegevensformaat nodig heeft

Een taalmodel antwoordt van zichzelf in tekst. Zelfs wanneer een prompt om JSON vraagt, kan het model uitleg toevoegen, een veld anders noemen of waarden als tekst weergeven terwijl de applicatie een getal verwacht. Dat maakt rechtstreekse verwerking kwetsbaar. Een parser kan stoppen op een kommafout, maar ontdekt niet vanzelf dat een datum ontbreekt of dat een status buiten de toegestane waarden valt.

Een vast gegevensformaat maakt de grens tussen taalbegrip en applicatielogica expliciet. De applicatie beschrijft welke velden ze verwacht, welk type iedere waarde heeft en welke waarden geldig zijn. Het model krijgt die structuur als onderdeel van de opdracht; de uitvoer kan vervolgens tegen dezelfde regels worden gecontroleerd. Zo wordt een antwoord niet alleen leesbaar voor mensen, maar ook toetsbaar door software.

JSON Schema is daarvoor een veelgebruikt hulpmiddel. Het beschrijft onder meer objecten, arrays, typen, verplichte velden en beperkingen op waarden. Het schema garandeert niet dat de inhoud feitelijk juist is. Het stelt wel vast of de uitvoer de verwachte vorm heeft, zodat code niet hoeft te vertrouwen op aannames over de formulering van het model. Dat onderscheid is essentieel: structurele geldigheid is een noodzakelijke controle, geen inhoudelijke waarheidscontrole.

Een JSON Schema ontwerpen dat aansluit op de verwerking

Begin bij de gegevens die de applicatie werkelijk nodig heeft, niet bij alles wat het model mogelijk zou kunnen noemen. Beschrijf per veld het datatype, de betekenis en eventuele grenzen. Een classificatielabel kan bijvoorbeeld een string zijn met een beperkte lijst toegestane waarden; een aantal kan een integer zijn met een minimum. Door zulke beperkingen in het schema op te nemen, wordt een verkeerde waarde zichtbaar voordat downstream-code ermee rekent.

Maak velden verplicht wanneer de verwerking niet zinvol kan doorgaan zonder die waarde. Gebruik required dus niet automatisch voor elk veld: een ontbrekende optionele toelichting is iets anders dan een ontbrekende identificatie. Voor objecten is additionalProperties: false nuttig wanneer onbekende velden niet stilzwijgend mogen worden geaccepteerd. Het voorkomt dat een wijziging in modelgedrag ongemerkt extra gegevens introduceert. Een nadeel is dat nieuwe velden dan ook pas worden toegelaten nadat het schema is aangepast.

Beschrijvingen in het schema kunnen het model helpen om velden juist in te vullen, maar ze vervangen geen formele beperkingen. Leg machinecontroleerbare regels vast waar dat kan en gebruik tekst voor context die niet in een type of bereik past. Houd het schema bovendien zo klein als de taak toelaat. Een omvangrijk schema met overlappende uitzonderingen vergroot de kans op onduidelijkheid, zowel voor het model als voor de code die fouten moet afhandelen.

Gestructureerde uitvoer van het model is geen volledige validatie

Sommige model-API’s kunnen uitvoer beperken met een opgegeven JSON Schema of een vergelijkbare modus voor gestructureerde antwoorden. Dat verkleint de kans op afwijkende sleutels en ongeldige JSON. De precieze ondersteuning verschilt echter per model en API: niet iedere schema-eigenschap wordt ondersteund en gedrag kan veranderen tussen modelversies. Controleer daarom welke beperkingen daadwerkelijk worden afgedwongen, in plaats van aan te nemen dat het volledige schema actief is.

Ook bij constrained generation blijft validatie aan de ontvangende kant nodig. Een API kan bijvoorbeeld alleen een subset van JSON Schema implementeren, of een antwoord kan buiten het verwachte pad vallen door een weigering, een onderbroken generatie of een foutrespons. Behandel het antwoord eerst als externe invoer: controleer de status van de API, parse de JSON en valideer daarna het resultaat tegen de regels die de applicatie zelf hanteert.

Een praktische verdeling is om het schema zowel aan het model mee te geven als lokaal te gebruiken voor controle, mits beide implementaties dezelfde relevante beperkingen ondersteunen. Wanneer dat niet zo is, kan de applicatie een strengere validatielaag hebben. Leg die verschillen bewust vast. Anders lijkt het alsof de uitvoer aan één contract voldoet, terwijl de modelaanroep en de daadwerkelijke verwerking uiteenlopende definities van geldig hanteren. De uitvoermodus helpt bij generatie; de lokale validator bepaalt wat de applicatie accepteert.

Ongeldige velden herkennen zonder gegevens stilzwijgend te verliezen

Veel voorkomende schemafouten zijn een ontbrekende verplichte sleutel, een onjuist datatype, een onbekende eigenschap of een waarde buiten een toegestaan bereik. Een datum kan als vrije tekst binnenkomen, een lijst kan één object bevatten in plaats van een array en een getal kan als string zijn gecodeerd. De validator moet niet alleen melden dat het antwoord ongeldig is, maar ook aangeven waar de afwijking zit. Foutpaden zoals items[2].quantity zijn veel bruikbaarder dan een algemene melding dat de validatie is mislukt.

Onbekende velden vragen om een expliciete keuze. Ze negeren kan compatibiliteit met nieuwe modeluitvoer bevorderen, maar verbergt mogelijk een fout gespelde sleutel die voor de verwerking belangrijk is. Ze afwijzen maakt afwijkingen zichtbaar, maar vereist dat schemawijzigingen zorgvuldig worden beheerd. In toepassingen waar onbedoelde velden risico opleveren, is afwijzen doorgaans veiliger. Bij een tolerant importproces kan gecontroleerd negeren passend zijn, zolang de afwijking wordt geregistreerd.

Pas niet automatisch typeconversies toe om validatiefouten te laten verdwijnen. Een string met cijfers omzetten naar een integer kan in sommige gegevensstromen bruikbaar zijn, maar conversie van lege strings, decimale waarden of notaties met komma’s kan een andere betekenis opleveren. Als normalisatie gewenst is, maak die stap afzonderlijk en controleerbaar. Bewaar zo nodig de oorspronkelijke uitvoer, zodat duidelijk blijft wat het model aanleverde en welke transformaties de applicatie heeft uitgevoerd.

Optionele waarden, null en ontbrekende velden uit elkaar houden

Een optioneel veld kan op verschillende manieren worden weergegeven: het ontbreekt, het bevat null of het bevat een waarde. Die toestanden zijn niet vanzelf hetzelfde. Een ontbrekende waarde kan betekenen dat het model geen antwoord heeft gevonden; null kan betekenen dat de waarde bewust niet van toepassing is. Een lege string is weer iets anders: die kan een echte, maar lege invoer vertegenwoordigen of een onbedoelde manier zijn om onzekerheid uit te drukken.

In JSON Schema betekent een veld niet verplicht maken doorgaans dat de sleutel mag ontbreken. Dat maakt de waarde niet automatisch nullable. Als zowel afwezigheid als null geldig moet zijn, moet het schema dat expliciet toestaan, bijvoorbeeld door het type uit te breiden. De keuze moet aansluiten op de betekenis in de applicatie. Als een veld later wordt gebruikt om een besluit te nemen, kan een expliciet statusveld zoals beschikbaar, onbekend of niet van toepassing duidelijker zijn dan meerdere impliciete varianten.

Leg ook vast hoe downstream-code met iedere toestand omgaat. Een databasekolom kan afwezigheid en null anders behandelen dan een API-serializer; een update kan een ontbrekend veld interpreteren als behoud de bestaande waarde, terwijl null de waarde wist. Zonder afgesproken semantiek kan een geldige AI-respons dus alsnog tot ongewenste wijzigingen leiden. Test ontbrekende sleutels, null, lege strings en normale waarden afzonderlijk, ook als sommige gevallen uiteindelijk naar dezelfde interne representatie worden omgezet.

Validatie uitvoeren voordat AI-gegevens worden verwerkt

Valideer de uitvoer voordat die een database-update, workflow, toolaanroep of zakelijke beslissing activeert. Een robuuste verwerkingsketen controleert eerst of de modelaanroep succesvol was, parseert vervolgens de JSON en valideert daarna de structuur. Pas na die stappen volgt eventuele normalisatie en inhoudelijke domeinvalidatie. Deze volgorde maakt fouten beter te lokaliseren: een parsefout is iets anders dan een ontbrekend veld, en beide verschillen van een geldig getal dat buiten de toegestane bedrijfsgrens valt.

Structurele validatie controleert bijvoorbeeld dat een veld een integer is. Domeinvalidatie kan aanvullend controleren of de waarde bij een bestaande entiteit hoort, of een datum binnen een toegestane periode valt en of een combinatie van velden logisch is. JSON Schema kan sommige onderlinge voorwaarden uitdrukken, maar complexe regels zijn vaak beter zichtbaar in expliciete applicatiecode. Verdeel verantwoordelijkheden bewust, zodat een schema geen onleesbare verzameling uitzonderingen wordt en bedrijfsregels niet verspreid raken over meerdere systemen.

Voer bij gevoelige handelingen ook controle uit op autorisatie en herkomst. Een schema bewijst niet dat een gebruiker bevoegd is om de gevraagde actie uit te voeren, en een syntactisch geldige identifier kan naar de verkeerde klant wijzen. Gebruik gevalideerde gegevens pas nadat de identiteit, context en toegangsrechten zijn gecontroleerd. Houd de validatiestap bovendien deterministisch waar mogelijk: dezelfde invoer moet onder dezelfde regels hetzelfde resultaat geven, zodat tests en incidentanalyse niet afhankelijk zijn van een nieuwe modelgeneratie.

Foutafhandeling bij ongeldige JSON en schema-afwijkingen

Een mislukte validatie hoeft niet altijd tot dezelfde reactie te leiden. Een tijdelijke API-storing vraagt om een andere behandeling dan een antwoord dat structureel afwijkt. Classificeer fouten daarom bijvoorbeeld als transportfout, onvolledige generatie, JSON-parsefout, schemafout of domeinfout. Die indeling maakt gerichte herstelacties mogelijk en voorkomt dat de applicatie elke afwijking oplost door het model opnieuw aan te roepen.

Een beperkte herstelpoging kan passend zijn wanneer een antwoord afgebroken is of een eenvoudig veld ontbreekt. Geef daarbij alleen de relevante foutmelding en de oorspronkelijke taakcontext mee, en vraag om een gecorrigeerde uitvoer binnen hetzelfde schema. Stel een maximum in voor pogingen. Herhaalde generatie kan anders kosten en wachttijd vergroten, terwijl een model dezelfde fout blijft maken of bij iedere poging nieuwe afwijkingen introduceert. Bij een inhoudelijke tegenstrijdigheid is opnieuw genereren bovendien niet per definitie een betrouwbare oplossing.

Als herstel niet slaagt, zet het item dan in een gecontroleerde foutstatus in plaats van gedeeltelijke gegevens te verwerken. Voor batchverwerking kan een afzonderlijke wachtrij voor handmatige beoordeling of herverwerking geschikt zijn. Log voldoende informatie om de fout te onderzoeken, maar voorkom dat gevoelige persoonsgegevens of volledige prompts onnodig in logs terechtkomen. Registreer onder meer schema-versie, foutcategorie en veldpad. Zo kan een terugkerende afwijking worden opgelost in de prompt, het schema of de applicatielogica, zonder dat foutafhandeling zelf onvoorspelbaar gedrag introduceert.

Schemawijzigingen, tests en monitoring van AI-uitvoer

Een JSON Schema is een contract tussen de modelaanroep en de applicatie. Wanneer een veld van optioneel naar verplicht gaat, een enum wordt uitgebreid of een type verandert, kan bestaande verwerking breken. Beheer schema’s daarom met versies en behandel wijzigingen als interfacewijzigingen. Een toevoeging die oude consumenten niet hindert, is doorgaans eenvoudiger dan een wijziging in betekenis of type. Als meerdere diensten hetzelfde resultaat verwerken, moeten zij dezelfde versie en interpretatie gebruiken.

Test niet alleen voorbeelden die geldig horen te zijn, maar ook gevallen die bewust moeten worden afgewezen: ontbrekende sleutels, verkeerde typen, onbekende velden, null waar dat niet is toegestaan en grenswaarden. Voeg representatieve modeluitvoer toe aan regressietests. Die tests bewijzen niet dat een taalmodel zich altijd hetzelfde gedraagt, maar laten wel zien of veranderingen in prompts, modellen of schema’s tot afwijkende resultaten leiden. Test daarnaast de foutpaden, zoals lege antwoorden, afgebroken JSON en API-foutresponsen.

Monitoring moet meer tonen dan het totale aantal mislukte verzoeken. Houd per schema-versie bij welk percentage antwoorden parsebaar en valide is, welke velden het vaakst falen en hoeveel herstelpogingen nodig zijn. Een plotselinge stijging kan wijzen op een modelwijziging, een promptaanpassing of een onbedoeld strenger schema. Koppel die signalen aan voldoende context om verschillen te onderzoeken, maar begrens en anonimiseer opgeslagen inhoud waar dat nodig is. Zo wordt schema-validatie niet alleen een eenmalige controle, maar ook een meetbaar onderdeel van het beheer van AI-integraties.

Veelgestelde vragen

Controleert JSON Schema het formaat van datums automatisch?

Niet altijd: de regel format voor een datum of tijdstip wordt niet door iedere JSON Schema-validator als harde controle toegepast. Sommige validators behandelen zo’n formaat alleen als aanvullende beschrijving. Controleer daarom de instellingen en mogelijkheden van de validator die je gebruikt.

  • Test of ongeldige waarden, zoals een onmogelijke kalenderdatum, worden afgewezen.
  • Bepaal expliciet of een tijdzone verplicht is.
  • Valideer aanvullende afspraken, zoals een toegestane periode, in applicatiecode.

Zo voorkom je dat een datum die er geldig uitziet toch onjuiste of onvolledige informatie bevat.

Hoe gebruik ik $ref en $defs om een JSON Schema herbruikbaar te maken?

Je maakt een schema herbruikbaar door terugkerende structuren in $defs te definiëren en ze met $ref op de benodigde plekken aan te wijzen. Dat is handig wanneer meerdere velden of schema’s bijvoorbeeld dezelfde adres- of identificatiestructuur gebruiken: wijzigingen hoeven dan niet op meerdere plaatsen te worden bijgehouden.

  • Geef definities duidelijke namen.
  • Controleer of de validator en model-API lokale en externe verwijzingen ondersteunen.
  • Vermijd verwijzingen naar schema’s die tijdens verwerking kunnen veranderen.

Test het volledige schema nadat verwijzingen zijn opgelost; een geldige definitie garandeert niet dat elke verwijzing correct is aangesloten.

Wat is het verschil tussen gestructureerde uitvoer en function calling?

Gestructureerde uitvoer vraagt het model om een antwoord in een afgesproken gegevensvorm, terwijl function calling het model laat voorstellen om een specifieke functie of tool aan te roepen. De eerste optie past bijvoorbeeld bij classificaties of extractieresultaten; de tweede bij taken waarbij de applicatie een actie kan uitvoeren.

  • Valideer ook de argumenten van een voorgestelde functieaanroep.
  • Behandel een toolaanroep niet als toestemming om die automatisch uit te voeren.
  • Controleer autorisatie en context voordat een actie plaatsvindt.

Een functieaanroep kan dus structureel geldig zijn en toch onveilig of ongewenst zijn om uit te voeren.

Welke statistieken moet ik monitoren voor AI-uitvoer met JSON Schema?

Monitor niet alleen hoeveel antwoorden het schema doorstaan, maar ook waar fouten ontstaan en of die veranderen in de tijd. Een hoog validatiepercentage zegt op zichzelf bijvoorbeeld niet dat de inhoud bruikbaar is of dat een wijziging geen nieuwe problemen veroorzaakt.

  • Meet parsefouten en schemafouten afzonderlijk.
  • Volg foutpercentages per veld, foutcategorie en schemaversie.
  • Registreer het aantal herstelpogingen en items dat handmatige beoordeling nodig heeft.
  • Vergelijk resultaten na wijzigingen aan prompts, modellen of schema’s.

Gebruik geaggregeerde gegevens waar mogelijk en leg geen gevoelige uitvoer vast als dat niet nodig is voor onderzoek.

Hoe test ik AI-uitvoer als modelantwoorden niet deterministisch zijn?

Test de vaste verwerkingsregels los van de modelgeneratie en gebruik representatieve, opgeslagen antwoorden om de validator en vervolgcode te controleren. Zo kan een wijziging in applicatiecode worden getest zonder dat een nieuwe modelaanroep toevallig een ander antwoord oplevert.

  • Gebruik fixtures voor geldige, ongeldige en grensgevallen.
  • Mock de modelaanroep in unit- en integratietests.
  • Controleer dat foutcategorieën en veldpaden correct worden afgehandeld.
  • Voer daarnaast periodiek evaluaties uit met echte modelaanroepen en beoordeel die op afgesproken criteria.

Verwacht daarbij geen identieke tekst bij elke generatie; toets de structuur en gewenste eigenschappen van het resultaat.

Portret van Maarten

Maarten

Freelance developer in Nijmegen

Even kennismaken?

Vertel kort wat er speelt. Dan hoor je wat er kan, wat ik anders zou doen en waar AI bij jou wél en niet iets toevoegt. Vrijblijvend.

[email protected]
Het kantoor in Nijmegen
© 2026 maarten.online Sitemap Privacy Algemene voorwaarden
Het kantoor in Nijmegen

Maarten.

Freelance developer in Nijmegen. Liever direct contact? Dat kan ook.

Kennismaken

Laat je gegevens achter, dan kijken we of het klikt. Vrijblijvend en zonder verkooppraat.

Maarten

Stuur een bericht via WhatsApp

Hoi! Waar kan ik je mee helpen?

nu