LLM-kosten 10× omlaag zonder kwaliteitsverlies
Prompt caching, modelroutering, batching en contextdiscipline. Vier hefbomen die betrouwbaar een orde van grootte van een AI-rekening afhalen — inclusief waarom caching stilletjes faalt.
De eerste maand van een AI-functie in productie is meestal een aangename verrassing. De zesde meestal niet, want tokenverbruik schaalt mee met gebruik en niemand heeft iets geoptimaliseerd toen het nog goedkoop was.
Het goede nieuws: de meeste productiesystemen zijn op vier specifieke, oplosbare manieren enorm inefficiënt. Die repareren haalt doorgaans een orde van grootte van de rekening zonder de outputkwaliteit aan te raken. Hier zijn ze, op volgorde van hefboom.
1. Prompt caching — de grootste hefboom, en het vaakst kapot
Elk verzoek in een typisch systeem stuurt dezelfde enorme prefix opnieuw mee: systeemprompt, tooldefinities, few-shot-voorbeelden, opgehaalde beleidsdocumenten, gespreksgeschiedenis. Je betaalt er elke keer de volle prijs voor.
Met prompt caching houdt de provider die prefix warm. Cache-reads kosten ruwweg een tiende van de standaard inputprijs. Cache-writes kosten een bescheiden opslag — rond 1,25× voor de kortlevende cache en rond 2× voor de lange — wat betekent dat de korte cache al bij twee verzoeken break-even draait en de lange bij drie. Voor alles met een stabiele prefix en herhaald verkeer is dat een enorme besparing.
En meestal werkt het stilletjes niet. Dit is het mechanisme, want dat begrijpen is het hele werk:
Caching is een prefix-match. Elke byte die ergens in de prefix verandert, maakt alles daarna ongeldig.
De prompt wordt in vaste volgorde opgebouwd — tools, dan system, dan messages — en de cachesleutel wordt afgeleid van de exacte bytes tot aan elk breekpunt. Eén ander teken op positie 400 vernietigt de cache voor alles vanaf positie 400.
De dingen die dit stilletjes doen:
| Patroon | Waarom het breekt |
|---|---|
datetime.now() in de systeemprompt |
De prefix verschilt bij elk verzoek |
| Een request-ID of UUID vroeg in de content | Idem — elk verzoek is uniek |
json.dumps(d) zonder gesorteerde sleutels, of itereren over een set |
Niet-deterministische serialisatie |
| Gebruikers- of sessie-ID in de systeemprompt | Prefix per gebruiker; niets wordt gedeeld |
Voorwaardelijke systeemsecties (if flag: system += ...) |
Elke combinatie van vlaggen is een aparte prefix |
| Een toollijst die per gebruiker verschilt | Tools staan vooraan — niets daarna cachet |
De architectuurregels die daaruit volgen:
- Bevries de systeemprompt. Geen datums, geen namen, geen modi. Injecteer dynamische context verderop in de berichtenlijst, waar hij alleen ongeldig maakt wat erna komt.
- Serialiseer tools deterministisch en wijzig de set niet halverwege een gesprek. Tooldefinities staan op positie nul; ze veranderen kost je de hele cache.
- Wissel niet van model halverwege een gesprek. Caches zijn modelspecifiek. Heeft een deeltaak een goedkoper model nodig, draai die dan als aparte aanroep in plaats van het model van de hoofdlus te wisselen.
- Zet vluchtige content achteraan. Stabiele content eerst, sessiegebonden daarna, per-beurt aan het eind.
Controleer het. Het usage-object in de respons rapporteert cache_read_input_tokens. Is dat nul over herhaalde verzoeken die een prefix zouden moeten delen, dan heb je een stille cache-breker — vergelijk de opgebouwde bytes van twee opeenvolgende verzoeken en je vindt hem binnen enkele minuten.
Nog iets dat mensen verrast: het minimum aan cachebare prefix verschilt per model, en niet netjes oplopend per generatie. Afhankelijk van welk model je draait ligt het ergens tussen ~512 en ~4096 tokens. Een prompt van 3.000 tokens cachet op sommige modellen en stilletjes niet op andere — geen foutmelding, alleen een nul in het usage-veld. Controleer het minimum voor het model dat je daadwerkelijk draait.
2. Routeer per taak, niet per systeem
De op één na grootste hefboom, en degene die de meeste teams overslaan omdat het aanvoelt als een stap terug.
Dat is het niet. Eén systeem bevat stappen met totaal verschillende moeilijkheidsgraad:
- Ticketintentie indelen in twaalf categorieën
- Een ordernummer uit vrije tekst halen
- Bepalen of een bericht boos is
- Het klantgerichte antwoord schrijven
- Een oordeel vellen over een dubbelzinnig retourverzoek
De eerste drie zijn smal, hoogvolume en uitstekend meetbaar. De laatste twee vragen echt oordeelsvermogen. Alles op je beste model draaien betekent topprijzen betalen om strings te classificeren.
Routeer per stap. Kleine, snelle modellen voor classificatie, extractie, routering en opmaak. Middenklasse voor het meeste generatiewerk. Topmodellen voor alles wat klantgericht, oordeelsgevoelig of langlopend en agentisch is.
Het kostenverschil tussen de klassen is aanzienlijk — de kleinste bruikbare modellen draaien op een fractie van de tokenprijs van topmodellen — en op de smalle taken is het vaak nauwkeuriger, omdat je voor een taak met een vaste labelruimte een echte eval-set kunt bouwen en er echt op kunt tunen.
Tweede knop: redeneerdiepte. Huidige topmodellen bieden een instelling die deliberatie afweegt tegen tokens en latency. De meeste teams laten die op de standaardwaarde staan, die meestal hoog is afgesteld. Sweep hem op je eigen eval-set — op routinematig operationeel werk houdt een of twee standen lager vaak de kwaliteit vast en snijdt het flink in de kosten. Op langlopend agentisch werk verlaagt hógere diepte juist vaak de totale kosten, omdat betere planning minder beurten betekent. Ga niet uit van de richting; meet hem.
3. Batch alles wat niet interactief is
Als een resultaat niet nodig is binnen dit HTTP-verzoek, hoort het geen interactieve prijs te betalen.
De Batch API verwerkt asynchroon tegen 50% van de standaardprijs, waarbij de meeste batches binnen een uur klaar zijn en het plafond op 24 uur ligt. Hij ondersteunt de volledige featureset — tools, caching, vision, gestructureerde output.
Alles op deze lijst hoort in een batch:
- Nachtelijke classificatie, verrijking of scoring
- Bulk-contentgeneratie (productbeschrijvingen, vertalingen, samenvattingen)
- Embeddings of metadata over een corpus bijwerken
- Eval-runs
- Rapportgeneratie
- Alles dat door een cron wordt gestart in plaats van door een gebruiker
De helft van je rekening, voor werk waar niemand op wacht. Het is de makkelijkste 50% die je ooit vindt, en hij blijft meestal liggen omdat de code voor het interactieve pad is geschreven en nooit is herzien.
4. Besteed contextdiscipline
Tokens die je verstuurt zijn tokens waarvoor je betaalt, en lange context heeft een tweede prijs: modellen letten ongelijkmatig op over een groot venster, dus de prompt volproppen maakt de output vaak slechter én duurder.
Haal minder op, maar beter. Vijf goed gerangschikte passages verslaan twintig middelmatige op zowel kosten als nauwkeurigheid. Dit is de praktische opbrengst van reranking — je kunt met meer vertrouwen minder chunks sturen.
Snoei gespreksgeschiedenis. In een lange agentische run zijn tool-resultaten van twintig beurten geleden bijna nooit nog dragend. Gooi verouderde tool-output weg, of vat de oudere historie samen tot een compacte vorm. De meeste providers bieden dit nu server-side aan.
Begrens de output. max_tokens is een echte kostenknop, niet alleen een veiligheidslimiet. Zet hem op wat de taak daadwerkelijk nodig heeft. Maar zet hem hoog genoeg — afgekapte output betekent een retry, en die kost meer dan de speelruimte gekost zou hebben.
Let op de redeneertoken-verrassing. Op modellen waar redeneren standaard aanstaat, begrenst max_tokens het denken plus het zichtbare antwoord samen. Een limiet die krap om het verwachte antwoord is gezet op een niet-redenerend model, kapt op een redenerend model midden in het antwoord af. Dit overkomt mensen tijdens migraties.
Er getallen op plakken
Een representatief supportsysteem vóór optimalisatie:
- Elk verzoek stuurt een prefix van 8.000 tokens ongecachet mee
- Alles draait op het topmodel
- Nachtelijke verrijking loopt synchroon door hetzelfde pad
- Retrieval stuurt 20 chunks
Erna:
- Prefix gecachet; het stabiele deel wordt tegen ruwweg een tiende gefactureerd
- Classificatie en routering op een klein model; generatie op middenklasse; topmodel alleen voor escalatie-achtige oordelen
- Nachtelijke verrijking verplaatst naar batch, tegen halve prijs
- Reranking brengt retrieval terug naar 6 chunks
Niets daarvan is een kwaliteitsafweging. Reranking verbetert de nauwkeurigheid. Routering verbetert de smalle taken. Caching verandert helemaal niets aan de output. Het samenspel van de vier levert de orde van grootte op.
De volgorde waarin je het doet
- Meet eerst. Log tokenaantallen per aanroeppad, getagd per functie. Je kunt geen rekening optimaliseren die je niet kunt toewijzen, en de verdeling is bijna nooit wat mensen denken.
- Repareer caching. Grootste hefboom, geen kwaliteitsrisico, en meestal al half geconfigureerd en stilletjes kapot.
- Verplaats batchbaar werk naar batch. Mechanisch, halveert dat deel van de rekening.
- Routeer per taak. Vraagt om evals per stap — die je toch al wilt.
- Stem context en redeneerdiepte af. Doorlopend, incrementeel, gemeten.
Stap één is degene die mensen overslaan, en het is degene die je vertelt of de andere vier de moeite waard zijn.
Wij meten het verbruik voordat we het optimaliseren, en dragen het dashboard samen met de code over. Plan een auditgesprek.