Werkplaats / De werkplaats
In jouw eigen tempo
← Werken met LLM’s
MODULE 01 · LES 04

Reserveer ruimte voor antwoord en geschiedenis

Meet prompttokens, laat hele berichtparen vallen en reken met expliciet fictieve prijzen zonder tussentijdse afronding.

60 min3 checkpoints
DIT GA JE ONTDEKKEN
  • Je reserveert het antwoord vóór je context selecteert.
  • Je onderscheidt tokenbudget, cachetokens en een eenvoudig kostenmodel.

Een gesprek past pas wanneer de invoer én het gereserveerde antwoord in het contextvenster passen. De invoer omvat ook instructies, voorbeelden, rolmarkers en eventuele toolbeschrijvingen. Alleen de zichtbare vraag tellen onderschat dus de benodigde ruimte.

Gebruik in een echte toepassing de tokenizer en chattemplate van het gekozen model. De oefeningen krijgen al gemeten token-IDs of aantallen. Daardoor kun je het selectiebeleid precies narekenen zonder een gok zoals “vier tekens per token”.

1. Reserveer antwoordruimte vooraf

Noem het aantal prompttokens P, de maximale antwoordlengte R en de contextcapaciteit C. De voorwaarde is:

P+R≤C

Bij drie prompttokens, drie gereserveerde antwoordtokens en capaciteit acht blijven twee tokens vrij. Het uiteindelijke antwoord kan korter zijn door een eindtoken. Dat verandert niets aan de ruimte die je vóór generatie nodig hebt gereserveerd.

r = context_budget([11,42,7],3,8)
print(r['prompt'],r['reserved'])  # 3 3
print(r['free'])  # 2

Maak context_budget met een niet-lege lijst echte gehele token-IDs tussen nul en 2³¹−1. Reserveer minstens één token en gebruik een venster van hoogstens 8192. Dit maximum is onze oefengrens en beschrijft niet de capaciteit van alle taalmodellen.

Als de prompt en reservering samen te groot zijn, geef je ValueError. Kap geen vraag of systeeminstructie stil af om de som te laten passen. Zo krijgt de aanroeper een duidelijke keuze: invoer verkorten of een andere passende configuratie gebruiken.

01
CHECKPOINTTel de prompt en reserveer het maximale antwoord

2. Verwijder complete oude berichtparen

Ons geschiedenisbeleid bewaart systeemcontext, huidige vraag en antwoordreservering altijd. Eerdere user/assistant-paren mogen vanaf de oudste worden verwijderd. Daardoor blijft één aaneengesloten recent deel over met bij elkaar horende vragen en antwoorden.

Neem vaste aantallen 2+3+4=9 en drie eerdere paren met samen 5, 6 en 4 tokens. Alles samen gebruikt 24 tokens. Bij capaciteit twintig valt het oudste paar weg: er blijven negentien gebruikte tokens en één vrij.

turns = [(3,2),(4,2),(2,2)]
r = choose_history(2,turns,3,4,20)
print(r['keep'])  # [1, 2]
print(r['used_with_reply'],r['free'])
# 19 1
s = choose_history(2,turns,3,4,14)
print(s['keep'])  # [2]
print(s['used_with_reply'],s['free'])
# 13 1

Maak choose_history voor maximaal honderd paren, elk als lijst of tuple met twee positieve gehele aantallen. Trek het oudste paar van het totaal af zolang dat totaal niet past. Rapporteer de behouden oorspronkelijke indices, het aantal verwijderde paren, totaal inclusief antwoord en vrije ruimte; wijzig de invoer niet.

Als zelfs de vaste basis niet past, geef je een fout. Het beleid is bovendien geen algemeen optimaal geheugen: een oude afspraak kan belangrijker zijn dan een recent praatje. We maken hier één eenvoudige, controleerbare keuze.

De aantallen moeten bij exact geserialiseerde tokenblokken horen, inclusief markers. Losse gewone tekstfragmenten apart tokeniseren en optellen kan door grenssamenvoegingen afwijken van de volledige tokenisatie. Controleer dat onderscheid wanneer je deze helper aan een echt model koppelt.

EERST RUIMTE VOOR HET ANTWOORDWelke complete gespreksturns passen nog?

Vooraf gegeven tokenaantallen, inclusief markers. Verwijder de oudste hele paren; systeemcontext en huidige vraag blijven staan.

VastSysteem · 8 tokens
Paar 1 · verwijderdVraag 14 + antwoord 12
Paar 2 · verwijderdVraag 25 + antwoord 20
Paar 3 · behoudenVraag 10 + antwoord 16
VastHuidige vraag · 32
Vooraf gereserveerdNieuw antwoord · 32
Complete paren behouden1Met antwoordreservering98 / 128Vrij30
02
CHECKPOINTBewaar de laatste complete berichtparen

3. Tel cache-invoer één keer

Een eenvoudig kostenmodel verdeelt invoer in ongecachete tokens U en gecachete tokens K. De totale invoer I bevat K al, dus U=I−K. Uitvoer O krijgt een eigen tarief; alle tarieven zijn hier fictieve bedragen per miljoen tokens in dezelfde munteenheid.

U=I−KT=Upin+Kpcache+Opoutkosten=T106

Bij I=1000, K=400 en O=200, met tarieven 2, .5 en 6, is de gewogen som 600×2+400×.5+200×6=2600. Delen door een miljoen geeft .0026. Cached tokens nogmaals bij I optellen zou dubbel tellen.

prices = {'input':'2','cached':'0.5',
          'output':'6'}
cost = token_cost(1000,200,400,prices)
print(cost)  # 0.0026
print(token_cost(1,0,0,prices))
# 0.000002

Maak token_cost met Decimal uit de prijsstrings. Valideer gehele aantallen tot een miljard, cached hoogstens input, en exact drie niet-negatieve gewone prijsstrings met maximaal zes decimalen en waarde hoogstens 10000. Geef een Decimal terug en rond niet tussentijds af.

De tweede uitkomst toont waarom vroeg afronden kleine aanvragen gratis kan laten lijken. Dit model bevat geen cache-schrijfkosten, belastingen of minimumafname; de site gebruikt zelf geen betaalde model-API. Het model-lab toont wel echte lokale invoer- en uitvoertelling.

03
CHECKPOINTReken met gemeten aantallen en expliciete tarieven

Wat neem je mee?

  • Antwoordreservering hoort vooraf in het contextbudget.
  • Een expliciet beleid verwijdert complete oude paren.
  • Cache-invoer wordt eenmaal geteld; Decimal bewaart de gekozen prijsprecisie.

Hierna beoordeel je of de inhoudelijke antwoorden van een LLM-toepassing ook kloppen.

Verder lezen & bronnen

Inhoud gecontroleerd op 2026-10-28.
DE VOLGENDE STAPMeet ook wat een antwoord niet kan onderbouwen
JOUW EXPERIMENT

Probeer het zelf

Python
main.py

Python start zodra jij code uitvoert.

UITVOER

Je uitvoer verschijnt hier.
Alles rekent in je eigen browser.

Jouw checkpoints0 / 3
01
Tel de prompt en reserveer het maximale antwoord

Schrijf context_budget(prompt_ids,reserve,window) met prompt, reserved en free. window en reserve zijn exacte ints met 1≤reserve≤window≤8192. prompt_ids is een niet-lege lijst exacte ints van 0 tot 2³¹−1. promptlengte+reserve≤window; anders ValueError.

Een hint

De gereserveerde tokens zijn nog niet gegenereerd. free=window−len(prompt_ids)−reserve.

02
Bewaar de laatste complete berichtparen

Schrijf choose_history(system_tokens,turn_tokens,current_tokens,reply_tokens,context) met keep (indices), dropped, used_with_reply en free. Context is een exacte int 1–8192. Vaste aantallen zijn exacte positieve ints ≤context. turn_tokens bevat maximaal 100 paren van twee zulke ints. Verwijder oudste paren tot het past; anders ValueError.

Een hint

Bereken eerst het vaste minimum, daarna het totaal. Trek complete paren af vanaf index nul; verander de oorspronkelijke lijst niet.

03
Reken met gemeten aantallen en expliciete tarieven

Schrijf token_cost(input_tokens,output_tokens,cached_tokens,prices) met Decimal. Aantallen zijn exacte ints 0–10⁹, cached≤input. prices heeft exact input/output/cached, gewone niet-negatieve decimale strings (1–5 cijfers vóór de punt, maximaal 6 erna), waarde ≤10000. Anders ValueError. Rond niet af.

Een hint

Vermenigvuldig aantallen met Decimal(tariefstring). Gebruik geen float tussenstap en bereken uncached=input−cached.

Vastgelopen? Bekijk de voorbeeldoplossing
def context_budget(prompt_ids, reserve, window):
    if type(window) is not int or not 1 <= window <= 8192 or type(reserve) is not int or not 1 <= reserve <= window:
        raise ValueError('Ongeldig contextvenster of antwoordbudget')
    if not isinstance(prompt_ids, list) or not prompt_ids or any(type(v) is not int or not 0 <= v < 2**31 for v in prompt_ids):
        raise ValueError('Geef echte niet-negatieve token-IDs')
    if len(prompt_ids) + reserve > window:
        raise ValueError('Prompt plus gereserveerd antwoord past niet')
    return {'prompt': len(prompt_ids), 'reserved': reserve, 'free': window - len(prompt_ids) - reserve}

def choose_history(system_tokens, turn_tokens, current_tokens, reply_tokens, context):
    if type(context) is not int or not 1 <= context <= 8192 or any(type(v) is not int or not 1 <= v <= context for v in [system_tokens, current_tokens, reply_tokens]):
        raise ValueError('Ongeldige vaste tokenaantallen')
    if not isinstance(turn_tokens, list) or len(turn_tokens) > 100:
        raise ValueError('Maximaal honderd eerdere berichtparen')
    for pair in turn_tokens:
        if not isinstance(pair, (list, tuple)) or len(pair) != 2 or any(type(n) is not int or not 1 <= n <= context for n in pair):
            raise ValueError('Ieder berichtpaar heeft twee positieve tokenaantallen')
    base = system_tokens + current_tokens + reply_tokens
    if base > context:
        raise ValueError('De onmisbare context past niet; vraag om een kortere opdracht')
    used = base + sum(sum(pair) for pair in turn_tokens)
    start = 0
    while used > context:
        used -= sum(turn_tokens[start])
        start += 1
    return {'keep': list(range(start, len(turn_tokens))), 'dropped': start,
            'used_with_reply': used, 'free': context - used}

import re
from decimal import Decimal

def token_cost(input_tokens, output_tokens, cached_tokens, prices):
    if any(type(v) is not int or not 0 <= v <= 10**9 for v in [input_tokens, output_tokens, cached_tokens]) or cached_tokens > input_tokens:
        raise ValueError('Ongeldige tokenaantallen')
    if not isinstance(prices, dict) or set(prices) != {'input', 'output', 'cached'}:
        raise ValueError('Drie prijzen per miljoen tokens vereist')
    rates = {}
    for key, text in prices.items():
        if not isinstance(text, str) or re.fullmatch(r'\d{1,5}(\.\d{1,6})?', text) is None:
            raise ValueError('Prijzen zijn gewone decimale strings met maximaal zes decimalen')
        rate = Decimal(text)
        if rate > 10000:
            raise ValueError('Prijs buiten oefenbereik')
        rates[key] = rate
    return ((input_tokens - cached_tokens) * rates['input'] + cached_tokens * rates['cached'] + output_tokens * rates['output']) / Decimal(10**6)

Voer de code uit en verklaar voor jezelf waarom elke stap werkt.