Observability en Logging voor LLM-toepassingen
Als je een traditionele REST API bouwt, is observability relatief rechttoe rechtaan. Je logt het endpoint, de HTTP-statuscode (meestal 200 of 500) en de responstijd. Bij Large Language Models (LLM's) gooi je deze klassieke aanpak het best direct overboord. Een LLM API is niet deterministisch. Een verzoek kan in de ene seconde 50 milliseconden duren en 2 tokens genereren, en vijf minuten later met exact dezelfde input 30 seconden duren en 4000 tokens teruggeven.
Zonder een doordachte observability-strategie vlieg je blind. Je kunt kostenpieken niet verklaren, je weet niet waarom een applicatie plotseling traag aanvoelt voor de eindgebruiker, en je hebt geen idee hoe vaak het model hallucineert of in een loop belandt. In dit artikel bespreken we precies wat je per call moet loggen, hoe je omgaat met de strenge privacy-eisen rondom prompts, hoe je complexe multi-step processen traceert en welke alerts écht waarde toevoegen voor je development- en operations-teams.
De basis: Wat moet je loggen per LLM API-call?
Om een robuust monitoringsysteem op te zetten, heb je gestructureerde logs (bij voorkeur in JSON) nodig voor elke interactie met de LLM. Dit stelt je in staat om later aggregaties en doorsnedes te maken. We categoriseren de benodigde datapunten in vier domeinen.
1. Configuratie en Context
Modellen veranderen onder water. Een update bij de provider kan ervoor zorgen dat jouw perfect afgestelde prompt ineens suboptimale resultaten levert. Log daarom altijd:
- Provider en Modelnaam: Bijvoorbeeld
openaiofanthropic, engpt-4-turbo. - Modelversie: Dit is cruciaal. Log niet alleen
gpt-4, maar de exacte iteratie zoalsgpt-4-0613. - Parameters:
temperature,top_p,max_tokensenfrequency_penalty. Deze bepalen mede de output en kosten. - Prompt-hash: Een cryptografische hash (zoals SHA-256) van de exacte prompt-tekst. Hierdoor kun je groeperen op identieke prompts zonder de daadwerkelijke, mogelijk privacygevoelige, tekst te hoeven opslaan.
2. Performance en Latency
Bij LLM's, vooral wanneer streaming wordt gebruikt, is de klassieke Total Latency niet voldoende om de gebruikerservaring te meten. Je hebt granulaire metrieken nodig:
- TTFT (Time To First Token): Hoe lang het duurt voordat de API de allereerste byte aan tekst terugstuurt. Dit is de belangrijkste metriek voor de perceptie van snelheid bij de eindgebruiker.
- TBT (Time Between Tokens): De gemiddelde tijd tussen het genereren van losse tokens tijdens een stream.
- Total Duration: De totale tijd van het initiële verzoek tot de API-connectie sluit.
3. Tokens en Kosten
Tokens zijn de valuta van LLM's. Je wilt op elk moment weten hoeveel een interactie kost. Voor een uitgebreide gids over hoe je deze data gebruikt voor financiële sturing, lees je ons artikel over kosten monitoren.
- Tokens in (Prompt tokens): Het aantal tokens dat naar het model is gestuurd.
- Tokens uit (Completion tokens): Het aantal gegenereerde tokens.
- Geschatte kosten: Bereken deze aan jouw kant (client-side) op basis van de token-aantallen en de huidige tarieven van de provider. Vertrouw niet uitsluitend op de billing-dashboards van de provider, deze lopen vaak uren achter.
4. Tracing en Identifiers
Fouten en bottlenecks komen altijd voor. Om deze te debuggen heb je sterke identifiers nodig. Zeker als je te maken krijgt met HTTP 429 (Too Many Requests), zoals beschreven in ons artikel over rate limits en kosten.
- Correlation-ID: Een unieke identifier voor het gehele gebruikerstraject, afkomstig uit je frontend of API-gateway.
- Request-ID: De unieke ID die de LLM-provider (bijv. OpenAI) meestuurt in de HTTP-headers van hun response.
- Foutcodes: De specifieke HTTP-status en de foutmelding in de body (bijv. context length exceeded).
Privacy en Security: Waarom je prompts niet zomaar opslaat
Het is verleidelijk om simpelweg de volledige inkomende prompt en de uitgaande response op te slaan in je loggingsysteem (zoals Elasticsearch, Datadog of Splunk) om later makkelijk te kunnen debuggen. Dit is in veel gevallen echter een enorme veiligheidsrisico en een schending van de GDPR (AVG).
Gebruikers voeren onvoorspelbare, ongestructureerde data in. Dit kan medische informatie, financiële gegevens of bedrijfsgeheimen bevatten (PII - Personally Identifiable Information). Als deze data onversleuteld in je gecentraliseerde logs belandt, creëer je direct een gigantisch datalek-risico. Ontwikkelaars met toegang tot de logs hebben dan plotseling toegang tot gevoelige persoonsgegevens. Voor meer context over veilige architecturen kun je onze externe gids over privacy by design voor LLM's raadplegen.
Hoe los je dit op?
- Hashing: Zoals eerder benoemd, gebruik een hash van de prompt. Voor analytische doeleinden wil je vaak alleen weten of prompt A vaker wordt gebruikt dan prompt B. Een hash is daarvoor voldoende.
- Data Masking / PII-scrubbing: Gebruik libraries (zoals Microsoft Presidio) om lokaal, vóórdat er gelogd wordt, namen, BSN-nummers, en e-mailadressen te vervangen door placeholders zoals
[PERSON]of[EMAIL]. Aanname hierbij is dat PII-detectie modellen ongeveer 95% accuraat zijn; handmatige controle of strikte retentie blijft nodig. - Shadow Logs met strikte TTL: Als je de ruwe tekst écht nodig hebt voor debug-doeleinden, sla deze dan op in een geïsoleerde, versleutelde database met sterk beperkte toegangsrechten (Role-Based Access Control) en een automatische Time-To-Live (TTL) van bijvoorbeeld 3 of 7 dagen. Na die periode wordt de tekst onherroepelijk verwijderd, terwijl de metagegevens (tokens, latentie) bewaard blijven in je reguliere logs.
Tracing over meerdere stappen (Agents & Chains)
Moderne LLM-toepassingen bestaan zelden uit één simpele call. Systemen die gebruikmaken van function-calling of complexe RAG-architecturen voeren vaak een keten van acties uit. Bijvoorbeeld: een gebruiker stelt een vraag, het systeem haalt data op uit een vector-database, roept een interne API aan via een LLM-tool, en gebruikt de resultaten om een finaal antwoord te genereren.
Als het antwoord 15 seconden duurt, waar zit dan de vertraging? Om dit te beantwoorden, leen je concepten uit OpenTelemetry, specifiek Traces en Spans.
- De Trace: Het volledige verzoek van de gebruiker (van begin tot eind). Krijgt een unieke
trace_id. - De Parent Span: De overkoepelende orkestratie (bijvoorbeeld de LangChain of LlamaIndex agent). Krijgt een
span_iden is gekoppeld aan detrace_id. - Child Spans: Elke individuele actie daaronder.
- Span 1: Vector Database query (50ms).
- Span 2: LLM call om te bepalen welke tool nodig is (800ms).
- Span 3: Uitvoeren van de weers-API (250ms).
- Span 4: Finale LLM call voor de samenvatting (3200ms).
Door elke log-entry te voorzien van een trace_id, een span_id, en een parent_span_id, kun je in tools zoals Jaeger of Datadog een waterval-grafiek genereren. Hierdoor zie je in één oogopslag dat de trage response niet lag aan het LLM-model, maar aan een time-out in Span 3 (de interne weers-API).
Een concreet logschema (JSON)
Om bovenstaande theorie concreet te maken, vind je hieronder een voorbeeld van een robuust JSON-logschema dat je per API-call (dus per span) naar je backend zou moeten schrijven.
{
"timestamp": "2026-07-25T22:23:07Z",
"environment": "production",
"application_name": "customer_support_bot",
"trace": {
"trace_id": "5b8d9c2e-4a6f-11ef-8b2b-0242ac120002",
"span_id": "a1b2c3d4-e5f6-7890",
"parent_span_id": "c3d4e5f6-7890-a1b2"
},
"llm_config": {
"provider": "openai",
"model": "gpt-4-0613",
"temperature": 0.2,
"max_tokens": 1000
},
"content_metadata": {
"prompt_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"tool_calls_requested": ["get_order_status"],
"finish_reason": "stop"
},
"metrics": {
"tokens_prompt": 450,
"tokens_completion": 125,
"tokens_total": 575,
"latency_ttft_ms": 420,
"latency_total_ms": 1850,
"cost_estimated_usd": 0.023
},
"status": {
"success": true,
"http_code": 200,
"provider_request_id": "req_8xV1..."
}
}
Dit schema is volledig vlak en geanonimiseerd (geen PII), maar rijk genoeg om complexe dashboards op te bouwen.
Troubleshooting: Latentie- en kostenpieken vinden
Met de data uit het bovenstaande schema ben je uitgerust om proactief problemen te vinden. Stel dat de maandelijkse factuur van de LLM-provider plotseling explodeert. Via je dashboards kun je nu groeperen op prompt_hash of tool_calls_requested.
Wellicht ontdek je dat een specifieke combinatie van een prompt en een interne database tool onnodig veel context meestuurt, waardoor tokens_prompt structureel boven de 8000 uitkomt. Omdat je de prompt_hash hebt, kun je terug in je versiebeheer zoeken welke prompt-template deze hash genereert, en deze optimaliseren.
Voor latentieproblemen kun je aggregeren op model en de P95 (het 95e percentiel) van latency_ttft_ms berekenen. Als je ziet dat gpt-4-turbo opeens een TTFT van 4000ms heeft, terwijl dat gisteren nog 400ms was, weet je direct dat de LLM-provider te kampen heeft met performance-degradatie, en kun je geautomatiseerd overschakelen naar een fallback-model of een andere regio.
Welke alerts zijn écht zinvol?
Te veel alerts leiden tot alert fatigue. Ontwikkelaars negeren uiteindelijk de meldingen. Beperk je LLM-alerts tot actiegerichte signalen:
- Foutenratio (HTTP 4xx/5xx): Alert als meer dan 2% van de requests in een tijdvak van 5 minuten faalt. Dit duidt meestal op uitputting van rate-limits of een storing bij de provider.
- TTFT Degradatie: Stel een alert in als de P90 van de Time To First Token stijgt boven een kritieke drempel (bijv. > 2 seconden). Dit raakt de gebruikerservaring direct en vereist mogelijk het inschakelen van een sneller model.
- Kosten- of Tokenlimieten (Budget Alerts): Stel waarschuwingen in zodra het opgetelde bedrag van
cost_estimated_usdbinnen één uur een bepaalde drempel overschrijdt. Dit is je beste verdediging tegen een DDoS-aanval of een runaway-script dat oneindig calls blijft maken. - Frequentie van 'finish_reason': 'length': Als modellen vaak afkappen vanwege een bereikte token-limiet (in plaats van een natuurlijke 'stop'), betekent dit dat de output voor de gebruiker onvolledig is. Een stijging hierin vereist direct onderzoek naar de gebruikte
max_tokensparameter.
Conclusie
Observability voor LLM's vereist meer dan standaard API-monitoring. Door de grillige aard van generatieve AI moet je prestaties (vooral tokens en eerste-byte latentie), kosten en orkestratie-stappen (traces) minutieus vastleggen. Zorg er tegelijkertijd voor dat je privacy respecteert door teksten te hashen of strikt te maskeren. Met een doordacht logschema bouw je niet alleen een fundament voor betrouwbare AI-applicaties, maar houd je ook de operationele kosten en de veiligheid van je gebruikers strak in de hand.