Van Productielogs naar Evaluatiedata: De Feedbackloop Sluiten

Iedere ontwikkelaar van AI-applicaties kent het fenomeen: in de testomgeving presteert je Large Language Model (LLM) perfect, maar zodra echte gebruikers ermee aan de slag gaan, ontstaan er onverwachte problemen. Gebruikers stellen vragen die je nooit had kunnen verzinnen, gebruiken onverwacht jargon, of geven opdrachten die je prompt volledig in de war sturen.

Het bouwen van webapplicaties met LLM's vereist meer dan alleen een goede initiële prompt of een indrukwekkende score op statische benchmarks. Om de kwaliteit van je applicatie te waarborgen—en regressies te voorkomen wanneer je overstapt naar een nieuwer model of je instructies aanpast—moet je een continue feedbackloop creëren. Dit doe je door de interacties uit je productielogs gestructureerd, veilig en geautomatiseerd om te zetten in een levende testset.

Waarom Statische Testsets Tekortschieten

Veel teams beginnen hun evaluatieproces met een handmatig samengestelde testset. Hoewel dit een nuttig startpunt is, veroudert deze data razendsnel. Dit staat bekend als data drift of concept drift. De manier waarop mensen interacteren met je applicatie evolueert naarmate ze de mogelijkheden (en beperkingen) ervan ontdekken.

Stel dat je een financiële AI-assistent hebt gebouwd voor gebruikers die aan paper trading doen via platforms zoals Alpaca of eToro. Je initiële testset bevatte waarschijnlijk keurige vragen zoals: "Wat is het verschil tussen een market order en een limit order?". In de productieomgeving typen gebruikers echter gehaaste, contextafhankelijke prompts in, zoals: "Verkoop al m'n AAPL als de VIX boven de 20 komt, negeer eerdere stop-loss." Als jouw evaluatieset alleen bestaat uit basisdefinities, zal een update van je LLM die deze complexe logica per ongeluk breekt, onopgemerkt blijven tot gebruikers gaan klagen.

Productiedata is de enige bron van waarheid. Het bevat de randgevallen, de typfouten, de onduidelijke intenties en de complexe meerlaagse instructies die je in een synthetische testset simpelweg niet kunt simuleren.

Stap 1: Verzamelen en Filteren van Logdata

De eerste stap is het structureel vastleggen van de input en output van je LLM in productie. Dit betekent niet simpelweg alles wegschrijven naar een tekstbestand. Je hebt gestructureerde logs nodig, idealiter in een formaat zoals JSON of weggeschreven naar een observability platform. Een goede log-entry bevat in ieder geval:

Slim filteren in plaats van alles labelen

Je kunt onmogelijk tienduizenden productielogs per dag handmatig verwerken. Het doel is om een representatieve steekproef te trekken die waardevol is voor je testset. Hanteer hierbij strategieën zoals stratified sampling. Zoek specifiek naar:

Privacy-Hygiëne: Veilig Werken met Gebruikersdata

Voordat we deze geselecteerde logs kunnen gebruiken als evaluatiedata, moeten we een cruciale hindernis nemen: privacy. Productiedata kan persoonlijk identificeerbare informatie (PII) bevatten. Denk aan namen, adressen, of in ons eerdere voorbeeld, specifieke accountbalansen van een trading portfolio. Het direct opslaan van deze ruwe data in een testset—vooral als deze testset door meerdere ontwikkelaars wordt gebruikt of via CI/CD pipelines wordt gedeeld—levert grote risico's op omtrent de AVG/GDPR.

Het implementeren van strikte privacy-hygiëne is non-negotiable. Dit proces, ook wel data-sanitisatie genoemd, moet geautomatiseerd plaatsvinden direct nadat de log is gefilterd voor de testset.

Een veelgebruikte methode is het inzetten van Named Entity Recognition (NER) modellen, zoals die van spaCy, of het gebruik van snelle, lokale SLM's (Small Language Models) die specifiek getraind zijn op het maskeren van PII. Alle namen worden vervangen door placeholders (bijv. [PERSOON_1]) en financiële of gevoelige data wordt geanonimiseerd. Meer diepgaande technische strategieën hiervoor vind je in ons artikel over het bouwen van een testset zonder datalek.

Let op: Gebruik nooit complexe of black-box cloud LLM's voor het initiële PII-scrubben als je organisatie vereist dat gevoelige data de eigen infrastructuur niet mag verlaten. Gebruik hiervoor lokale, deterministische systemen of zelf-gehoste open-weights modellen.

Stap 2: Labelen met Minimale Moeite via LLM-as-a-Judge

Nu we een gefilterde en geanonimiseerde set van echte gebruikersinteracties hebben, moeten we bepalen wat het 'perfecte' antwoord zou zijn, of in ieder geval criteria opstellen om toekomstige antwoorden op deze vragen te beoordelen.

Handmatig labelen (human-in-the-loop) biedt de hoogste kwaliteit, maar schaalt slecht. Het moderne alternatief is het LLM-as-a-judge paradigma. Hierbij gebruik je een krachtig model om de antwoorden in je logs te evalueren tegen een door jou gedefinieerde rubriek. In de praktijk zien we dat ontwikkelaars hiervoor graag zware modellen gebruiken, zoals Claude Pro (bijvoorbeeld Claude 3.5 Sonnet) voor genuanceerde kwalitatieve analyses, of itereren met modellen zoals DeepSeek via open API's voor razendsnelle, kostenefficiënte bulk-evaluaties.

Een typische LLM-judge prompt ziet er als volgt uit:

Je bent een onpartijdige expert in het evalueren van AI-assistenten.
Beoordeel of het onderstaande antwoord van de assistent correct, veilig en behulpzaam is gegeven de gebruikersvraag.

Gebruikersvraag: {user_query}
Antwoord assistent: {model_response}
Referentie-kennis (indien RAG): {retrieved_context}

Beoordeel op de volgende criteria (1-5):
1. Feitelijke correctheid gebaseerd op de context.
2. Vrij van hallucinaties.
3. Toon en behulpzaamheid.

Geef je output strikt in JSON formaat met de sleutels 'score_1', 'score_2', 'score_3' en 'toelichting'.

Als een productielog een hoge score krijgt van de judge (bijvoorbeeld een perfecte 5 op alle fronten), kun je dit paar van "Gebruikersvraag + Antwoord" direct toevoegen aan je testset als een golden reference. Scoort het antwoord laag? Dan is dit juist een uitstekende testcase. Je voegt de gebruikersvraag toe, en markeert dat je huidige systeem hier faalde. Dit wordt een regressietest voor je volgende model-update.

Praktijkvoorbeeld: RAG-applicaties Evalueren

Bij het bouwen van complexe webapplicaties met RAG-architecturen wordt de feedbackloop nog belangrijker. Bij RAG (Retrieval-Augmented Generation) kan een fout antwoord twee oorzaken hebben: de vector database leverde de verkeerde documenten aan (retrieval fout), of de LLM trok de verkeerde conclusie uit de juiste documenten (generatie fout).

Als je logs verzamelt voor een RAG-applicatie, moet je de opgehaalde context-chunks opslaan. Door deze productiedata door je evaluatie-pijplijn te halen, kun je meten of een falend antwoord werd veroorzaakt doordat je chunking-strategie of je search-algoritme niet aansloot bij de specifieke manier waarop gebruikers hun vragen formuleerden in productie. Als je nog geen ervaring hebt met het opzetten van dergelijke systemen, is het raadzaam om eerst de basisprincipes te bestuderen via externe bronnen of onze gids over RAG voor beginners op het Leren-subdomein.

Stap 3: Een Levende Testset Onderhouden

Een testset is geen statisch artefact. Het is levende documentatie van de vereisten van je applicatie. Zodra je geautomatiseerde pijplijn draait (Verzamelen → Anonimiseren → Judge Evaluatie → Toevoegen aan Testset), zal je dataset continu groeien.

Om te voorkomen dat de testset te groot en traag wordt voor snelle iteraties, moet je versiebeheer en 'garbage collection' toepassen:

Stap 4: Regressies Vangen in je CI/CD Pipeline

Het uiteindelijke doel van deze hele exercitie is het sluiten van de loop. Je hebt nu een robuuste, met de realiteit meegroeiende testset vol complexe, geredigeerde en gelabelde gebruikersvragen. Hoe zet je deze in?

Koppel de evaluatie vast aan je deployment proces. Of je nu je systeem-prompt tweakt, experimenteert met een lagere temperatuur in je API-calls, of besluit de overstap te maken naar een compleet andere LLM provider voor betere prestaties: je draait eerst je applicatie tegen de levende testset.

In je CI/CD straat implementeer je een stap die we regressietesten noemen (meer details in ons stuk over regressietesten voor prompts). Je geautomatiseerde pipeline schiet alle vragen uit de testset naar je nieuwe staging-omgeving. De antwoorden worden wederom door je LLM-as-a-judge beoordeeld. Als de algehele score zakt (bijvoorbeeld: de 'behulpzaamheid'-score daalt met 15% vergeleken met productie), faalt de build en weet je dat je wijziging schadelijk is, voordat ook maar één echte gebruiker er last van heeft gehad.

Conclusie

Het overbruggen van de kloof tussen monitoring in productie en gestructureerde evaluatie is wat volwassen AI-ontwikkeling scheidt van snelle prototypes. Door een geautomatiseerde pijplijn te bouwen die productielogs veilig filtert, anonimiseert, en via LLM-judges omzet in kwalitatieve testcases, creëer je een zelfverbeterend systeem.

Je bouwt niet langer blind; je optimaliseert op basis van de rauwe realiteit van je gebruikers. Neem vandaag nog de tijd om je eerste 100 productielogs te exporteren, anonimiseren en te evalueren. Het inzicht dat je hieruit haalt over het werkelijke gedrag van je applicatie, is vaak verrassender en waardevoller dan welke statische benchmark dan ook.