De context window, tokens en de rekening, gemeten
Een gemeten gesprek van 40 beurten kost 22× zijn eigen lengte aan input tokens. Caching verlaagt dat 68%; één timestamp verkeerd kost 20%.
Op deze pagina
Hier is een supportgesprek van veertig beurten, per beurt gefactureerd. Niets eraan is ongewoon: een developer die iets vraagt over een API, een assistant die antwoordt in een alinea of twee. De hele uitwisseling is 5.090 tokens tekst — ongeveer acht pagina’s.
| beurt | prompt tokens | nieuwe tekst | output | kosten van deze beurt | lopend totaal |
|---|---|---|---|---|---|
| 1 | 213 | 18 | 183 | $0.002622 | $0.002622 |
| 5 | 892 | 14 | 123 | $0.003260 | $0.014354 |
| 10 | 1,656 | 19 | 114 | $0.004680 | $0.035530 |
| 20 | 2,868 | 18 | 103 | $0.006972 | $0.094426 |
| 30 | 3,941 | 20 | 99 | $0.009070 | $0.174170 |
| 40 | 4,947 | 17 | 142 | $0.011598 | $0.274386 |
Lees de tweede en derde kolom samen. Bij beurt 40 typte de gebruiker zeventien tokens en werd er afgerekend voor 4.947. De vraag was niet moeilijker dan de eerste; hij was korter. Wat veranderde, is dat het verzoek het hele gesprek opnieuw meedroeg, voor de veertigste keer.
Totaal aantal gefactureerde input tokens over die veertig calls: 112.617. Het gesprek is 5.090 tokens lang. Je betaalde ervoor tweeëntwintig keer opnieuw.
Dit hoofdstuk gaat over waarom dat gebeurt, hoe het op de factuur van elke provider heet, en aan welke van de vijf dingen waarvoor je betaalt je iets kunt doen.
Details tonen
Wat dit hoofdstuk nodig heeft uit deel II.
- Hoofdstuk 7 bouwde de tokenizer. Een token is hier ook de eenheid — dezelfde eenheid, nu met een prijs.
- Hoofdstuk 9 leidde self-attention en de -kosten ervan af, in het vak over asymptotische notatie. Die kosten zijn waarom er überhaupt een limiet bestaat, en we linken er hier naar in plaats van het opnieuw uit te leggen.
- Hoofdstuk 13 mat prefill tegenover decode en berekende wat een KV cache inneemt. Die twee fasen zijn wat de input- en outputkolommen hierboven werkelijk inkopen.
Al het andere is TypeScript, want dit is boekhouding voor een externe call en geen wiskunde over een model.
De window is geen geheugen
Link naar de sectie: De window is geen geheugenDe duurste misvatting in deze business is dat een model een gesprek onthoudt.
Dat doet het niet, en het mechanisme uit hoofdstuk 13 zegt precies waarom. De toestand van een transformer tijdens generatie is de KV cache: de keys en values die voor elke token in de sequentie zijn berekend. Die cache leeft zolang één request duurt. Wanneer het request eindigt, is het proces dat hem vasthield vrij om iemand anders te bedienen, en is de cache weg. Er is aan de andere kant geen opslag per gebruiker, en geen sessie.
Dus het volgende request moet alles meebrengen wat het model geacht wordt te weten, en het model bouwt die toestand opnieuw op door een forward pass over de hele prompt te draaien voordat het één nieuwe token uitstuurt. Hoofdstuk 15 noemde de prompt "de volledige toestand". Dit is de fysieke reden: de prompt is de volledige toestand omdat niets anders de call overleeft.
De context window is de maximale lengte van die prompt plus het antwoord. Het is een plafond op hoeveel toestand je kunt herbouwen, geen container die tussen requests iets vasthoudt. Hem "het geheugen van het model" noemen draait de causaliteit om — je vult geen geheugen, je betaalt om er een opnieuw op te bouwen.
Daar komt die tweeëntwintig vandaan. Beurt draagt alle vorige beurten mee, dus de totale input over een gesprek van beurten is de som van een groeiende reeks, en die is kwadratisch:
waarbij de system prompt is en de geschiedenis bij beurt . De gemeten cumulatieve input fitten op over de veertig beurten geeft , wat 113.645 tokens voorspelt bij beurt 40 tegenover 112.617 gemeten. De kwadratische term domineert en de lineaire term is wat de gebruiker daadwerkelijk typte.
De consequentie is de zin om uit dit hoofdstuk mee te nemen: je rekening groeit met het kwadraat van het gesprek, niet met de laatste vraag. Dezelfde veertig vragen zonder enige geschiedenis kosten $0.066036. De geschiedenis behouden kostte $0.274386. Geschiedenis vermenigvuldigde de rekening met 4,2, en blijft dat doen, want de vermenigvuldiger is de gesprekslengte.
Waarom er überhaupt een limiet is
Link naar de sectie: Waarom er überhaupt een limiet isDe window is eindig om twee redenen die dezelfde kant op trekken. De eerste is die van hoofdstuk 9: attention vergelijkt elke token met elke andere token, dus het werk van die laag groeit met het kwadraat van de sequentielengte. De tweede is geheugen: de KV cache groeit lineair met de sequentielengte, en hoofdstuk 13 deed die rekensom — bij lange sequenties is hij groter dan de weights.
Beide limieten zijn aangevallen en geen van beide is verdwenen. FlashAttention1 reorganiseert de berekening zodat er veel minder naar high-bandwidth memory wordt gelezen en geschreven, waardoor lange sequenties praktisch worden zonder de asymptotische kosten te veranderen. Position Interpolation2 en YaRN3 vergroten de bruikbare window van een getraind model door de positional encodings uit hoofdstuk 9 te herschalen in plaats van opnieuw te trainen. Samen verklaren ze waarom windows in vijf jaar van 2K naar 1M gingen.
Wat ze niet deden, is lange contexts gratis maken. Ze maakten het plafond hoger en de helling zachter. De helling is er nog steeds, en dat is wat de prijstiers later in dit hoofdstuk meten.
Vijf buckets, geen twee
Link naar de sectie: Vijf buckets, geen tweeBijna elke kostencalculator op internet modelleert een API-call als input tokens keer een inputprijs plus output tokens keer een outputprijs. Dat klopte in 2023. Nu is het fout op een manier die rekeningen in beide richtingen met een factor twee of meer laat afwijken.
Er zijn vijf factureerbare token-categorieën:
| bucket | wat het is | typische prijs, relatief tot input |
|---|---|---|
| uncached input | prompt tokens die het model vers moest verwerken | 1× |
| cache read | prompt tokens geleverd uit een opgeslagen prefix | 0,1× |
| cache write | prompt tokens die bij deze call in de cache worden opgeslagen | 1,25× tot 2× |
| output | tokens die het model genereerde en naar je stuurde | 5× tot 6× |
| reasoning | tokens die het model genereerde en niet naar je stuurde | output-tarief |
Drie van die vijf bestonden twee jaar geleden niet als aparte regels, en de twee cacheregels zijn degene die mensen verkeerd begrijpen, omdat een cache write meer kost dan gewone input, niet minder. Je betaalt een premie om iets op te slaan zodat je korting kunt betalen om het terug te lezen, en of dat goed uitpakt hangt volledig af van hoe vaak je het leest.
De reasoning-bucket is die van hoofdstuk 12, nu met een prijs erop, en bevat een detail dat het waard is om expliciet te zeggen: Google's documentatie zegt dat pricing "is based on the full thought tokens the model needs to generate, despite only the summary being output from the API."4 Je wordt gefactureerd voor tokens die nooit naar je worden verzonden. Het is de enige bucket waarvan je de inhoud niet kunt tellen, inspecteren of verifiëren.
Dezelfde call, drie dialecten
Link naar de sectie: Dezelfde call, drie dialectenNu het deel dat dit een normalisatieprobleem maakt in plaats van een vermenigvuldigingsprobleem. Elke provider rapporteert deze buckets onder andere namen, en — dit is de valkuil — twee van hen gebruiken hetzelfde woord voor twee verschillende hoeveelheden.
Neem één call: 4.837 tokens gelezen uit cache, 110 vers, 142 zichtbare output tokens, 300 reasoning tokens.
// OpenAI-compatible
{ "usage": { "prompt_tokens": 4947,
"prompt_tokens_details": { "cached_tokens": 4837 },
"completion_tokens": 442,
"completion_tokens_details": { "reasoning_tokens": 300 } } }
// Anthropic
{ "usage": { "input_tokens": 110,
"cache_read_input_tokens": 4837,
"cache_creation_input_tokens": 0,
"output_tokens": 442 } }
// Gemini
{ "usageMetadata": { "promptTokenCount": 4947,
"cachedContentTokenCount": 4837,
"candidatesTokenCount": 142,
"thoughtsTokenCount": 300 } }Kijk naar prompt_tokens: 4947 en input_tokens: 110. Beide velden zijn het input token-aantal voor dezelfde prompt. Dat van OpenAI bevat de gecachte tokens; dat van Anthropic sluit ze uit — de documentatie noemt de identiteit expliciet, total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens.5 Anthropic's input_tokens betekent "de tokens na je laatste cache-breakpoint".
En kijk naar de output. OpenAI en Anthropic rapporteren allebei 442, waar de 300 reasoning tokens al in zitten. Gemini rapporteert 142 en zet de 300 in een eigen veld. Hoofdstuk 12 markeerde dit als een incompatibiliteit tussen twee manieren om hetzelfde werk te tellen; hier is wat het kost.
Een normalizer is dertig regels en is niet optioneel:
export interface Usage {
promptTokens?: number; // input, NOT cached
cachedInputTokens?: number; // read from cache
cacheWriteTokens?: number; // written to cache on this call
completionTokens?: number; // output
reasoningTokens?: number; // billed apart from output (Gemini only)
}
const num = (v: unknown) => (typeof v === "number" && isFinite(v) ? v : 0);
export const fromOpenAI = (raw: any): Usage => {
const u = raw.usage ?? {}, d = u.prompt_tokens_details ?? {};
const cached = num(d.cached_tokens), write = num(d.cache_write_tokens);
return {
promptTokens: Math.max(0, num(u.prompt_tokens) - cached - write),
cachedInputTokens: cached,
cacheWriteTokens: write,
completionTokens: num(u.completion_tokens), // reasoning already inside
reasoningTokens: 0,
};
};
export const fromAnthropic = (raw: any): Usage => {
const u = raw.usage ?? {};
return {
promptTokens: num(u.input_tokens), // already excludes cache
cachedInputTokens: num(u.cache_read_input_tokens),
cacheWriteTokens: num(u.cache_creation_input_tokens),
completionTokens: num(u.output_tokens),
reasoningTokens: 0,
};
};
export const fromGemini = (raw: any): Usage => {
const m = raw.usageMetadata ?? {}, cached = num(m.cachedContentTokenCount);
return {
promptTokens: Math.max(0, num(m.promptTokenCount) - cached),
cachedInputTokens: cached,
cacheWriteTokens: 0,
completionTokens: num(m.candidatesTokenCount), // EXCLUDES thinking
reasoningTokens: num(m.thoughtsTokenCount), // billed at output rate
};
};Haal de drie payloads hierboven door de drie readers en alle drie leveren dezelfde Usage op, en dus hetzelfde getal: $0.006491. Die overeenstemming is het hele punt van die laag schrijven.
Doe je het fout, dan kost dat op dezelfde call dit:
| fout | gefactureerd | afwijking |
|---|---|---|
cached_tokens behandelen als extra bovenop prompt_tokens | $0.016165 | 2,49× — je rekent de prompt twee keer af |
| cache reads als gratis behandelen in plaats van 0,1× | $0.005524 | 0,85× — je slikt 15% |
candidatesTokenCount lezen en thoughtsTokenCount negeren | $0.002891 | 55% van de call verdwijnt |
De derde is de gevaarlijke, omdat hij stil faalt in de richting van goed nieuws. Je dashboard laat zien dat een reasoning-model minder dan de helft kost van wat het werkelijk kost, en nergens gaat er een fout af.
De kosten berekenen
Link naar de sectie: De kosten berekenenMet de buckets genormaliseerd is de kostenfunctie kort. Het enige niet voor de hand liggende deel is de tier lookup, die de volgende sectie uitlegt:
export interface Tier { maxPromptTokens: number | null; price: number }
export interface Pricing {
input: Tier[]; output: Tier[];
cachedInput?: Tier[]; cacheWrite?: Tier[]; reasoning?: Tier[];
}
const tierPrice = (tiers: Tier[] | undefined, contextSize: number, fallback?: Tier[]) => {
const table = tiers ?? fallback;
if (!table?.length) return 0;
const sorted = [...table].sort(
(a, b) => (a.maxPromptTokens ?? Infinity) - (b.maxPromptTokens ?? Infinity));
for (const t of sorted)
if (t.maxPromptTokens === null || contextSize <= t.maxPromptTokens) return t.price;
return sorted[sorted.length - 1].price;
};
export function computeCost(pricing: Pricing, usage: Usage): number {
const fresh = usage.promptTokens ?? 0;
const read = usage.cachedInputTokens ?? 0;
const write = usage.cacheWriteTokens ?? 0;
const out = usage.completionTokens ?? 0;
const think = usage.reasoningTokens ?? 0;
const contextSize = fresh + read + write; // the tier depends on the WHOLE prompt
return fresh * tierPrice(pricing.input, contextSize)
+ read * tierPrice(pricing.cachedInput, contextSize, pricing.input)
+ write * tierPrice(pricing.cacheWrite, contextSize, pricing.input)
+ out * tierPrice(pricing.output, contextSize)
+ think * tierPrice(pricing.reasoning, contextSize, pricing.output);
}Twee ontwerpkeuzes daar zijn het verdedigen waard. De fallbacks — cacheprijzen die terugvallen op input, reasoning op output — coderen wat een ontbrekende tabel betekent: reasoning tokens op Gemini worden gefactureerd tegen het output-tarief, dus een ontbrekende reasoning-prijs is niet nul, maar de outputprijs. En contextSize telt alle drie input-buckets op in plaats van alleen de verse, omdat de tier wordt gekozen op basis van hoe lang de prompt is, niet op basis van hoeveel ervan tegen volle prijs werd afgerekend.
Prompt caching, en wat schrijven kost
Link naar de sectie: Prompt caching, en wat schrijven kostEen prompt cache slaat de berekende toestand van het model op voor een prefix van je prompt, zodat een later request met dezelfde prefix het opnieuw berekenen overslaat. Uit het woord "prefix" volgen vier eigenschappen, en alle vier verrassen mensen.
Het is een prefix, geen set
Link naar de sectie: Het is een prefix, geen setDe cache matcht vanaf het begin van de gerenderde prompt naar voren, en stopt bij de eerste byte die verschilt. Er is geen gedeeltelijke credit voor content die later in een andere volgorde verschijnt. OpenAI zegt het plat: "cache reuse requires the entire rendered prefix to match."6
Er is een minimale lengte
Link naar de sectie: Er is een minimale lengteDaaronder wordt niets gecachet en komt er geen fout terug. Bij OpenAI is het minimum 1.024 tokens voor GPT-5.6 en later en 2.048 voor oudere modellen. Bij Anthropic varieert het van 512 tot 4.096 afhankelijk van het model — 1.024 voor Claude Sonnet 4.5, 4.096 voor Claude Haiku 4.5. Als beide cachevelden nul terugkomen, is dat meestal de reden.
Schrijven kost meer dan lezen, en meer dan niet cachen
Link naar de sectie: Schrijven kost meer dan lezen, en meer dan niet cachenBij OpenAI en Anthropic is een cache write 1,25× het uncached input-tarief voor de kortlevende cache, en Anthropic's cache van één uur is 2×. Een read is 0,1×. Google rekent niets voor schrijven maar verhuurt de opslag: $4.50 per miljoen tokens per uur op Gemini 2.5 Pro.
Hij verloopt, en hij leeft op één machine
Link naar de sectie: Hij verloopt, en hij leeft op één machineAnthropic's standaardentry leeft vijf minuten, gratis ververst bij elke hit. Die van OpenAI is minstens dertig minuten na de laatste write of reuse. En OpenAI merkt op dat gecachte toestanden op afzonderlijke machines leven, dus een request hit alleen als het wordt gerouteerd naar de machine die de entry vasthoudt — en dat is waar prompt_cache_key invloed op heeft, zonder garantie.
Het break-evenpunt is klein genoeg om te onthouden, en OpenAI's documentatie doet de rekensom: een prefix één keer schrijven en één keer hergebruiken kost 1,35× de gewone inputkosten, tegenover 2× om hem twee keer uncached te verwerken; over tien requests kosten één write en negen reads 2,15× tegenover 10×. Eén reuse betaalt de write terug. Anthropic komt op dezelfde plek uit: één read voor de cache van vijf minuten, twee voor de cache van één uur.
Nu opnieuw het gesprek van veertig beurten, met caching aan en een stabiele prefix:
| uncached input | cache reads | cache writes | totaal | |
|---|---|---|---|---|
| geen cache | 112,617 | — | — | $0.274386 |
| caching | 2,887 | 104,783 | 4,947 | $0.088250 |
Achtenzestig procent goedkoper, en drie getallen in die tabel verdienen aandacht.
De cache grijpt pas in bij beurt 6. De prompt haalt tot dan geen 1.024 tokens, dus de eerste vijf beurten worden precies als voorheen gefactureerd — en de zesde wordt duurder gefactureerd, met de 1,25× write-premie, omdat dit de beurt is die de cache vult. De eerste read komt bij beurt 7. De 2.887 uncached tokens in de tabel zijn de rekensom: vijf beurten waard, niet zes. Caching is een korting op lange prompts, en een kort gesprek krijgt er niets van.
De write-premie is $0.002474, oftewel 2,8% van de gecachte rekening. Elke beurt schrijft zijn nieuwe staart, veertig keer, en de hele write-premie is een afrondingsfout tegenover wat de reads bespaarden. De write charge is het waard om precies te begrijpen zodat je stopt met je er zorgen over maken.
Slechts 2.887 tokens werden tegen de volle inputprijs gefactureerd van de 112.617. Dat is de vorm van een werkende cache: bijna alles is een read.
De volgorde van de prompt bepaalt of dit überhaupt gebeurt
Link naar de sectie: De volgorde van de prompt bepaalt of dit überhaupt gebeurtHier is de failure die echt geld kost, en het is een bug van één regel.
Zet iets dat bij elke call verandert vooraan in de prompt — een timestamp, een request id, de naam van de gebruiker, een "vandaag is"-regel, een vers opgehaald document — en de prefix verschilt vanaf byte één. Niets matcht. Elke call is een miss. En omdat elke call een nieuwe prefix presenteert, schrijft elke call ook.
Hetzelfde gesprek, dezelfde veertig beurten, caching ingeschakeld, met een timestamp per call bovenaan de system prompt:
| totaal | versus | |
|---|---|---|
| helemaal geen caching | $0.274386 | — |
| caching, stabiele prefix | $0.088250 | −67,8% |
| caching, volatiele prefix | $0.329251 | +20,0% |
Prompt caching inschakelen maakte het gesprek twintig procent duurder dan het niet inschakelen. Je betaalde de 1,25× write-premie over 109.730 tokens en las nul terug. Er is geen fout, geen waarschuwing, en de feature staat aan.
Dus de regel, en dit is heel prompt caching in één regel: stabiele content vooraan, variabele content achteraan. System instructions, tool definitions en referentiemateriaal eerst; timestamps, gebruikersidentiteit en de huidige vraag als laatste. Anthropic maakt de hiërarchie expliciet — de cache volgt tools → system → messages, en een wijziging op elk niveau invalideert dat niveau en alles erna, dus het bewerken van één toolbeschrijving invalideert de hele cache.5
Twee consequenties waar mensen over struikelen. Veranderen welke tools enabled zijn verandert de tool definitions, dus een feature flag die voor sommige gebruikers een tool toevoegt splitst je cache in tweeën. En bij Anthropic wijzigt het aan- of uitzetten van web search of citations de system prompt, wat de system- en message-caches invalideert zonder dat je één regel eigen tekst aanraakt.
De geschiedenis afkappen is niet de oplossing
Link naar de sectie: De geschiedenis afkappen is niet de oplossingDe voor de hand liggende reactie op een kwadratische rekening is stoppen met de hele geschiedenis sturen: bewaar de laatste twaalf berichten en laat de rest vallen. Het verlaagt de rekening, en het is meestal de verkeerde zet, en de meting zegt waarom.
| strategie | totaal | versus volledige geschiedenis + cache |
|---|---|---|
| volledige geschiedenis, geen cache | $0.274386 | +211% |
| volledige geschiedenis, caching | $0.088250 | — |
| laatste 12 berichten, geen cache | $0.118712 | +35% |
| laatste 12 berichten, caching aan | $0.122546 | +39% |
Afkappen naar een window van twaalf berichten is 57% goedkoper dan alles uncached sturen — de vergelijking die iedereen maakt, en waarom de techniek populair is. Maar het is 39% duurder dan alles sturen met een werkende cache, en caching aanzetten naast truncation maakt het iets slechter in plaats van beter.
Het mechanisme is opnieuw de prefix. Een sliding window laat elke beurt het oudste bericht vallen, dus de prompt begint niet meer waar hij de vorige keer begon en elke beurt presenteert een nieuwe prefix. OpenAI's guidance zegt precies dit: "summarisation, compaction, or context truncation can change the prefix and reset cache reuse."6 Bij beurt 40 is de windowed prompt 813 tokens, onder het minimum van 1.024 tokens, dus hij kan helemaal niet gecachet worden.
En het geld is de goedkope helft van de kosten. Wat je liet vallen is de instructie die de gebruiker bij beurt 2 gaf en die het model bij beurt 40 nodig had. Truncation ruilt een rekening die je kunt zien voor een failure die je niet kunt zien, en het goed doen — compaction, gestructureerde notities buiten de window, geschiedenis op verzoek ophalen — is het onderwerp van hoofdstuk 24.
Een tier passeren herprijst het hele request
Link naar de sectie: Een tier passeren herprijst het hele requestLange contexts zijn niet alleen duurder omdat ze langer zijn. Na een drempel zijn ze per token duurder, en de drempel geldt met terugwerkende kracht voor de hele prompt.
OpenAI's modelpagina voor gpt-5.6-terra zegt het in één zin: "Prompts with >272K input tokens are priced at 2x input and 1.5x output for the full request."7 Niet voor het overschot. Voor het geheel.
prompt 271,999 + 500 output -> $0.5500
prompt 272,000 + 500 output -> $0.5500
prompt 272,001 + 500 output -> $1.0970Eén token, vijfenvijftig cent. Als je service prompts bouwt uit opgehaalde documenten waarvan je de grootte niet beheerst, heb je een klif in je kostenmodel op een grens die niemand in je team heeft opgeschreven.
Google's pricing werkt op dezelfde manier met een drempel van 200.000 tokens: Gemini 2.5 Pro is $1.25 per miljoen input tokens voor prompts tot 200K en $2.50 daarboven, waarbij output van $10.00 naar $15.00 gaat.8 Anthropic ging de andere kant op — per 6 september 2026 stelt de documentatie dat Claude 4.6 en later de volledige window van één miljoen tokens tegen standaardpricing bevatten, dus "a 900k-token request is billed at the same per-token rate as a 9k-token request."9 Eerdere modellen hadden de surcharge nog.
Daarom is een prijs geen getal. Een prijs is een tabel met tiers keyed by prompt length, waarvoor Tier[] in de kostenfunctie bestaat, en daarom selecteert computeCost de tier met de hele prompt in plaats van elke bucket afzonderlijk.
Prefill, decode, en waarom output zes keer input kost
Link naar de sectie: Prefill, decode, en waarom output zes keer input kostDe vijf buckets mappen op de twee fasen van hoofdstuk 13, en zodra je de mapping ziet, lijken de prijsverhoudingen niet meer willekeurig.
Input tokens zijn prefill. De hele prompt gaat in één pass door het model, parallel verwerkt — grote matrixvermenigvuldigingen, compute-bound. De kosten per token zijn laag, en dit is de fase die time to first token bepaalt: een prompt van 4.947 tokens heeft 4.947 tokens prefill te doen voordat het eerste woord verschijnt.
Output tokens zijn decode. Ze worden één voor één geproduceerd, elk een volledige forward pass die de hele KV cache leest, terwijl de GPU vooral op geheugen wacht in plaats van rekent. Dit is de fase die tokens per second bepaalt, hij kan niet binnen één response worden geparalleliseerd, en daarom kost output ongeveer zes keer input op het hier geprijsde model: $12.00 tegenover $2.00 per miljoen tokens.
Drie consequenties volgen direct. Een cache read vervangt prefill-werk, dus hij koopt latency en geld tegelijk — dezelfde korting verschijnt als een lagere rekening en een kortere wachttijd op de eerste token. Reasoning tokens zijn decode die je nooit ziet, en daarom streamt een reasoning-model enkele seconden niets en antwoordt het daarna snel: hoofdstuk 12 waarschuwde voor de interfaceconsequentie, en dit is de factuurconsequentie. En een stream afbreken stopt de generatie niet — hoofdstuk 14 bouwde cancellation en liet de prijs over aan dit hoofdstuk, en de prijs is de volledige output count, omdat de tokens worden geproduceerd en gefactureerd of er nu iemand luistert of niet. Hetzelfde geldt voor het antwoord dat niemand bewaart: een antwoord bij beurt 40 vijf keer regenereren kost $0.057990 voor het ene dat op het scherm blijft staan.
Tokens tellen voordat je ze verstuurt
Link naar de sectie: Tokens tellen voordat je ze verstuurtDe tokenizer van hoofdstuk 7 was Python en bleef daar. Budgettering gebeurt in de server die het request bouwt, dus moet het hier gebeuren, en er zijn precies drie nauwkeurigheidsniveaus beschikbaar.
Niveau één: lokaal tellen. js-tiktoken levert dezelfde BPE merge tables als de Python tiktoken, dus een byte-voor-byte identieke count voor OpenAI-encodings, zonder network call:
import { getEncoding } from "js-tiktoken";
const enc = getEncoding("o200k_base");
const PER_MESSAGE = 4; // role and delimiters added by the chat template
const PER_REPLY = 3; // priming for the assistant turn
export function promptTokens(messages: { role: string; content: string }[]) {
return messages.reduce(
(sum, m) => sum + enc.encode(m.content).length + PER_MESSAGE, PER_REPLY);
}De twee constanten doen ertoe en daar gaan lokale counts afwijken. Je tekst is niet wat wordt getokenized — de chat template uit hoofdstuk 11 wikkelt eerst elk bericht in role markers, en dat zijn tokens waarvoor je betaalt. Vier per bericht en drie voor de reply priming is de conventionele benadering voor OpenAI-chatmodellen; over de eenentachtig berichten van het gesprek hierboven tellen ze op tot 324 tokens, 6,4% van de lengte. De counts hier zijn gecontroleerd tegen de Python tiktoken uit hoofdstuk 7 op alle eenentachtig strings en zijn identiek.
Niveau twee: vraag het de provider. Anthropic biedt /v1/messages/count_tokens en Google biedt count_tokens, beide accepteren dezelfde request shape als een echte call en retourneren gratis een input token count. Gebruik ze wanneer je niet lokaal kunt tellen — en je kunt niet lokaal tellen voor Anthropic, waarvan de tokenizer niet gepubliceerd is. Anthropic's documentatie is zorgvuldig over wat ze je geeft: de count "is an estimate", en "may include tokens added automatically by Anthropic for system optimizations", waarvoor "you are not billed".10
Niveau drie: lees usage in de response. Dat is de waarheid, en die arriveert nadat het geld is uitgegeven. Precies daarom bestaan de eerste twee niveaus — om te beslissen of je het request verstuurt, niet om ervoor te factureren.
De dingen waarvoor je betaalt die niemand je laat zien
Link naar de sectie: De dingen waarvoor je betaalt die niemand je laat zienVier line items die niet als line items verschijnen.
De system prompt, betaald bij elke call. Die hierboven is 192 tokens met zijn template-overhead. Over veertig calls is dat 7.680 tokens — 5,6% van de volledige rekening van dit gesprek, voor acht regels die één keer zijn geschreven. Hij is ook de best mogelijke cachekandidaat, omdat hij zowel stabiel als eerste is.
Tool definitions. De naam, beschrijving en het JSON-schema van elke tool gaan bij elk request mee, en providers voegen daar scaffolding bovenop toe. Anthropic publiceert het getal: tools überhaupt inschakelen voegt een verborgen system prompt van 496 tokens toe op Claude Sonnet 4.5 met tool_choice ingesteld op auto, of 588 met any of een named tool.9 Dat is vóór je eigen schema’s. Hoofdstuk 18 bouwt de catalogus; hoofdstuk 24 meet wat die opeet.
Elke generatie, inclusief degene die je weggooit. Vijf regeneraties kosten vijf keer. De chat toont er één.
Gedachten die je niet te zien krijgt. Billing is gebaseerd op de volledige thought tokens, hoewel alleen een summary wordt geretourneerd, en geen enkele boekhouding van jou kan dat getal auditen.
200K tokens hebben is ze niet gebruiken
Link naar de sectie: 200K tokens hebben is ze niet gebruikenEén waarschuwing om mee af te sluiten, omdat het de natuurlijke volgende gedachte is en het antwoord niet het voor de hand liggende is.
Een window van een miljoen tokens betekent niet een miljoen bruikbare tokens. Retrieval-accuracy verslechtert met positie: Liu et al. vonden dat modellen informatie betrouwbaar vinden aan het begin en het einde van een lange input, en veel minder betrouwbaar in het midden.11 Een grotere window koopt de mogelijkheid om meer te sturen, niet de zekerheid dat het wordt gelezen.
Dat fenomeen wordt één keer in deze cursus gemeten — de retrieval rate op negen posities in dezelfde prompt van 853 tokens — en hoort thuis in hoofdstuk 24, waar het verandert wat een agent doet. Het wordt hier aangehaald omdat het verandert wat je zou moeten kopen: de goedkoopste token is degene die je niet hebt verstuurd.
Waar dit heen gaat
Link naar de sectie: Waar dit heen gaatJe kunt nu voorspellen wat een call zal kosten voordat je hem doet, achteraf lezen wat hij heeft gekost, en het verschil tussen die twee zien. Dat dekt alles over het request behalve het deel dat je nog niet hebt aangeraakt: de knobs.
Hoofdstuk 17 is sampling — temperature, top-p, top-k, de penalties, en de determinism die je niet hebt. Het begint met het ontmantelen van de meest wijdverspreide fout in het veld: dat temperature een creativiteitsknop is. Dat is het niet: temperature deelt de logits uit hoofdstuk 4 vóór de softmax, en hem verhogen maakt het model niet fantasierijker, het verhoogt de waarschijnlijkheid van tokens die het model zelf als slechter scoorde. Vanaf daar: waarom greedy decoding meetbaar slechtere tekst produceert dan sampling, waarom top-k en top-p falen op tegenovergestelde vormen van distributies, en het experiment dat het hoofdstuk afsluit: twintig identieke forward passes op temperature 0 komen bit-voor-bit identiek terug wanneer het model alleen draait, en dezelfde prompt in een batch zetten naast requests van iemand anders verplaatst 97% van zijn logits.
Ze matchen niet allemaal. De reden begint met het floating-point-vak uit hoofdstuk 2.
Bronnen en methode
Link naar de sectie: Bronnen en methodeAlle prijzen, thresholds en multipliers in dit hoofdstuk zijn gelezen van de eigen pagina’s van de providers op 6 september 2026 en worden met die datum vermeld omdat ze zullen veranderen. De methode doet er meer toe dan de getallen: de buckets, de prefix-regel en de tier-rekensom zijn twee jaar stabiel geweest terwijl elk getal erin bewoog.
Stanford CS336 lecture 2, Resource accounting, is de dichtstbijzijnde academische behandeling van dit materiaal en de juiste volgende tekst om te lezen: hij doet aan de trainingskant dezelfde rekensom die dit hoofdstuk aan de inference-kant doet. De token counts hier zijn geproduceerd met js-tiktoken 1.0.21 met de o200k_base- en cl100k_base-encodings, over een gesprek van veertig beurten en 5.090 tokens; de template-overhead per message is de conventionele vier-plus-driebenadering en wordt vermeld overal waar hij is meegerekend. De cache-, tier- en truncation-cijfers zijn de gedocumenteerde pricing rules toegepast op die gemeten token counts, geen observaties van live API-responses — er is geen betaalde call gedaan om dit hoofdstuk te maken, wat ook de eerlijke reden is dat de latencyclaims kwalitatief zijn en de kostclaims niet.
Referenties
Link naar de sectie: Referenties-
Dao, T., Fu, D. Y., Ermon, S., Rudra, A. en Ré, C. FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness. arXiv:2205.14135 (2022). Waarom het plafond verschoof zonder dat de asymptotische kosten veranderden. ↩
-
Chen, S., Wong, S., Chen, L. en Tian, Y. Extending Context Window of Large Language Models via Positional Interpolation. arXiv:2306.15595 (2023). ↩
-
Peng, B., Quesnelle, J., Fan, H. en Shippole, E. YaRN: Efficient Context Window Extension of Large Language Models. arXiv:2309.00071 (2023). ↩
-
Google, Thinking,
ai.google.dev/gemini-api/docs/thinking, en Token counting,ai.google.dev/gemini-api/docs/tokens, beide geraadpleegd op 2026-09-06. "Pricing is based on the full thought tokens the model needs to generate, despite only the summary being output from the API." Het usage-object rapporteerttotal_input_tokens,total_output_tokens,total_thought_tokens,total_cached_tokens,total_tool_use_tokensentotal_tokens— zes buckets, met thoughts en tool use buiten de output count. De eerdere veldnaam voor dezelfde hoeveelheid, nog steeds geretourneerd door de generateContent-surface, isthoughtsTokenCount, gedocumenteerd op een derde pagina,ai.google.dev/gemini-api/docs/generate-content/thinking. ↩ -
Anthropic, Prompt caching,
docs.anthropic.com/en/docs/build-with-claude/prompt-caching, geraadpleegd op 2026-09-06. Bron van detools→system→messagesinvalidatiehiërarchie en de tabel ervan; de minimale cachebare lengtes per model; de identiteittotal_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens; en de standaardlevensduur van vijf minuten die bij elke hit gratis wordt ververst. ↩ ↩2 -
OpenAI, Prompt caching,
platform.openai.com/docs/guides/prompt-caching, geraadpleegd op 2026-09-06. Bron van: de regel voor de volledige gerenderde prefix; de minimale cachebare prefix (1.024 zichtbare input tokens op GPT-5.6 en later, 2.048 eerder); de 1,25× write- en 0,1× read-multipliers, en de afwezigheid van een write charge op GPT-5.5 en eerder; de levensduur van 30 minuten; de limieten van vier writes per request en vijftig breakpoints; de machine-affinity note enprompt_cache_key; de uitgewerkte break-evenvoorbeelden van 1,35×, 2,15× en 10×; en de uitspraak dat summarisation, compaction of truncation cache reuse reset. ↩ ↩2 -
OpenAI, Pricing (
platform.openai.com/docs/pricing) en de modelpagina voorgpt-5.6-terra, beide geraadpleegd op 2026-09-06.gpt-5.6-terra, standard service tier, per miljoen tokens: input $2.00, cached input $0.20, cache writes $2.50, output $12.00; long context input $4.00, cached $0.40, writes $5.00, output $18.00; "prompts with >272K input tokens are priced at 2x input and 1.5x output for the full request"; context window 1.050.000 tokens met een maximum van 922.000 input tokens. Dezelfde tabel vermeldtgpt-6-astraop $10.00/$1.00/$12.50/$50.00 engpt-5.6-lunaop $0.20/$0.02/$0.25/$1.20. Elke uitgewerkte kost in dit hoofdstuk gebruikt degpt-5.6-terrastandard short-context rates. ↩ -
Google, Gemini Developer API pricing,
ai.google.dev/gemini-api/docs/pricing, geraadpleegd op 2026-09-06. Gemini 2.5 Pro, per miljoen tokens: input $1.25 voor prompts tot 200K en $2.50 daarboven; output $10.00 en $15.00, in beide gevallen gelabeld "including thinking tokens"; context caching $0.125 en $0.25, plus opslagkosten van $4.50 per miljoen tokens per uur. Gemini 3.1 Pro Preview gebruikt dezelfde 200K-threshold op $2.00/$4.00 input en $12.00/$18.00 output. ↩ -
Anthropic, Pricing,
docs.anthropic.com/en/docs/about-claude/pricing, geraadpleegd op 2026-09-06. Per miljoen tokens, base input / 5-minute cache write / 1-hour cache write / cache read / output: Claude Sonnet 4.5 $3 / $3.75 / $6 / $0.30 / $15; Claude Haiku 4.5 $1 / $1.25 / $2 / $0.10 / $5; Claude Opus 5 $5 / $6.25 / $10 / $0.50 / $25. Multipliers: 1,25× voor de five-minute write, 2× voor de one-hour write, 0,1× voor een read. Ook de bron van de long-context-uitspraak ("Claude 4.6 and later models... include the full 1M token context window at standard pricing"), de tool-use system prompt token counts (496 tokens op Claude Sonnet 4.5 mettool_choicevanautoofnone, 588 metanyof een named tool), en de noot dat Claude 4.7 en later een nieuwere tokenizer gebruiken die "approximately 30 % more tokens for the same text" produceert. ↩ ↩2 ↩3 -
Anthropic, Token counting,
docs.anthropic.com/en/docs/build-with-claude/token-counting, geraadpleegd op 2026-09-06. Het/v1/messages/count_tokens-endpoint neemt dezelfde inputs als een message en retourneert een input token count; de documentatie stelt dat de count een estimate is, dat hij tokens kan bevatten die Anthropic toevoegt voor system optimisations, en dat die niet worden gefactureerd. ↩ -
Liu, N. F., Lin, K., Hewitt, J., Paranjape, A., Bevilacqua, M., Petroni, F. en Liang, P. Lost in the Middle: How Language Models Use Long Contexts. arXiv:2307.03172 (2023). Hier geciteerd, gemeten in hoofdstuk 24. ↩