Latency är en feature. Så här tänker vi när användaren väntar
En sak jag märker när jag testar nybyggda AI-features hos andra team är att de nästan alltid mäter fel sak. De tittar på p95-latency på sitt LLM-anrop, ser 4.2 sekunder, suckar, och börjar prata om att byta till en mindre modell.
Alexander Galldin
Kapaciti
En sak jag märker när jag testar nybyggda AI-features hos andra team är att de nästan alltid mäter fel sak. De tittar på p95-latency på sitt LLM-anrop, ser 4.2 sekunder, suckar, och börjar prata om att byta till en mindre modell. Sedan visar jag dem samma feature i en chattapp som tar 6 sekunder på samma fråga, och de säger att den känns snabbare. Klassiskt. Det handlar nästan aldrig om hur lång tid svaret tar att generera. Det handlar om vad användaren tittar på under tiden.
Det är där den här posten landar. Latency i en AI-produkt är inte bara en teknisk siffra du ska minimera. Det är en yta du designar. Om du gör det rätt blir väntan en del av upplevelsen, ibland till och med det som får produkten att kännas seriös. Om du gör det fel sitter användaren och stirrar på en spinner i fyra sekunder och tror att det är trasigt.
Streaming är default, men inte alltid rätt
Det första alla bygger nuförtiden är streaming. Token-för-token, som ChatGPT. Och det funkar. Hjärnan börjar läsa de första orden innan modellen ens är klar med sista meningen, och den upplevda latencyn rasar. Vi pratar om time-to-first-token istället för total response time, och plötsligt är 4 sekunder okej igen, för redan efter 400 ms händer det något på skärmen.
Men streaming är inte alltid svaret. Det jag är trött på är att se streaming användas reflexmässigt även när det aktivt försämrar produkten. Ta ett klassisk exempel: en agent som ska klassificera ett mejl och returnera en JSON med tre fält. Om du streamar det får användaren se halvfärdig JSON växa fram tecken för tecken, och du måste antingen dölja det bakom en spinner ändå eller exponera det som blinkande råtext. Då har du betalat för streaming utan att få något tillbaka. Kör hela svaret, parsa, och visa sedan en snyggt formaterad ruta. Det blir snabbare upplevt om du samtidigt visar en bra skeleton-state, vilket vi kommer till.
Tumregeln vi jobbar efter är enkel. Streama när output är prosa som användaren ska läsa. Buffra när output är struktur som användaren ska konsumera. En kund som ber om en sammanfattning av ett möte ska se orden droppa in. En backend-agent som ber Claude att returnera en lista med kontaktuppgifter ska köra färdigt och visa kortet i ett svep. Det är två helt olika UX-problem som råkar dela samma underliggande modellanrop.
Skeleton states som ljuger på rätt sätt
Skeleton-states är gammal Facebook-teknik från 2013, och ändå glömmer halva AI-startup-världen bort dem när de bygger sin första chattprodukt. Felet de gör är att visa en spinner. En spinner kommunicerar två saker: något händer, och jag har ingen aning om vad. En skeleton kommunicerar: något händer, och här är en preview av vad som kommer.
Den intressanta varianten i AI-produkter är att skeletten kan vara informerad. Om du vet att svaret kommer bli ett kort med rubrik, tre bullets och ett källblock, så rita upp den layouten med pulserande grå rektanglar i exakt rätt storlekar redan medan modellen tänker. Användaren ser strukturen formera sig innan innehållet finns. Det här fungerar för att hjärnan börjar bygga förväntan på vad som kommer, och förväntan tar bort den där tomma kognitiva pausen som spinner-väntan består av.
Vi gör ofta en till sak: vi visar progressiva skeletter. Första 200 ms är allt grått. Vid 800 ms tonar rubrikfältet in med en placeholder-text som "Hämtar kontext från dina dokument". Vid 1500 ms byts det till "Sammanfattar 14 källor". Användaren får en känsla av att maskineriet tuggar, även om de exakta stegen är ungefärliga. Min teori är att det här fungerar så bra för att människor är vana vid att kompetenta saker tar tid. En jurist som svarar på två sekunder känns slarvig. En jurist som "går igenom underlaget" i fem sekunder känns grundlig. Samma sak gäller AI.
Edit-as-you-go i stället för accept eller reject
Det här är en av få saker där jag tycker att hela branschen tänker fel. Den dominerande mönstret för AI-genererat innehåll är fortfarande accept-eller-reject. Modellen föreslår en text. Användaren får två knappar: använd, eller börja om. Det är samma logik som autoreply från 2010. Och det skapar en konstig dynamik där användaren antingen tar något halvbra för att de inte orkar göra om, eller scrollar igenom fem regenereringar och blir frustrerad på att modellen inte fattar.
Bättre mönster: edit-as-you-go. AI:n genererar ett utkast direkt in i en redigerbar yta. Inga modaler, inga preview-paneler, ingen knapp som heter "Acceptera". Texten är redan din från första millisekunden. Du kan börja skriva över den medan resten streamas in nedanför. Cursor har gjort det här bra för kod, och det är samma princip som funkar för mejl, sammanfattningar, brief-utkast, allt. Vi byggde en intern variant där användaren kan klicka på vilken mening som helst i ett AI-utkast och få tre alternativa formuleringar i en liten popup, utan att behöva regenerera hela texten. Det är en mycket mer naturlig arbetsmodell, för du tänker inte "är det här bra eller dåligt", du tänker "den här meningen är konstig, fixa den".
Tekniskt är det inte särskilt komplicerat. Du behöver en editor som tål att text injiceras under tiden användaren skriver, en diff-logik som inte krockar med markören, och en förmåga att göra mindre LLM-anrop på meningsnivå. Vi använder ofta gpt-5.4-mini eller en mindre Claude-variant för dessa per-mening-rewrites, eftersom de är snabba och billiga, och kvaliteten räcker för enstaka meningar. Den stora modellen får göra första utkastet, småmodellen sköter mikroredigeringen.
Prefetch när du anar nästa fråga
Det här är knepet ingen pratar om, men som ger den största upplevda hastighetsvinsten. Om du kan gissa vad användaren kommer fråga om härnäst, börja generera svaret innan de hinner trycka på knappen. När de väl klickar är svaret redan på väg eller helt klart, och latencyn känns som noll.
Det funkar oftare än man tror. Säg att du har en supportagent där användaren just har fått ett svar om en faktura. Sannolikheten att nästa fråga handlar om betalningsmetoder eller förfallodatum är hög. Du kan börja förbereda kontext för de troliga uppföljningarna i bakgrunden direkt efter att första svaret levererats. Eller säg att du har en analysprodukt där användaren just laddat upp ett dokument. Börja embedda och indexera direkt, även innan användaren har formulerat sin första fråga, för chansen att de kommer ställa en är 100 procent.
Vi har använt det här mönstret i flera bygger med pgvector och Postgres som vector store, där förinläsningen sker så fort en fil dyker upp. När användaren sedan ställer sin första fråga är det första RAG-anropet redan varmt. För agentbaserade flöden kan du gå längre och faktiskt köra spekulativa LLM-anrop mot de troligaste tre frågorna, cacha resultaten, och slänga de som inte används. Det kostar tokens, men om din produkt har en hög konverteringsgrad mellan steg är det värt det. För Anthropic Claude och OpenAI gpt-5.4 är prompt caching dessutom inbyggt, så återanvänd kontext kostar nästan inget efter första anropet.
Riskerna är två. En, du betalar för svar som aldrig konsumeras. Två, om du gissar fel kan det kännas konstigt om användaren märker att fel sak förbereddes. Vi löser det första genom att bara prefetcha när modellanropen är billiga eller cachade, och det andra genom att aldrig exponera prefetch-tillståndet i UI. Användaren ska aldrig se "förbereder svar på fråga du inte ställt". De ska bara uppleva att produkten är magiskt snabb.
När du SKA få det att kännas långsamt
Här blir det kontraintuitivt. Ibland är snabbt fel. Det finns kategorier av AI-svar där omedelbar leverans aktivt skadar förtroendet, och där du medvetet bör bygga in väntan.
Klassiska fall är beslutsstöd, juridiska sammanfattningar, medicinsk triage, finansiell rådgivning, och allt annat där användaren behöver känna att svaret är genomtänkt. Om du frågar en AI-assistent om du ska säga upp ett anställningsavtal och får svar på 600 ms, så litar du inte på det. Om samma svar tar 4 sekunder och visar mellansteg som "Granskar lagrum", "Jämför med praxis", "Formulerar rekommendation", så känns det helt annorlunda. Innehållet är identiskt. Förtroendet är inte det.
Det här är inte manipulation, det är ärlig kommunikation av att en process är komplex. Och faktum är att i många fall är processen faktiskt komplex. När vi bygger agentbaserade flöden med LangGraph eller egna orkestreringslager, så är det ofta sant att modellen gör flera anrop, hämtar dokument, jämför, sammanställer. Det är bara att den gör det snabbt. Att exponera de stegen som synliga statusmeddelanden är ärligare än att gömma dem bakom en spinner.
Vi använder samma teknik för agenter som faktiskt skickar något i världen. Mejlutskick, betalningar, bokningar. Där lägger vi medvetet in en bekräftelseyta som tar 2 sekunder att rita upp och en explicit klick-för-att-skicka, även om vi tekniskt skulle kunna göra det direkt. Det handlar inte om hastighet, det handlar om att ge användaren känslan av att hen har kontroll. Den där lilla pausen är skillnaden mellan en produkt som känns mogen och en som känns oroande.
Vad det betyder i praktiken
Om jag skulle dra ihop allt det här till en arbetsmetod, så är det ungefär så här vi tänker när vi bygger en ny AI-feature. Först frågar vi vad output är. Prosa eller struktur. Det avgör om vi streamar eller buffrar. Sedan frågar vi vad användaren ska göra med svaret. Läsa det och nicka, eller redigera det och göra det till sitt. Det avgör om vi har accept-knappar eller edit-as-you-go. Sedan tittar vi på flödet före och efter. Vad anar vi om nästa steg. Det avgör om vi prefetchar. Och till sist frågar vi vad känslan ska vara. Snabbt och smidigt, eller övervägd och pålitligt. Det avgör om vi visar mellansteg eller inte.
Det är fyra frågor, och de tar typ 15 minuter att svara på, men de gör mer för upplevd kvalitet än någon modellbyte vi har gjort under hela förra året. Jag fattar fortfarande inte varför så få team gör det här arbetet uppfront. Det är billigare än att optimera bort en sekund av faktisk latency, och effekten är större.
En sista grej. Mät rätt sak. Time-to-first-token är viktigare än total tid. Time-to-first-meaningful-content är ännu viktigare. Och time-to-user-action, alltså hur lång tid det tar innan användaren faktiskt gör något med svaret, är det enda måttet som korrelerar med produktnytta. Om de stirrar i 8 sekunder på ett färdigt svar innan de fattar att de kan redigera det, så är produkten långsam, oavsett vad p95 säger.
På Kapaciti bygger vi mycket av det här. Hör av dig om du sitter med en AI-feature som känns trög trots att benchmarken ser bra ut.