Hoppa till innehåll
AI EngineeringStreamingSSEWebSockets11 min läsning

Streaming i LLM-appar: SSE, WebSockets och backpressure-hantering

Hur jag strömmar tokens till användaren så att appen känns snabb - och vad som händer när klienten inte hinner med servern.

24 februari 2026Uppdaterad 10:00
00
Streaming i LLM-appar: SSE, WebSockets och backpressure-hantering
Strömmande tokens gör en långsam modell uthärdlig - upplevd hastighet slår faktisk.Photo: Unsplash

Token-streaming i LLM-appar. SSE, WebSockets och backpressure.

En LLM kan ta många sekunder på sig att skriva ett långt svar. Visar du en spinner under tiden känns appen död; strömmar du ut svaret ord för ord känns den levande, trots att den faktiska tiden är densamma. Upplevd hastighet är ofta viktigare än faktisk, och det är därför streaming inte är en lyx utan en grundförväntan i moderna LLM-appar. Men streaming öppnar också en rad tekniska frågor som inte syns förrän man är i produktion: vilket transportlager, hur hanterar man avbrott, och vad gör man när mottagaren inte hinner med.

Jag har byggt strömmande gränssnitt för svenska produkter och nedan går jag igenom valen som faktiskt spelar roll. Det lurigaste med streaming är att det nästan alltid fungerar perfekt på utvecklarens maskin och först visar sina problem i produktion, under last, genom flera lager av infrastruktur. Därför handlar mycket av det här om att förstå vad som händer mellan modellen och webbläsaren, inte bara hur man läser en ström i sin egen kod.

SSE eller WebSockets - vad ska du välja?

För de flesta LLM-appar är Server-Sent Events (SSE) rätt val. Det är enkelriktat från server till klient, vilket passar perfekt för att strömma ut ett svar, och det bygger på vanlig HTTP utan extra protokoll. WebSockets ger tvåvägskommunikation och är värt det när du verkligen behöver dubbelriktad realtid - som i röstapplikationer, vilket jag beskriver i artikeln om voice AI. Min default är SSE för text och WebSockets först när behovet av tvåvägstrafik är reellt. Att välja WebSockets för en ren textström är vanligen onödig komplexitet.

  • SSE: enkelriktat, bygger på HTTP, enkelt att återansluta - default för textsvar.
  • WebSockets: tvåvägs, mer overhead - rätt när klienten också skickar löpande.

Backpressure: när klienten inte hinner med

Här ligger det som få tänker på förrän det smäller. Servern kan producera tokens snabbare än klienten, nätet eller ett mellanled hinner ta emot dem. Utan hantering byggs en buffert upp som äter minne, och i värsta fall kraschar processen under last. Backpressure handlar om att låta mottagarens takt styra: pausa produktionen när bufferten fylls och återuppta när det finns plats. Det är skillnaden mellan en app som tål många samtidiga strömmar och en som faller över vid trafiktoppar.

Hantera avbrutna strömmar

Användare stänger flikar, byter nätverk och tappar uppkoppling mitt i ett svar. En strömmande app måste upptäcka när mottagaren försvunnit och då sluta generera - annars betalar du för tokens som ingen läser. Jag kopplar därför klientens avbrott hela vägen tillbaka till modellanropet, så att en stängd flik faktiskt avbryter genereringen. Det är både en kostnads- och en resursfråga, som hänger ihop med det jag skriver om i kostnadsoptimering.

Avbrott i andra riktningen är minst lika viktigt: vad gör appen om strömmen bryts halvvägs på grund av ett nätverksglapp? Användaren ska inte lämnas med ett halvt svar och ingen förklaring. Jag bygger in så att klienten märker när strömmen tagit slut i förtid och kan visa det tydligt, och i lägen där det är möjligt erbjuda att fortsätta eller göra om. Att tänka igenom det ofullständiga svaret hör till de detaljer som skiljer en genomarbetad app från en demo.

Strömma genom flera lager

I praktiken passerar en ström sällan rakt från modell till webbläsare. Den går ofta genom en proxy, en gateway eller en serverlös funktion, och varje led kan buffra eller bryta strömmen om det inte är rätt konfigurerat. Jag verifierar att hela kedjan släpper igenom data löpande - en enda buffrande mellanhand gör att hela streaming-vinsten försvinner och svaret kommer i ett enda klump. Kör ni en AI-gateway behöver den vara inställd för strömning, vilket jag berör i artikeln om gateways.

Att få strömningen att fungera hela vägen, inklusive backpressure och avbrott, är en återkommande del av leveranserna inom AI Engineering, och det är ofta detaljerna i mellanlagren som avgör.

Strömma strukturerade svar

Det blir knepigare när svaret ska vara strukturerat. Att strömma partiell JSON kräver att klienten kan hantera ofullständiga objekt under tiden de byggs upp. Ibland är rätt svar att strömma ett synligt textsvar för känslan men vänta med den strukturerade datan tills den är komplett. Hur jag tänker kring garanterad struktur beskriver jag i artikeln om structured outputs.

Det är just i de här mellanlagren jag oftast hittar buggen när en kund säger att deras streaming "inte fungerar i produktion". Serverlösa plattformar och edge-miljöer har egna regler för hur länge ett svar får strömma och hur det buffras, och en standardkonfiguration som passar vanliga API-svar kan tyst förstöra en ström. Jag verifierar därför alltid streaming i den faktiska driftmiljön, inte bara lokalt, eftersom det är där sanningen visar sig.

Mät det användaren känner

Den siffra som spelar mest roll för upplevelsen är tiden till första token - hur snabbt något börjar hända - snarare än den totala tiden. Jag mäter den separat, eftersom en app kan ha hög total latens men ändå kännas snabb om första token kommer direkt. Det är en av flera dimensioner jag följer i en utvärderingssvit enligt mina evals-principer.

Relaterat

Ett exempel på en strömmande app som klarade en trafiktopp tack vare backpressure finns bland mina kundcase.

Vill du ta det vidare?

Har er LLM-app en spinner där den borde ha en ström, eller faller den över vid många samtidiga användare? Boka ett förutsättningslöst samtal så tittar vi på er pipeline.

Upplevd hastighet är ofta viktigare än faktisk - strömmar du svaret känns en långsam modell snabb.

- Simon Axelsson

Vanliga frågor

SSE eller WebSockets för en chattapp?
SSE för de flesta textsvar. Det är enkelriktat från server till klient, bygger på vanlig HTTP och är enkelt att återansluta - precis vad en utströmmande text behöver. WebSockets är värt sin extra komplexitet först när klienten också skickar löpande, som i röstapplikationer.
Vad är backpressure och varför spelar det roll?
Det är hanteringen av att servern kan producera tokens snabbare än klienten eller nätet hinner ta emot dem. Utan den byggs buffertar upp som äter minne och kan krascha processen under last. Med backpressure pausar produktionen när bufferten fylls, vilket gör att appen tål många samtidiga strömmar.
Varför fungerar inte min streaming i produktion fast den fungerar lokalt?
Oftast för att ett mellanlager buffrar. En proxy, en gateway eller en serverlös funktion kan samla upp hela svaret innan det skickas vidare, vilket gör att det kommer i ett klump. Verifiera att varje led i kedjan är konfigurerat för att släppa igenom data löpande.

Om författaren

Simon Axelsson
Simon AxelssonIT-konsult & teknisk rådgivare

Simon Axelsson är senior IT-konsult och grundare av SIAX Technology AB. Han hjälper nordiska företag med molninfrastruktur, dataplattformar och AI-automation.

Fler artiklar av Simon