Bij het evalueren van de prestaties van Large Language Model (LLM) API's is responstijd (latency) een van de meest kritieke bedrijfsparameters. Toch trappen veel engineeringteams en technische beslissers in de valkuil om latency uit te drukken in een enkel gemiddelde. In een traditionele webapplicatie kan een gemiddelde responstijd al een vertekend beeld geven, maar bij LLM-infrastructuur is het rekenkundig gemiddelde ronduit misleidend.
LLM-interacties vertonen geen klassieke normaalverdeling (de bekende klokcurve), maar een sterk scheve verdeling met een extreem lange staart (een zogenaamde heavy-tailed distribution). Wie beslissingen neemt op basis van gemiddeldes, negeert de frustrerende ervaring van de 5 tot 10 procent gebruikers die te maken krijgen met onaanvaardbaar trage verzoeken. In deze handleiding behandelen we waarom de latencyverdeling bij LLM's zo scheef is, hoe je percentielen (p50, p90, p95, p99) leest, hoe je metingen correct corrigeert voor uitvoerlengte en welke valkuilen er bestaan bij het aggregere en opstellen van een Service Level Objective (SLO).
Het rekenkundig gemiddelde wordt berekend door de som van alle gemeten responstijden te delen door het totale aantal metingen. Deze metriek is uitermate gevoelig voor uitschieters (outliers). Wanneer negentien verzoeken binnen 500 milliseconden worden afgehandeld, maar het twintigste verzoek duurt 30 seconden vanwege een koudestart-mechanisme of een herpoging, stijgt het gemiddelde voor alle twintig verzoeken direct naar bijna 2 seconden.
Dat gemiddelde van 2 seconden vertelt je echter twee dingen niet:
Voor een breder overzicht van het opzetten van prestatiemetingen kun je onze gids over snelheid meten bij LLM's raadplegen, maar de kernoorzaak van dit specifieke latencygedrag ligt in de architectuur van AI-cloudproviders.
De responstijd van een LLM-endpoint wordt niet alleen bepaald door de hoeveelheid rekenkracht die nodig is voor een prompt, maar door een keten van dynamische factoren bij de provider:
Om de verdeling van responstijden goed te begrijpen, maken we gebruik van percentielen. Een percentiel is een drempelwaarde die aangeeft welk percentage van de metingen op of onder die waarde valt wanneer je alle metingen van klein naar groot sorteert.
| Percentiel | Betekenis in de praktijk | Operationele focus |
|---|---|---|
| p50 (Mediaan) | 50% van de verzoeken was sneller dan deze waarde, 50% was trager. Dit is de 'typische' ervaring. | Inzicht in de algemene efficiëntie van de infrastructuur onder normale omstandigheden. |
| p90 | 90% van de verzoeken was sneller dan deze waarde; 10% ondervond meer vertraging. | Eerste indicatie van opbouwende drukte of lichte capaciteitsgebreken. |
| p95 | 95% van de verzoeken viel binnen deze tijd. 1 op de 20 verzoeken was trager. | De standaard grens voor het opstellen van gebruikersgericht kwaliteitsbeleid (SLA/SLO). |
| p99 | 99% van de verzoeken was sneller. Slechts 1% (1 op de 100) was trager. | Detecteren van zeldzame maar ernstige systeemfouten, koude starts en extreme wachtrijen. |
Stel dat we een fictieve reeks van 100 verzoeken meten. Als de p50 op 800 ms ligt, de p95 op 1.200 ms en de p99 op 14.500 ms, dan betekent dit dat de meeste gebruikers een zeer snelle ervaring hebben, maar dat 1 op de 100 gebruikers bijna 15 seconden moet wachten. Het gemiddelde van deze reeks zou rond de 1.100 ms liggen, waardoor de p99-piek van 14,5 seconden volledig onzichtbaar blijft in de stuurgetallen.
Bij het meten van LLM-latency is het maken van onderscheid tussen twee fasen in het generatieproces essentieel: de verwerking van de invoer (prefill) en het genereren van de uitvoer (decode). Deze twee fasen hebben een heel ander prestatieprofiel.
TTFT is de tijd die verstrijkt tussen het verzenden van de HTTP-request door de client en het ontvangen van het allereerste token van de LLM-respons. TTFT omvat de netwerktijd, de tijd in de wachtrij van de provider en de prefill-fase waarin het model de gehele invoerprompt in één keer verwerkt.
Een hoge TTFT wijst vrijwel altijd op lange invoerprompts, drukte in de wachtrijen van de provider of netwerkvertraging. Voor de interactieve gebruikerservaring (bijvoorbeeld een chat-interface) is TTFT de belangrijkste metriek: het bepaalt hoe snel de gebruiker ziet dat het systeem 'begint te typen'.
De totale antwoordtijd is de tijd vanaf het verzoek tot de ontvangst van het allerlaatste token (of het sluiten van de stream). De totale tijd is echter sterk afhankelijk van hoeveel tokens het model heeft gegenereerd. Een antwoord van 500 tokens duurt logischerwijs langer dan een antwoord van 20 tokens.
Daarom splitsen we de meting op in twee heldere componenten:
(Totale tijd - TTFT) / (Aantal gegenereerde tokens - 1). Alternatief wordt dit vaak uitgedrukt als generatiesnelheid in tokens per seconde (TPS).Als je twee LLM-providers of twee modelversies met elkaar wilt vergelijken, kun je de absolute totale responstijden niet zomaar naast elkaar leggen. Als Model A in 2 seconden een antwoord geeft van 50 tokens, en Model B doet er 4 seconden over maar genereert 300 tokens, dan is Model B in de generatiefase significant sneller (75 tokens/sec vs 25 tokens/sec), hoewel de absolute responstijd van Model B twee keer zo hoog is.
Zonder normalisatie verval je in een vergelijking die afhankelijk is van de toevallige lengte van het gegenereerde antwoord op dat specifieke moment. Raadpleeg ons uitgebreide stappenplan voor een eigen benchmark voor meer richtlijnen over het opzetten van gestandaardiseerde testsets.
Om latency correct te vergelijken op percentielniveau, pas je de volgende normalisatiestappen toe:
Een van de meest gemaakte wiskundige fouten in monitoring-dashboards is het middelen van percentielen. Stel dat je applicatie op vijf verschillende servers draait. Elke server berekent elk uur zijn eigen p95 latency. Veel ontwikkelaars neigen ernaar om het gemiddelde te nemen van die vijf p95-waarden om de 'totale p95' van het uur te bepalen. Dit is statistisch invalide.
Percentielen zijn niet-lineair en niet-additief. De p95 van een gecombineerde dataset kan veel hoger of lager liggen dan het gemiddelde van de individuele p95-waarden, afhankelijk van het volume en de verdeling van de metingen per server.
Stel dat Server A 1.000 verzoeken afhandelt met een p95 van 1.000 ms. Server B handelt slechts 10 verzoeken af, maar door een incident was de p95 daar 20.000 ms. Neem je het eenvoudige gemiddelde van de twee p95's, dan kom je uit op (1.000 + 20.000) / 2 = 10.500 ms. In werkelijkheid vielen 950 van de 1.010 totale verzoeken ruim onder de 1.000 ms, waardoor de werkelijke gecombineerde p95 dicht bij de 1.000 ms ligt. Het gemiddelde van de percentielen geeft hier een volstrekt verkeerd beeld.
In moderne AI-architecturen staat een LLM-call zelden op zichzelf. Denk aan een Retrieval-Augmented Generation (RAG) pipeline waarbij eerst een embedding-model wordt aangeroepen, vervolgens een vector-database wordt geraadpleegd, daarna een reranker draait en ten slotte het hoofdmodel een antwoord genereert. In een multi-agent systeem worden soms wel tientallen LLM-calls in serie of parallel uitgevoerd.
Wanneer meerdere stappen sequentieel worden uitgevoerd, stapelen de percentielen zich op een gevaarlijke manier op. De totale p99 van een keten is drastisch slechter dan de p99 van de individuele onderdelen.
Als een keten bestaat uit $n$ onafhankelijke stappen, en elke stap heeft een p99-latency van 1 seconden (wat betekent dat 1% van de calls erg traag is), dan is de kans dat een verzoek geen enkele p99-vertraging oploopt gelijk aan $0{,}99^n$.
| Aantal sequentiële stappen ($n$) | Kans dat álles snel verloopt ($0{,}99^n$) | Kans dat ten minste 1 stap de p99-staart raakt |
|---|---|---|
| 1 stap | 99,0% | 1,0% |
| 5 stappen | 95,1% | 4,9% |
| 10 stappen | 90,4% | 9,6% |
| 50 stappen (complex agentic proces) | 60,5% | 39,5% |
Bij een proces met 50 stappen krijgt bijna 40% van de eindgebruikers te maken met de p99-latency van ten minste één subsysteem! Dit fenomeen noemt men tail latency amplification. Om deze reden moeten de p95- en p99-eisen voor individuele bouwstenen in een RAG-keten vele malen strenger zijn dan de uiteindelijke SLO die aan de gebruiker wordt beloofd.
Een veelgemaakte fout bij benchmarks is het rapporteren van een p99 op basis van een te kleine steekproef. Als je een benchmark uitvoert met 50 verzoeken en daaruit 'de p99' berekent, is de uitkomst puur statistische ruis.
Het 99e percentiel vertegenwoordigt immers een gebeurtenis die slechts in 1 op de 100 gevallen voorkomt. Om het 99e percentiel met een acceptabele betrouwbaarheid te kunnen bepalen, heb je een absolute ondergrens aan waarnemingen nodig.
Draai je een snelle test van 30 prompts om een nieuw model uit te proberen? Kijk dan uitsluitend naar p50 en eventueel p90. Trek geen conclusies over de p99 van een provider op basis van enkele tientallen test-requests.
Waar meet je de latency? In de praktijk zit er een aanzienlijk verschil tussen wat de API-provider in zijn statusdashboard rapporteert (server-side latency) en wat de eindgebruiker van jouw applicatie daadwerkelijk ervaart (client-side latency).
De provider meet de tijd vanaf het moment dat het verzoek hun loadbalancers binnenkomt tot het moment dat het laatste token hun netwerkpoort verlaat. Wat hierin ontbreekt:
Client-side latency omvat de volledige round-trip time (RTT), inclusief eventuele vertragingen in het verwerken van de HTTP-respons door jouw eigen SDK of applicatiecode. Verder kan een lokale garbage collection pauze in Node.js of Python de gemeten latency artificieel verhogen.
De manier waarop je applicatie omgaat met fouten en netwerkstreams heeft een directe impact op de gemeten percentielen.
Wanneer een LLM-verzoek faalt met een HTTP 503 (Capacity Exceeded) of een HTTP 429 (Rate Limit), zal een robuuste client het verzoek opnieuw proberen met een korte vertraging (exponential backoff). Meer details over hoe je dit configureert vind je op de pagina over retries en backoff-strategieën.
Als je pas de latency registreert zodra het verzoek uiteindelijk slaagt, telt de wachttijd van de mislukte pogingen mee in de totale duur. Een verzoek dat twee keer faalt en pas bij de derde poging slaagt, schiet direct door naar de p99-staart. Registreer daarom zowel de latency van de poging (per HTTP-call) als de latency van de transactie (de totale tijd die de eindgebruiker wacht inclusief herpogingen).
Als je een harde client-side time-out instelt op bijvoorbeeld 10 seconden, worden alle verzoeken die langer dan 10 seconden duren afgebroken en als fout gemarkeerd. Zie voor de verwerking hiervan onze handleiding over timeouts en cancellation.
Als je deze afgebroken verzoeken vervolgens verwijdert uit je latency-statistieken, ontstaat er truncation bias: je p99 lijkt opeens kunstmatig laag (onder de 10 seconden), simpelweg omdat je de echt trage responses hebt afgesneden. Neem afgebroken verzoeken met de maximale geconfigureerde time-outwaarde op in je percentielberekeningen, of rapporteer het foutpercentage expliciet naast je percentielen.
Bij het gebruik van streaming HTTP-responses sturen veel client-SDK's of proxy's tokens pas door naar de applicatie wanneer een buffer van een bepaalde grootte (bijv. 4 KB) vol is. Dit beïnvloedt de TTFT-meting negatief. Zorg er bij latencymetingen voor dat netwerkbuffers op de client uitstaan (unbuffered stream) om de daadwerkelijke fysieke TTFT te meten.
Het overstappen van gemiddeldes naar percentielen stelt je in staat om reële Service Level Objectives (SLO's) af te spreken met het team of met de business. Een afspraak als *"Onze LLM-dienst heeft een gemiddelde responstijd van 1,5 seconde"* is waardeloos, omdat het geen garanties biedt voor individuele verzoeken.
Een professionele SLO-definitie op basis van percentielen ziet er als volgt uit:
Voorbeeld van een robuuste LLM SLO:
"In 95% van de gevallen over een rollend venster van 30 dagen moet de Time To First Token (TTFT) kleiner zijn dan 800 ms, en moet de Time Per Output Token (TPOT) lager liggen dan 40 ms/token. Verzoeken die langer duren dan 15 seconden worden als mislukt beschouwd."
Een grens stellen op de p95 betekent automatisch dat je accepteert dat 5% van de verzoeken de norm mag overschrijden. Dit is je foutbudget. Pas wanneer meer dan 5% van de verzoeken trager is dan de p95-norm (of wanneer de p99 een kritieke bovengrens van bijvoorbeeld 20 seconden overschrijdt), raakt het foutbudget uitgeput.
Op dat moment heeft het team een helder signaal om te grijpen naar maatregelen zoals:
Ter afsluiting een overzicht van de meest voorkomende valkuilen in de praktijk, en wat de juiste aanpak is:
| Foutieve aanpak | Waarom het misgaat | De correcte methode |
|---|---|---|
| Sturen op gemiddelde latency. | Verbergt de trage ervaring van de staartgebruikers en reageert extreem op uitschieters. | Stuur op p50 voor de mediaanervaring en p95/p99 voor de staart. |
| Gemiddelde nemen van p95-waarden over meerdere servers. | Statistisch invalide; vervalst het echte percentiel. | Sla ruwe data op of gebruik t-digest / HDR Histograms voor aggregatie. |
| Totale tijd vergelijken zonder te corrigeren voor tokenlengte. | Modellen die uitgebreidere antwoorden geven lijken onterecht 'trager'. | Splits in TTFT (ms) en TPOT (ms/token of TPS). |
| p99 rapporteren op basis van 30 testverzoeken. | Te kleine steekproef leidt tot willekeurige ruis. | Evalueer p99 pas bij minimaal 1.000 representatieve verzoeken. |
| Time-outs schrappen uit de latencydataset. | Leidt tot truncation bias, waardoor de p99 kunstmatig laag lijkt. | Reken geannuleerde/ge-timeoutte verzoeken mee tegen de maximale duur. |
Door percentielen consequent en op de juiste manier toe te passen in je evaluaties, benchmarks en productiemonitoring, transformeer je latency van een vage indruk naar een harde, stuurbare kwaliteitsmetriek voor je AI-infrastructuur.