Naar de inhoud
NLEN
Illustratie: Herstelprompts bij gefaalde validatie van LLM-output

Herstelprompts bij gefaalde validatie van LLM-output

Door Ivo Donker — samengesteld met AI-ondersteuning (Claude & Gemini)

In productie-architecturen waarin taalmodellen worden ingezet voor data-extractie, geautomatiseerde besluitvorming of integraties met externe API's, is determinisme een vereiste. Grote taalmodellen genereren echter probabilistische tekst. Zelfs met strikte systeemprompts, type-hints en schema-instructies komt het regelmatig voor dat de gegenereerde output faalt tijdens de validatiefase. Een JSON-document mist een verplichte sleutel, een veld bevat een string in plaats van een integer, of de semantische inhoud overschrijdt de gestelde bedrijfsregels.

Wanneer parsing of validatie faalt, is simpelweg dezelfde prompt opnieuw versturen (een 'blind retry') zelden de meest efficiënte oplossing. Het model heeft immers al een probabilistisch pad gekozen dat tot een fout leidde. Een gerichte herstelprompt (ook bekend als error reflection prompt of repair prompt) injecteert de specifieke validatiefout terug in de context van het model. Hierdoor kan het model gericht reflecteren op zijn eigen fout en een gecorrigeerd antwoord leveren binnen een gecontroleerde lus.

De architectuur van een validatie- en herstellus

Een robuuste integratie behandelt de aanroep naar een taalmodel als een onbetrouwbare externe component. Tussen de LLM-respons en de ontvangende applicatielogica bevindt zich altijd een strikte validatielaag. Deze laag controleert de ruwe tekst op syntaxis, structuur en domeinregels voordat de data verder door de softwarepijplijn stroomt.

Het fundament van betrouwbare interfaces begint bij de manier waarop je de initiële instructie formuleert; lees in hoe je een LLM betrouwbaar in een vast outputformaat laat antwoorden welke prompt-patronen de kans op initiële fouten minimaliseren. Blijft de parser alsnog steken, dan activeert de orchestrator de herstellus:

De vier fasen van de herstellus:
  1. Generatie: Het model ontvangt de initiële taakprompt en retourneert een ruwe payload.
  2. Validatie: Een lokale parser (zoals Pydantic, Zod of een custom JSON-schema validator) toetst de uitvoer.
  3. Diagnose & Extractie: Bij een fout genereert de validator een gestructureerde foutmelding inclusief pad, verwachte waarde en daadwerkelijke waarde.
  4. Herstel-injectie: Een dynamische herstelprompt wordt samengesteld en met minimale context naar het model gestuurd voor correctie.

Door deze lus programmatisch te begrenzen tot maximaal twee of drie iteraties, voorkom je oneindige lussen en onnodig oplopende tokenkosten wanneer een taak fundamenteel niet uitvoerbaar blijkt.

Syntactische versus semantische validatiefouten

Om een effectieve herstelprompt op te stellen, moet de applicatie onderscheid maken tussen de aard van het falen. Niet elke fout vereist dezelfde instructiestrategie.

Foutcategorie Typische manifestatie Oorzaak in LLM Herstelstrategie
Syntactisch Ongeldige JSON, ontbrekende sluitaccolades, markdown-ticks rond payload, trailing comma's. Tokenlimiet bereikt, stream vroegtijdig afgebroken, chat-formaat vervuiling. Minimale instructie: toon foutlocatie en vraag uitsluitend om ruwe syntactische correctie.
Structureel Ontbrekende verplichte velden, foutieve veldnamen, geneste objecten die plat zijn geslagen. Aandachtsverlies bij lange contexten, verwarring over schemadefinitie. Herhaal het schema met nadruk op de ontbrekende sleutel en het vereiste JSON-type.
Semantisch / Bereik Waarde buiten toegestaan bereik (bijv. score > 100), datum in het verleden, ongeldige enum-waarde. Gebrekkige domeinrestricties in basisprompt, hallucinatie van categorieën. Injecteer de specifieke bedrijfsregel samen met de afgekeurde waarde.

Voor diepgaande geautomatiseerde validaties tegen schema-definities kun je de werking controleren met de JSON Schema Output Validator & Benchmark Tool om te zien hoe verschillende schema-complexiteiten scoren op parserfouten.

Anatomie van een gerichte herstelprompt

Een veelgemaakte ontwerpfout is een generieke foutmelding sturen, zoals: "Je output was ongeldig, probeer het opnieuw." Het model mist dan de diagnostische context om te begrijpen wat er misging, en zal vaak dezelfde syntactische constructie herhalen.

Een succesvolle herstelprompt bevat vier vaste componenten:

Hieronder staat een concreet sjabloon voor een herstelprompt bij een Pydantic- of Zod-validatiefout:

Je vorige respons voldeed niet aan het vereiste validatieschema.

GEGEVEN OUTPUT:
```json
{
  "klant_id": "NL-8921",
  "status": "in_behandeling",
  "factuurbedrag": "honderdtwintig euro",
  "betaald": false
}
```

VALIDATIEFOUT:
- Veld: `factuurbedrag`
- Fout: `value_error.number.not_a_number`
- Verwacht type: `float` (bijvoorbeeld 120.00)
- Ontvangen waarde: "honderdtwintig euro"

OPDRACHT:
Corrigeer de foutieve waarde(n). Retourneer het volledige, herstelde JSON-object.
Genereer GEEN toelichting, GEEN excuses en GEEN markdown-opmaak buiten het JSON-blok.

Contextbeheer: Append-in-history versus Isolated Repair

Bij het doorvoeren van een herstelpoging zijn er twee dominante architectuurpatronen voor het beheren van het contextvenster:

1. De conversationele append-strategie

Hierbij voeg je de foutieve output toe als een assistant-bericht en de herstelprompt als een nieuw user-bericht in de bestaande chathistorie. Voordeel: Het model behoudt de volledige context van de initiële taak en de brondocumenten. Nadeel: Het contextvenster groeit snel, wat leidt tot hogere latency en kosten per token. Daarnaast kan de aanwezigheid van de foutieve output in de context het model biasen om opnieuw vergelijkbare patronen te genereren.

2. De geïsoleerde herstelprompt (Isolated Single-Turn Repair)

In dit patroon stuur je uitsluitend het foutieve JSON-fragment en de validatiefout naar een lichter, sneller model (of een aparte stateless API-call). Het model hoeft de oorspronkelijke brontekst van 10.000 tokens niet opnieuw te lezen; het krijgt alleen de opdracht om het JSON-fragment syntactisch of typematig te repareren. Wanneer taken worden opgesplitst over meerdere gespecialiseerde stappen, biedt prompt-chaining voor complexe taken het juiste raamwerk om herstelacties los te koppelen van de zware analyse-stappen.

Sampling-parameters aanpassen tijdens herstel

Wanneer een model faalt bij een deterministische taak, draait de initiële aanroep vaak met een lage temperatuur (bijvoorbeeld temperature: 0.0 of 0.1). Als de gegenereerde output faalt en je stuurt een herstelprompt met exact dezelfde parameters, bestaat het risico dat het model vastzit in een lokaal minimum van zijn probabilistische verdeling.

Tijdens herstelpogingen is het raadzaam om de sampling-instellingen dynamisch aan te passen. Verhoog de temperatuur marginaal naar 0.2 of 0.3, of pas top_p aan om alternatieve tokenpaden toe te staan. Een compleet overzicht van de interactie tussen deze variabelen vind je in temperature, top-p en andere sampling-parameters uitgelegd, waar de invloed van sampling op determinisme gedetailleerd wordt behandeld.

Implementatievoorbeeld in Python met Pydantic

In moderne backend-systemen combineer je type-validatie met automatische foutafhandeling. Het onderstaande Python-voorbeeld toont een robuuste lus waarin Pydantic-validatiefouten automatisch worden vertaald naar een gestructureerde herstelprompt.

import json
from typing import Optional, Dict, Any
from pydantic import BaseModel, Field, ValidationError

class FactuurModel(BaseModel):
  factuurnummer: str = Field(description="Formaat: INV-XXXX")
  totaalbedrag: float = Field(gt=0, description="Bedrag exclusief btw, strictly positief")
  valuta: str = Field(pattern="^(EUR|USD|GBP)$")
  geaccordeerd: bool

def valideer_en_herstel(
    ruwe_llm_output: str, 
    llm_client, 
    max_pogingen: int = 2
) -> Optional[FactuurModel]:
  huidige_output = ruwe_llm_output
  
  for poging in range(max_pogingen + 1):
    try:
      # Stap 1: Parseer JSON
      schone_json = huidige_output.strip()
      if schone_json.startswith("```json"):
        schone_json = schone_json.split("```json")[1].split("```")[0].strip()
      data = json.loads(schone_json)
      
      # Stap 2: Valideer tegen Pydantic model
      gevalideerd = FactuurModel.model_validate(data)
      return gevalideerd

    except (json.JSONDecodeError, ValidationError) as fout:
      if poging == max_pogingen:
        # Geen pogingen meer over: failover
        return None
      
      # Stap 3: Bouw de specifieke herstelprompt
      fout_beschrijving = str(fout)
      herstel_prompt = f"""De vorige JSON-output bevatte validatiefouten.
FOUTMELDING:
{fout_beschrijving}

ORIGINELE OUTPUT:
{huidige_output}

INSTRUCTIE:
Herstel de data zodat deze exact voldoet aan het schema:
- factuurnummer: string (INV-XXXX)
- totaalbedrag: float groter dan 0
- valuta: EUR, USD of GBP
- geaccordeerd: boolean

Retourneer uitsluitend het gecorrigeerde JSON-object."""

      # Stap 4: Roep het model opnieuw aan
      respons = llm_client.chat(
        messages=[{"role": "user", "content": herstel_prompt}],
        temperature=0.1 + (poging * 0.1)
      )
      huidige_output = respons.content

  return None

Valkuilen en anti-patronen bij geautomatiseerd herstel

Het implementeren van herstelprompts brengt specifieke risico's met zich mee die de betrouwbaarheid van een applicatie kunnen ondermijnen als ze niet goed worden gemonitord:

1. De beleefdheidsvalkuil (Apologetic Drift)

Wanneer een model te horen krijgt dat het een fout heeft gemaakt, start het zijn antwoord vaak met excuses: "Mijn excuses voor de fout. Hier is het gecorrigeerde JSON-object...". Als de parser downstream direct een JSON-payload verwacht, faalt de herstelpoging direct opnieuw door deze inleidende tekst. Dwing in de herstelinstructie expliciet af dat meta-communicatie verboden is.

2. Verlies van brongetrouwheid (Correction Hallucination)

Als een model een ontbrekend veld moet corrigeren terwijl de benodigde informatie niet in de oorspronkelijke brontekst aanwezig was, zal een herstelprompt het model forceren om een waarde te verzinnen om de validator tevreden te stellen. Zorg ervoor dat het datamodel voorziet in null-waarden of optionele velden voor ontbrekende gegevens.

3. Oneindige cascades in agentic workflows

In complexe autonome agent-systemen kunnen herstelprompts leiden tot vicieuze cirkels waarin twee componenten elkaars output blijven afkeuren. Lees in agentic loops debuggen: waar het vaak misgaat hoe je dit soort recursieve fouten tijdig detecteert en afbreekt.

Daarnaast is het cruciaal om vangrails in te bouwen die voorkomen dat het model buiten zijn bevoegdheden treedt tijdens herstel; zie guardrails voor prompts: blokkades en uitwijkregels voor beproefde methoden om grenzen af te bakenen.

Herstelprompts versus Native Structured Output

Moderne LLM-providers bieden steeds vaker native methoden om JSON-schema's op token-niveau af te dwingen (zoals grammars of constrained decoding via de API). Het is belangrijk om te weten wanneer herstelprompts noodzakelijk blijven en wanneer je native schema-enforcement kiest.

Een diepgaande analyse over de keuze tussen harde API-schema's en sturing vanuit de prompt vind je in output afdwingen: promptregels of API-schema. Daarnaast biedt de gids over betrouwbare JSON en structured output uit LLM's halen concrete voorbeelden van hoe constrained decoding op gateway-niveau werkt.

Eigenschap Native API Structured Output Herstelprompts (Reflection Loop)
Syntactische garantie 100% gegarandeerd geldige JSON-syntaxis via constrained decoding. Probabilistisch; vereist 1 tot 3 iteraties om fouten op te lossen.
Semantische validatie Beperkt (kan geen complexe business rules of cross-field validaties afdwingen). Uitstekend geschikt voor semantische fouten, bereikcontroles en logische checks.
Provider-onafhankelijkheid Laag; API-parameters verschillen sterk per leverancier. Hoog; werkt uniform over commerciële API's en lokale opensource-modellen.
Latency Minimaal (geen extra roundtrips nodig voor syntaxis). Hoger bij fouten (elke herstelpoging is een extra netwerkaanroep).

Metrics en monitoring: Wat kost herstel in productie?

Om de effectiviteit van herstelprompts inzichtelijk te houden, moet de engineering-omgeving twee kernstatistieken continu meten:

First-Pass Success Rate (FPSR): Het percentage verzoeken dat zonder enige validatiefout door de eerste parsering komt.

Recovery Success Rate (RSR): Het percentage van de initieel gefaalde verzoeken dat binnen maximaal twee herstelpogingen alsnog succesvol valideert.

Wanneer de FPSR onder de 90% zakt, duidt dit op een structureel probleem in de basisprompt, een overdreven complex JSON-schema, of een model dat ongeschikt is voor de taak. Herstelprompts dienen als veiligheidsnet, niet als structurele vervanging voor een goed ontworpen initiële prompt. Als de RSR onder de 70% ligt, is de herstelprompt zelf waarschijnlijk te vaag geformuleerd en levert de foutcontext onvoldoende sturing aan het model.

Best practices voor productie-implementatie

Bij het uitrollen van herstelprompts in een productieomgeving gelden de volgende richtlijnen: