# Tokenverbruik normaliseren over providers - api.llmnet.nl

Deel:[𝕏](https://twitter.com/intent/tweet?url=https%3A//api.llmnet.nl/token-usage-normalisatie-providers&text=Tokenverbruik%20normaliseren%20over%20providers%20-%20api.llmnet.nl)[LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A//api.llmnet.nl/token-usage-normalisatie-providers)[Reddit](https://www.reddit.com/submit?url=https%3A//api.llmnet.nl/token-usage-normalisatie-providers&title=Tokenverbruik%20normaliseren%20over%20providers%20-%20api.llmnet.nl)[Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A//api.llmnet.nl/token-usage-normalisatie-providers)[Kopieer link](#)

# Tokenverbruik normaliseren over providers

Door Ivo Donker — samengesteld met AI-ondersteuning (Claude & Gemini) · Laatst bijgewerkt: 6 augustus 2026

Organisaties die meerdere Large Language Models (LLM's) inzetten via verschillende API-aanbieders stuiten al snel op een harde realiteit: het aantal gerapporteerde tokens is geen universele meeteenheid. Een token bij aanbieder A staat niet gelijk aan een token bij aanbieder B, noch qua informatie-inhoud, noch qua technische afhandeling of kostenstructuur. Om een betrouwbare meetlaag te bouwen die inzicht geeft in efficiëntie, budgetten en gebruikspatronen, is een doordachte normalisatie-architectuur noodzakelijk.

In dit artikel behandelen we de technische en conceptuele uitdagingen bij het normaliseren van tokenverbruik over diverse AI-providers. We bespreken de werking van tokenizers, het scheiden van afwijkende API-responservelden, de specifieke behandeling van redeneer- en cache-tokens, en het ontwerpen van een toekomstbestendig datamodel.

## Waarom een token geen universele eenheid is

Het idee dat een token een vaste hoeveelheid tekst of informatie vertegenwoordigt, is een misvatting. Een token is simpelweg het resultaat van een specifiek algoritme (de tokenizer) dat tekst opknipt in numerieke bouwstenen voor een specifiek neuraal netwerk. Omdat elke aanbieder zijn eigen vocabulaire en opknipregels hanteert, verschilt de informatiedichtheid per token aanzienlijk.

De werking van deze algoritmes wordt uitgebreid besproken in het overzicht van [tokenisatie uitgelegd](https://leren.llmnet.nl/tokenisatie-uitgelegd). Voor applicatie-architecten betekent dit dat twee verschillende modellen voor exact dezelfde invoertekst een heel ander aantal invoertokens kunnen registreren.

### Het systematische nadeel van de Nederlandse taal

Dit fenomeen heeft een directe impact op meertalige toepassingen, en in het bijzonder op de Nederlandse taal. De meeste commerciële tokenizers zijn primair getraind op engelstalige datasets en broncode. Daardoor bevat de vocabulairetabel van de tokenizer voornamelijk volledige Engelse woorden of veelvoorkomende Engelse woorddelen.

Wanneer Nederlandse tekst door een dergelijke tokenizer wordt gehaald, treedt er fragmentatie op. Veelvoorkomende Nederlandse woorden, samengestelde zelfstandige naamwoorden en specifieke vervoegingen worden opgeknipt in talloze losse lettergrepen of zelfs afzonderlijke tekens. Een Nederlandse alinea kan daardoor tot 40% tot 70% meer tokens vereisen dan exact dezelfde inhoud in het Engels. Wanneer je applicaties bouwt die wisselen tussen modellen van verschillende leveranciers, leidt een wijziging van modelversie direct tot een verschuiving in het gemeten tokenvolume, zelfs als de onderliggende tekststroom identiek blijft.

## Versnippering in API-responservelden

Naast de intrinsieke verschillen in tokenisatie, hanteren API-aanbieders uiteenlopende gegevensstructuren in hun JSON-antwoorden. Waar het basale onderscheid vroeger enkel bestond uit invoertokens (prompt) en uitvoertokens (completion), is het spectrum aan velden inmiddels aanzienlijk complexer geworden.

In de praktijk kom je onder meer de volgende categorieën velden tegen in API-responses:

- Standaard invoer (input / prompt tokens): De tokens die verwerkt zijn om de prompt te interpreteren.

- Standaard uitvoer (output / completion tokens): De gegenereerde teksttokens die zichtbaar zijn in het antwoord.

- Cache-read invoer: Invoertokens die zijn afgetapt uit een bestaande context-cache en waarvoor een verlaagd tarief geldt.

- Cache-write invoer: Invoertokens die gebruikt zijn om een nieuwe context-cache op te bouwen.

- Niet-getoonde redeneertokens: Interne denkstappen bij redeneermodellen (reasoning of thought tokens) die wel gefactureerd worden, maar niet als zichtbare tekst naar de client terugkeren.

Het zomaar samenvoegen van deze getallen tot één 'totaal aantal tokens' maakt elke vorm van kosten- en prestatieanalyse onmogelijk.

## Redeneertokens en cache-tokens categoriseren

Het correct afhandelen van gespecialiseerde token-typen vraagt om duidelijke logica in de verzamel- en analysefase. Twee categorieën vereisen hierbij bijzondere aandacht: redeneertokens en cache-tokens.

### Redeneertokens scheiden van de zichtbare output

Modellen met uitgebreide redeneercapaciteiten genereren interne denkstappen voordat ze hun uiteindelijke antwoord formuleren. Deze 'reasoning tokens' worden door de API gefactureerd tegen het tarief van uitvoertokens. Ze verschijnen echter niet in het uiteindelijke tekstveld van de API-response.

Het is cruciaal om deze denkstappen in je datamodel streng te scheiden van de reguliere uitvoertokens. Als je redeneertokens op één hoop gooit met de gegenereerde tekst, vervuilt dit je prestatiestatistieken. Je kunt dan bijvoorbeeld niet meer nauwkeurig berekenen hoeveel output-tokens je applicatie per seconde produceert voor de gebruiker, of wat de gemiddelde lengte is van de daadwerkelijk getoonde antwoorden. Houd redeneertokens daarom altijd als een afzonderlijk metrisch veld bij.

### Cache-tokens: schrijven versus lezen

Context caching stelt ontwikkelaars in staat om grote hoeveelheden statische informatie (zoals documentatie of systeeminstructies) in het geheugen van de aanbieder te bewaren. De financiële en technische afhandeling van cache-tokens kent echter twee kanten:

- Cache-creatie (write): Het eenmalig verwerken en wegschrijven van de context naar de cache. Dit kost vaak meer verwerkingskracht en kan soms tegen een apart tarief worden gefactureerd.

- Cache-gebruik (read): Het hergebruiken van de gecachete context bij vervolgvragen. Dit verlaagt de verwerkingstijd en wordt gefactureerd tegen een sterk gereduceerd tarief.

Sommige providers trekken de gecachete tokens af van het totale aantal invoertokens, terwijl andere aanbieders een totaalgetal geven waarin de cached tokens als subveld zijn opgenomen. In je normalisatielaag moet je de API-payloads zo ontleden dat zowel de 'bruto invoer' als de 'cache-treffers' eenduidig worden opgeslagen.

## Interne rekeneenheden en ruwe data scheiden

Een fundamenteel ontwerpprincipe bij het bouwen van een LLM-meetlaag is het scheiden van gemeten feiten en berekende aannames. Je mag een geschat of omgerekend getal nooit verwarren met een hard gemeten waarde.

Ontwerpregel: Bewaar de ruwe API-responsinformatie van de aanbieder altijd in de originele vorm. Sla daarnaast de genormaliseerde of afgeleide waarden op in afzonderlijke kolomstructuren.

Als een provider meldt dat een verzoek 1.200 `prompt_tokens` heeft gekost, sla je dat exacte getal op in het veld voor de ruwe invoer. Om vergelijkingen tussen verschillende modellen mogelijk te maken, kun je daarnaast een interne genormaliseerde eenheid berekenen, bijvoorbeeld op basis van een standaard karakterlengte of een referentie-tokenizer. Mocht de berekeningswijze van je interne rekeneenheid in de toekomst wijzigen, dan kun je op basis van de ongewijzigde ruwe data altijd historische herberekeningen uitvoeren.

## Kosten losmaken van token-aantallen

Het direct opslaan van een berekend geldbedrag op basis van vaste variabelen in de applicatiecode is een veelvoorkomende valkuil. Prijzen per miljoen tokens wijzigen regelmatig, en aanbieders introduceren continu nieuwe kortingsstructuren of piek- en daltarieven. Wie meer wil lezen over de uiteenlopende opbouw van tarieven kan het artikel over [prijsmodellen per token](https://hub.llmnet.nl/prijsmodellen-per-token-uitgelegd) raadplegen.

Om te voorkomen dat prijswijzigingen je historische financiële rapportages herschrijven, dien je kostenberekeningen los te koppelen van het tokenvolume. Dit bereik je door een ontkoppelde prijstabel (prijsmatrix) te onderhouden met een geldigheidstermijn.

Model ID | 
Token Categorie | 
Prijs per 1M (EUR) | 
Geldig vanaf | 
Geldig tot | 

model-alpha-v1 | 
input_standard | 
Geen vaste prijs | 
2026-01-01 | 
2026-06-30 | 

model-alpha-v1 | 
input_standard | 
Nieuw tarief | 
2026-07-01 | 
NULL | 

model-alpha-v1 | 
input_cached | 
Gereduceerd tarief | 
2026-01-01 | 
NULL | 

model-alpha-v1 | 
output_reasoning | 
Uitvoer tarief | 
2026-01-01 | 
NULL | 

Bij het verwerken van een verzoek koppel je het verzoek aan de op dat moment geldige prijsversie (`price_version_id`). Op deze manier blijft de historische kostberekening van een verzoek uit mei 2026 exact gelijk, ook als het tarief van dat specifieke model in juli 2026 wordt aangepast.

## Omgaan met ontbrekende of onvolledige verbruiksdata

In een ideale wereld geeft elke API-call een net geformatteerd JSON-object terug met een exact overzicht van het verbruik. In de praktijk treedt er regelmatig dataverlies op, met name bij het gebruik van streaming antwoorden (Server-Sent Events).

Wanneer een gebruiker de browser sluit tijdens het streamen, of wanneer een netwerkonderbreking de verbinding verbreekt voordat het afsluitende verbruiksblok is ontvangen, ontbreken de officiële metingen van de provider. Toch heeft de provider op dat moment wel kosten gemaakt voor de verwerkte invoer en de deels gegenereerde uitvoer.

### Schatten met een eigen tokenizer

Om gaten in je datamodel te voorkomen, moet je applicatie in zulke gevallen terugvallen op een lokale schattingsmodule. Hiervoor gebruik je een lokale tokenizer-bibliotheek om de verzonden prompt en de tot dan toe ontvangen tekstelementen te tellen.

Het is van essentieel belang dat de uitkomst van een dergelijke berekening expliciet wordt gemarkeerd. Gebruik een boolean vlag zoals `is_estimated = true` of een statusveld `usage_source = 'local_fallback'`. Daarmee voorkom je dat geschatte data per ongeluk wordt aangezien voor harde factuurgegevens bij latere controles.

## Het datamodel voor een werkbare meetlaag

Om alle ruwe gegevens, berekende kosten en functionele context op een gestructureerde manier op te slaan, is een robuust databaseschema vereist. De onderstaande SQL-tabelstructuur illustreert hoe een genormaliseerde meettabel ingericht kan worden.

CREATE TABLE llm_usage_logs (
 request_id UUID PRIMARY KEY,
 created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
 provider VARCHAR(50) NOT NULL,
 model_version VARCHAR(100) NOT NULL,
 
 -- Ruwe metingen van provider
 raw_input_tokens INT DEFAULT 0,
 raw_output_tokens INT DEFAULT 0,
 raw_cached_input_tokens INT DEFAULT 0,
 raw_reasoning_tokens INT DEFAULT 0,
 
 -- Status van de meting
 is_estimated BOOLEAN DEFAULT FALSE,
 usage_source VARCHAR(20) DEFAULT 'provider_api',
 
 -- Financiële koppeling
 price_version_id INT REFERENCES price_matrix(id),
 calculated_cost_eur NUMERIC(10, 6),
 
 -- Functionele attributie
 calling_function VARCHAR(100) NOT NULL,
 team_id VARCHAR(50),
 user_hash VARCHAR(64)
);

Deze tabel vormt de fundamentele meetlaag onder je financiële administratie. Zie voor het doorberekenen van deze gegevens naar organisatorische eenheden het artikel over [kosten per gebruiker toerekenen](https://api.llmnet.nl/kosten-per-gebruiker-toerekenen), dat bouwt op de hier beschreven logica.

## Attributie en privacy: toerekenen zonder inhoud

Voor auditing en interne verrekening is het noodzakelijk om te weten welke gebruiker, welk team of welke specifieke softwarefunctie verantwoordelijk is voor welk deel van het tokenverbruik. Tegelijkertijd stellen privacywetgeving (zoals de AVG) en interne veiligheidsrichtlijnen strenge eisen aan het opslaan van persoonsgegevens en de inhoud van de prompts.

De meetlaag moet daarom strikt gescheiden blijven van de inhoudelijke datastroom:

- Sla nooit promptinhoud op in de meettabel: Bewaar geen ingevoerde teksten, gegenereerde antwoorden of ingesloten documenten in de logging van je tokenverbruik.

- Pseudonymiseer gebruiker-IDs: Sla geen directe e-mailadressen of namen op. Gebruik cryptografische hashes (zoals SHA-256 met een interne salt) om verzoeken aan een anonieme identiteit te koppelen.

- Sla functionele metadata op: Leg vast welke microservice, welk API-eindpunt of welke specifieke achtergrondtaak de aanroep heeft geïnitieerd (`calling_function`).

Door deze benadering te hanteren kun je gedetailleerd rapporteren over verbruikspatronen en kosten per afdeling, zonder dat het logsysteem verandert in een privacygevoelige databron. Deze aanpak sluit naadloos aan op de richtlijnen voor [observability en logging](https://api.llmnet.nl/observability-en-logging) binnen AI-architecturen.

## Vroegtijdige kwaliteits- en kostencontroles

Wanneer je alle tokenstromen van verschillende aanbieders hebt genormaliseerd in een centraal datamodel, kun je geautomatiseerde controles inrichten. Dit helpt om fouten in de software, afwijkend gedrag of onverwachte kostenstijgingen in een vroeg stadium op te sporen.

### 1. Detectie van onverklaarde sprongen per model

Door het gemiddelde tokenverbruik per verzoek per functie (`calling_function`) continu te monitoren, kun je direct alarm slaan bij afwijkingen. Als een specifieke functie na een software-release plotseling dubbel zoveel invoertokens verbruikt, wijst dit vaak op een fout in de prompt-opbouw of het onbedoeld meesturen van overtollige geschiedenis.

### 2. Bepalen van de cache-efficiëntie

Een plotselinge daling in het percentage `raw_cached_input_tokens` ten opzichte van het totale invoervolume is een belangrijk signaal. Dit duidt er meestal op dat de context-cache niet meer optimaal werkt. Oorzaken kunnen zijn dat de systeeminstructies dynamische elementen bevatten (zoals een veranderende tijdstempel bovenaan de prompt), waardoor de unieke hash van de cache breekt en de aanbieder elke aanroep als een volledig nieuwe prompt verwerkt.

### 3. Verificatie van de providerfactuur

Aan het einde van de maand kun je de geaggregeerde totalen uit je interne datamodel leggen naast de verzamelfactuur en de verbruiksrapporten van de API-aanbieder. Kleine afwijkingen zijn normaal door afrondingsverschillen of incidentele netwerkfouten. Verschillen van meer dan een fractie van een procent duiden echter op structurele problemen, zoals niet-geregistreerde streaming-onderbrekingen, onjuist verwerkte kortingstarieven of ontbrekende foutafhandeling in je eigen applicatiecode.

Voor een breder overzicht van het opzetten van alarmering en drempelwaarden kun je terecht bij de handleiding over [kosten monitoren](https://api.llmnet.nl/kosten-monitoren) op ons platform. Zodra de basisgegevens betrouwbaar worden vastgelegd, wordt het tevens mogelijk om vergelijkingen te maken met de prestatiestatistieken uit de [benchmark voor kosten per taak](https://benchmark.llmnet.nl/kosten-per-taak).

## Lees ook

- [Kosten monitoren van LLM-infrastructuur](https://api.llmnet.nl/kosten-monitoren)

- [Kosten per gebruiker toerekenen in multi-tenant systemen](https://api.llmnet.nl/kosten-per-gebruiker-toerekenen)

- [Observability en logging voor AI-applicaties](https://api.llmnet.nl/observability-en-logging)

- [Prijsmodellen per token uitgelegd](https://hub.llmnet.nl/prijsmodellen-per-token-uitgelegd)

- [Tokenisatie uitgelegd: van tekst naar vector](https://leren.llmnet.nl/tokenisatie-uitgelegd)

- [Benchmark kosten per taak](https://benchmark.llmnet.nl/kosten-per-taak)

llmnet.nl - LLM-aggregatie en API-integratie
