
Samengesteld door de llmnet.nl-redactie met AI-ondersteuning · Laatst bijgewerkt: 27 juli 2026
Als je applicaties bouwt met Large Language Models (LLM's), is een van de grootste frustraties het onvoorspelbare antwoordformaat. Je vraagt om een schone JSON-output die je direct in je database wilt parsen, maar het model besluit vriendelijk te zijn en antwoordt met: "Natuurlijk! Hier is de JSON die je zocht: ```json { ... } ``` Ik hoop dat dit helpt!". Dit soort conversatie-ruis breekt je code direct.
Het betrouwbaar afdwingen van machine-leesbare formaten zoals JSON, CSV en XML vereist specifieke technieken. In dit artikel behandelen we hoe je met pure prompting het outputformaat strak dicteert, hoe je omgaat met afwijkingen, hoe je validatieloops opzet, en wanneer je beter de overstap kunt maken naar API-specifieke functionaliteiten zoals function calling.
Om te begrijpen hoe we dit probleem oplossen, moeten we eerst kijken naar de aard van de modellen. LLM's zijn in de basis text completion engines. Ze voorspellen simpelweg het volgende woord (token) op basis van de context. Tijdens de trainingsfase (met name via Reinforcement Learning from Human Feedback, RLHF) worden deze modellen getraind om behulpzaam, beleefd en uitgebreid te zijn in gesprekken met mensen.
Deze mensgerichte training staat haaks op wat een systeemintegratie nodig heeft. Een parser heeft geen behoefte aan een beleefde introductie of een uitgebreide conclusie; die wil uitsluitend ruwe, goed geformatteerde data. Als je niet expliciet tegen het model zegt dat het zich niet als een behulpzame assistent mag gedragen, zal het altijd terugvallen op deze conversationele standaard.
De meest toegankelijke manier om een formaat af te dwingen is door je prompts te optimaliseren. Dit doen we door het gewenste schema letterlijk te definiëren, voorbeelden te geven en systeeminstructies te verfijnen.
Vraag niet zomaar om "een JSON". Een LLM heeft structuur nodig. Geef het exacte schema mee waaraan het antwoord moet voldoen. Voor JSON werkt het vaak goed om een TypeScript interface of een versimpeld JSON Schema mee te sturen. Dit geeft het model niet alleen de datastructuur, maar ook de exacte sleutelnamen en datatypes.
Een effectief promptfragment voor JSON:
Genereer een profiel van de beschreven persoon in het volgende JSON-formaat.
Je output moet exact matchen met dit TypeScript schema:
interface Persoon {
voornaam: string;
achternaam: string;
leeftijd: number;
beroep: string | null;
vaardigheden: string[];
}
Geef uitsluitend de JSON terug. Voeg geen extra tekst toe.
Voor XML of CSV geldt hetzelfde principe. Definieer de exacte headers of de XML-tags. Voor CSV is het bovendien belangrijk om het scheidingsteken expliciet te benoemen, aangezien een komma in een tekstveld de hele structuur kan breken als deze niet goed wordt "geëscaped".
De effectiefste manier om een LLM te dwingen een bepaald formaat aan te houden, is door het simpelweg voor te doen. Dit staat bekend als few-shot prompting. Door het model meerdere voorbeelden te geven van een input en de bijbehorende perfect geformatteerde output, dwing je het in een specifiek voorspellingspatroon.
Een voorbeeld voor CSV-extractie:
Extraheer de bestelinformatie uit de tekst en formatteer dit als CSV.
Scheidingsteken: puntkomma (;).
Zet tekstvelden met leestekens tussen dubbele aanhalingstekens ("").
Input: "Ik wil graag 3 appels en 2 bananen bestellen, op naam van Jan."
Output:
product;aantal;klant
appels;3;Jan
bananen;2;Jan
Input: "Lever 10 laptops af bij de IT-afdeling. Contactpersoon is mevrouw De Vries."
Output:
product;aantal;klant
laptops;10;De Vries
Input: [JOUW DYNAMISCHE INPUT HIER]
Output:
Door te eindigen met de letterlijke tekst Output: forceer je het model om direct met de data te beginnen en de introductie over te slaan.
Als je gebruikmaakt van een model via een API, plaats je formatteringsinstructies dan bij voorkeur in de systeemprompts. Systeeminstructies dragen bij de meeste moderne modellen meer gewicht dan gebruikersprompts. Ze zetten het fundamentele gedrag van het model vast voor de gehele sessie.
Zelfs met een goed schema en voorbeelden is de kans aanwezig dat het model de output verpakt in markdown-blokken (zoals ```json). Om dit te voorkomen, moet je zogenaamde negative constraints of expliciete verboden toevoegen aan je prompt.
Wees hierbij direct en ondubbelzinnig. Vermijd zachte taal zoals "probeer te voorkomen dat". Gebruik in plaats daarvan harde commando's. Hoewel modellen steeds beter worden in het volgen van deze regels, is het een best practice om ze in hoofdletters of als een opsomming te presenteren.
Ondanks je beste prompts, zal een LLM in een productieomgeving soms alsnog afwijken. Het model hallucineert dan toch een introductie. Je moet je applicatie hier weerbaar tegen maken met slimme parsing logica aan de backend.
Probeer nooit direct de ruwe output in JSON.parse() of een XML-parser te gooien zonder validatie. Een robuuste strategie is om reguliere expressies (regex) te gebruiken om de datastructuur uit de tekst te isoleren.
Voor JSON betekent dit dat je zoekt naar het eerste { of [ karakter, en het laatste } of ] karakter. Alles wat daarvoor of daarna staat, strip je weg. Voor XML kun je zoeken naar de begin- en eindtag van je root-element. Hoewel dit geen vervanging is voor goede prompting, is het een onmisbaar vangnet dat 99% van de kleine weigeringen (zoals de beruchte markdown-blokken) opvangt.
Als zowel je prompt als je regex-parser falen (bijvoorbeeld omdat de JSON syntax zelf corrupt is, zoals een ontbrekende komma of een ongeëscaped aanhalingsteken binnen een string), heb je een fallback-mechanisme nodig. Dit is waar prompt-chaining en automatische repareer-loops uitkomst bieden.
Het concept is verrassend simpel, maar buitengewoon effectief. Wanneer je code een syntaxfout detecteert (bijvoorbeeld een SyntaxError in JavaScript of een JSONDecodeError in Python), vang je deze fout af in een try-catch blok. Vervolgens stuur je de foutmelding, samen met de corrupte output, geautomatiseerd terug naar de LLM met de opdracht om zichzelf te corrigeren.
Een typische repareer-prompt ziet er zo uit:
Je vorige antwoord was geen geldige JSON.
De parser gaf de volgende foutmelding: [FOUDMELDING HIER INVOEGEN]
Hier is de ongeldige output die je genereerde:
[CORRUPTE OUTPUT HIER INVOEGEN]
Analyseer de fout, repareer de structuur en geef uitsluitend de gecorrigeerde, geldige JSON terug.
In de praktijk lost een LLM zijn eigen formateringsfouten in de eerste repareer-poging vrijwel altijd op. Stel wel een harde limiet in op deze loop (bijvoorbeeld maximaal twee pogingen) om eindeloze API-kosten en loops te voorkomen.
Hoewel je met prompting indrukwekkende resultaten kunt behalen, is het niet de meest stabiele oplossing voor enterprise-applicaties met complexe schema's. Als je werkt met geavanceerde modellen zoals GPT-4 of Claude 3, biedt de API-laag robuustere mechanismen.
Sinds de introductie van API integraties voor LLM's met functionaliteiten zoals JSON Mode, Function Calling (ook wel Tool Use genoemd) en Structured Outputs, is het afdwingen van formaten veel directer geworden.
Veel API's bieden inmiddels een parameter aan (zoals response_format: { "type": "json_object" }). Hiermee dwing je het model op backend-niveau om uitsluitend een valide JSON-string te genereren. Je moet nog steeds in je prompt om JSON vragen en een schema meegeven, maar de kans op conversatie-ruis is vrijwel nihil.
In plaats van het model te vragen een JSON te genereren, definieer je een 'functie' met parameters in de API-aanroep. Je vertelt het model: "Je hebt toegang tot de functie sla_gebruiker_op met de argumenten naam (string) en leeftijd (integer)". Het model zal vervolgens de argumenten extraheren en deze als een perfect gestructureerd JSON-object naar de API sturen om de functie 'aan te roepen'. Dit garandeert niet alleen het JSON-formaat, maar vaak ook de validiteit van de datatypes.
Recente updates van partijen zoals OpenAI maken gebruik van 'Constrained Decoding'. Hierbij geef je een JSON Schema mee aan de API, waarna de inference-engine op token-niveau wordt geblokkeerd om iets anders te genereren dan tokens die perfect in dat schema passen. Dit geeft een 100% garantie op zowel het JSON-formaat als de validiteit van het schema, zonder dat er complexe prompts of repareer-loops aan te pas hoeven te komen.
Het afdwingen van outputformaten is een gelaagd proces. Begin altijd met een heldere prompt waarin het schema, duidelijke voorbeelden en strikte verboden op extra tekst zijn opgenomen. Maak je code robuust met regex-extractie en overweeg een automatische repareer-loop voor incidentele syntaxfouten. Voor complexe of missiekritieke datastructuren is het echter sterk aan te raden om de ruwe prompting-fase voorbij te stappen en direct gebruik te maken van de Structured Output of Function Calling functionaliteiten van de LLM-provider.