- Je simuleert begrensde FIFO-batches met expliciete aankomst-, start- en eindtijden.
- Je berekent nearest-rank-percentielen, inclusieve SLO-fracties en afzonderlijke tarieven per miljoen tokens.
Een model kan een verzoek snel berekenen terwijl de gebruiker toch lang wacht. Er kunnen al andere verzoeken klaarstaan, en samen verwerken kan efficiënter zijn dan ieder verzoek apart starten. Daarom horen wachttijd, verwerkingscapaciteit en kosten bij het ontwerp van een AI-dienst.
Denk aan een bus: direct vertrekken helpt de eerste reiziger, even wachten kan meer mensen meenemen. Maar een grote bus helpt weinig als je op een lege halte onnodig blijft wachten. Bij batching zoek je zo'n afweging met expliciete aannames en metingen.
Wij gebruiken een eigen FIFO-simulator: wie het eerst aankomt, wordt het eerst meegenomen. Er is één uitvoerder en een batch eindigt voor al haar verzoeken tegelijk. De tijden en tarieven zijn oefenwaarden; het rekenmodel helpt je beleid vergelijken.
1. Scheid wachten van uitvoeren
Bekijk eerst hoe dezelfde verzoeken veranderen als je de batchgrootte of maximale verzamelwachttijd aanpast. Een volle batch vertrekt zodra de uitvoerder vrij is en genoeg verzoeken aanwezig zijn. Anders wacht zij tot de deadline van het oudste verzoek, of tot zij eerder vol raakt.
Volg ieder verzoek vanaf de aankomst tot het batchresultaat. Vergelijk een piek met rustige aankomsten en onderzoek wat de verzamelgrens werkelijk begrenst.
● Aankomst · gestreept: wachten · gevuld: verwerking. Verzoeken met hetzelfde batchnummer eindigen samen.
- Batches
- 2
- Verzoeken per seconde
- 375
- p95 latency
- 5 ms
- Binnen gekozen SLO
- 66,667%
| R / batch | Start | Einde | Wacht | Latency |
|---|---|---|---|---|
| 1 / 1 | 1 | 5 | 1 | 5 |
| 2 / 1 | 1 | 5 | 0 | 4 |
| 3 / 2 | 6 | 8 | 2 | 4 |
1 van 3 verzoeken overschrijden 4 ms; gelijk aan de grens telt als gehaald. Grootste wachttijd: 2 ms bij een verzamelgrens van 2 ms. Een bezette uitvoerder kan die wachttijd verder laten oplopen.
Eigen FIFO-oefensimulator: één uitvoerder, overhead 1 ms en 1 ms per grootste werktoken. Geen echte hardwaremeting of continuous LLM batching. Een SLO is hier een zelfgekozen grens voor de totale latency.
Noem aankomst A, start S en afronding F. Voor verzoek i is de wachtrijduur Q het stuk vóór de start; de totale latentie L loopt helemaal tot de afronding. Dezelfde batch kan daardoor verschillende latenties voor haar reizigers opleveren.
In onze simulator kost elke batch b een vaste overhead h plus c milliseconden per werktoken van het langste verzoek. De hoeveelheid werk van verzoek i heet W_i. Dit model maakt ook zichtbaar waarom zeer ongelijke verzoeklengtes ongunstig kunnen zijn: kort werk wacht mee tot het lange werk klaar is.
Neem aankomsten 0, 1 en 4 ms met respectievelijk 2, 3 en 1 werktokens. De batchlimiet is twee, de verzamelwachttijd twee ms, overhead één en tokentijd één ms. Het tweede verzoek vult de eerste batch op tijdstip één; haar duur is vier en haar einde vijf.
Het derde verzoek komt tijdens die uitvoering aan. Zijn deadline is tijdstip zes, dus de onvolledige tweede batch start daar en eindigt op acht. De simulator gebruikt ook voor deze laatste batch dezelfde wachtregel.
| Rij | A | S | F | L | |---|---:|---:|---:|---:| | 0 | 0 | 1 | 5 | 5 | | 1 | 1 | 1 | 5 | 4 | | 2 | 4 | 6 | 8 | 4 |
requests = [[0,2],[1,3],[4,1]]
run = simulate_batches(
requests,batch_limit=2,
max_wait_ms=2,overhead_ms=1,
per_token_ms=1)
print(run['starts_ms'].tolist())
print(run['finishes_ms'].tolist())
# [1.0, 1.0, 6.0]
# [5.0, 5.0, 8.0]
Een maximale verzamelwachttijd begrenst niet de wachttijd achter een bezette uitvoerder. Ook is een grotere batch niet automatisch beter: één verzoek met tien ms verzamelwachttijd moet gewoon wachten, terwijl er niemand bijkomt.
alone = simulate_batches(
[[0,2]],batch_limit=8,
max_wait_ms=10,overhead_ms=1,
per_token_ms=1)
print(alone['latencies_ms'].tolist())
# [13.0]
012. Kijk ook naar de staart
Het gemiddelde kan een groep trage verzoeken verbergen. Sorteer daarom de latenties en kies expliciet hoe je percentielen berekent. Onze rangmethode (nearest rank) gebruikt fractie q en aantal N; r is de nulgebaseerde index in de gesorteerde vector.
De gesorteerde latenties zijn [4, 4, 5]. P50 is vier, p95 is vijf; bij een gekozen servicenorm (service level objective, SLO) van vier ms halen twee van de drie verzoeken hun grens. Gelijkheid telt als gehaald, en de functie geeft een fractie terug.
summary = latency_summary(
[5,4,4],slo_ms=4)
print(summary['p50_ms'])
print(summary['p95_ms'])
print(round(summary['slo_met'],3))
# 4.0
# 5.0
# 0.667
Voor throughput telt ook het meetinterval. Met N verzoeken in T milliseconden, van eerste aankomst tot laatste afronding, is R het aantal verzoeken per seconde. Ons voorbeeld verwerkt drie verzoeken in acht ms en komt dus op 375 per seconde binnen dit model.
023. Houd rekeneenheden zichtbaar
Een tarief per miljoen tokens is geen tarief per verzoek. Noem de aantallen invoer- en uitvoertokens I en O, met tarieven a en b per miljoen. Totale kosten C volgen door beide soorten apart om te rekenen en op te tellen.
Met fictieve tarieven twee en acht kosten 1000 invoertokens en 250 uitvoertokens elk 0,002 valuta-eenheid. Samen is dat 0,004. Dit oefenmodel rekent geen kortingen, belastingen of andere factuurregels mee.
cost = token_cost(1000,250,2,8)
print(cost['input_cost'])
print(cost['output_cost'])
print(cost['total_cost'])
# 0.002
# 0.002
# 0.004
03Wat neem je mee?
- Vergelijk batchbeleid met dezelfde verzoeken en expliciete serviceaannames.
- Scheid wachtrijduur, totale latentie, staartpercentielen en throughput.
- Controleer aantallen en tariefeenheden voordat je kosten optelt.
Hierna meet je of snelle antwoorden ook goede antwoorden blijven en wat een verschoven verdeling werkelijk zegt.