Door streaming voelt een AI-interface responsief aan, omdat de gebruiker de voortgang kan zien nog voordat het volledige antwoord klaar is. Bovendien wordt één verzoek zo omgezet in een levenscyclus die de modelaanbieder, de applicatieserver, de reverse proxy en de browser omvat.
Ik wil dat die levenscyclus uit welomschreven statussen bestaat. Het afsluiten van een verbinding, het voltooien van een provider en een antwoord dat de validatie doorstaat, zijn verschillende gebeurtenissen. Als je ze alle drie als ‘voltooid’ beschouwt, wordt het moeilijk om fouten te verklaren.
Kies een vervoersmiddel dat bij de interactie past
Door de server verzonden gebeurtenissen zijn zeer geschikt voor een stroom van updates van de server naar de client. Het gebeurtenisformaat ondersteunt gebeurtenissen met een naam, ID’s en gegevensvelden, zoals beschreven in de SSE-handleiding van MDN.
De ingebouwde EventSource-interface van de browser is handig voor het ontvangen van een stream, maar toepassingen die een POST-body of aangepaste verzoekheaders nodig hebben, kunnen in plaats daarvan gebruikmaken van een op fetch gebaseerde streamingclient. Die keuze bepaalt welk gedrag op het gebied van parseren en herverbinding de toepassing zelf moet implementeren.
Ik maak authenticatie, het verzenden van verzoeken en het abonneren op streams expliciet. Inloggegevens mogen niet in een URL worden opgenomen, louter omdat dat handig is om een verbinding tot stand te brengen.
Definieer het applicatieprotocol
Een nuttige stream zou onderscheid kunnen maken tussen acceptatie, voortgang, tekst, validatiestatus, voltooiing en mislukking. De namen van de gebeurtenissen zijn keuzes van de toepassing; het zijn geen garanties die door het transport worden geboden.
event: accepted
data: {"request_id":"req_example"}
event: text_delta
data: {"text":"The available sizes are"}
event: completed
data: {"request_id":"req_example","status":"complete"}
Dit voorbeeld illustreert het begrip ‘framing’. Een echte parser moet omgaan met netwerkblokken die een gebeurtenis opsplitsen, meerdere gebeurtenissen bevatten of een multibyte-teken opsplitsen. Een netwerklezing is niet automatisch één volledig bericht.
Beperk de hoeveelheid gegevens die in het geheugen staat te wachten
Als de verbinding stroomafwaarts traag is, kan de server de output van de provider sneller ontvangen dan hij deze kan doorgeven. Onbeperkte buffering zorgt ervoor dat een trage client een geheugenprobleem wordt.
De toepassing moet rekening houden met de druk op de schrijfbare stream en een bufferlimiet vaststellen. Wanneer het upstream-protocol niet op een zinvolle manier kan worden gepauzeerd, kan het veiliger zijn om de bewerking af te breken dan de wachtrij oneindig te laten groeien.
In de uitleg over de Streams API van MDN wordt backpressure beschreven als een mechanisme voor stroomregeling. In een LLM-toepassing moet ik dat mechanisme nog koppelen aan het annuleren door de provider en het time-outbeleid van het product.
De annulering doorvoeren in het gehele verzoek
Het sluiten van de browserverbinding moet leiden tot het opschonen van de toepassing en, indien ondersteund, tot het annuleren van het upstream-modelverzoek. Timers, listeners en buffers moeten worden vrijgegeven, zelfs als de annulering zelf mislukt.
Het feit dat de klant de verbinding verbreekt, bewijst echter niet dat de dienstverlener het factureerbare werk heeft stopgezet. Bij de verbruiksafrekening moet deze onzekerheid in aanmerking worden genomen en moeten de gegevens worden afgestemd op basis van de beschikbare verbruiksgegevens van de dienstverlener.
Ook langdurige verbindingen lopen via proxyservers met instellingen voor buffering en time-out. Ik test het geïmplementeerde pad, omdat een stream die rechtstreeks op een ontwikkelingsserver werkt, zich anders kan gedragen binnen de productie-infrastructuur.
Bepaal hoe gedeeltelijke antwoorden worden weergegeven
Een antwoord dat halverwege afbreekt, moet zichtbaar onvolledig blijven. Bij het herstellen van de verbinding mag er niet stilzwijgend een nieuwe modelaanroep worden uitgevoerd of een nieuw antwoord aan het onvolledige antwoord worden toegevoegd.
Voor het hervatten zijn een bewaarde gebeurtenisgeschiedenis en een gedefinieerde cursor nodig; een gebeurtenis-ID alleen volstaat niet om het afspelen te implementeren. Bij een eenvoudiger product is het wellicht duidelijker om een expliciete herstart aan te bieden.
Validatie biedt nog een andere optie. Als de feitencontroles vóór de publicatie moeten zijn afgerond, moet de betreffende inhoud in de buffer worden opgeslagen. Tekst onmiddellijk weergeven en deze pas daarna controleren, is een andere productbelofte.
Ik controleer op trage clients, afgebroken verzoeken, time-outs bij de proxy, storingen bij de provider en onjuist gevormde gebeurtenisgrenzen. Een goede streaminginterface voelt snel aan en biedt tegelijkertijd betrouwbare informatie over de voltooiingsstatus.
Bijgewerkt op 25 september 2026.