Ett mönster jag ser i nybyggda AI-features är att man mäter fel sak. Man tittar på p95-latency på sitt LLM-anrop, alltså svarstiden som 95 procent av anropen ligger under, ser några sekunder, suckar, och börjar prata om att byta till en mindre modell. Samtidigt kan samma fråga i en välbyggd chattapp ta ännu längre tid och ändå kännas snabbare. 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, tiden till första ordet, istället för total tid, och plötsligt är några sekunder okej igen, för det händer något på skärmen nästan direkt.
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 jag håller mig till ä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, alltså grå platshållare i samma form som svaret kommer få, är ett gammalt mönster. Luke Wroblewski beskrev det i Mobile Design Details: Avoid The Spinner på lukew.com, och ändå glömmer halva AI-startup-världen bort det 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.
Ett mönster jag gillar är progressiva skeletter. Först är allt grått. Efter en stund tonar rubrikfältet in med en placeholder-text i stil med "Hämtar kontext från dina dokument". Strax därefter byts den mot nästa steg, "Sammanfattar källorna". 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. Ett välfungerande mönster är att låta användaren 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å. Till per-mening-omskrivningar räcker en liten modell som gpt-5.4-mini eller en mindre Claude-variant, eftersom de är snabba och billiga och kvaliteten håller 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 mycket hög.
Mönstret är enkelt att bygga med pgvector och Postgres som vector store, där förinläsningen startar 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. Det första löser man genom att bara prefetcha när modellanropen är billiga eller cachade, det andra genom att aldrig exponera prefetch-tillståndet i gränssnittet. 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. I agentbaserade flöden med LangGraph eller ett eget orkestreringslager ä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.
Samma teknik hör hemma i agenter som faktiskt skickar något i världen, som mejlutskick, betalningar och bokningar. Där vill jag ha en bekräftelseyta som tar ett par sekunder att rita upp och en explicit klick-för-att-skicka, även om det tekniskt går att göra 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 jag tänker inför en ny AI-feature. Först frågar jag vad output är. Prosa eller struktur. Det avgör om man streamar eller buffrar. Sedan frågar jag 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 det blir accept-knappar eller edit-as-you-go. Sedan tittar jag på flödet före och efter. Vad går att ana om nästa steg. Det avgör om det är värt att prefetcha. Och till sist frågar jag vad känslan ska vara. Snabbt och smidigt, eller övervägd och pålitligt. Det avgör om mellanstegen ska visas eller inte.
Det är fyra frågor, och de tar en kvart att svara på, men jag tror att de gör mer för upplevd kvalitet än något modellbyte. 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 jag tror att 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 länge på ett färdigt svar innan de fattar att de kan redigera det, så är produkten långsam, oavsett vad p95 säger.
Det här är sådant jag bygger på Kapaciti. Hör av dig om du sitter med en AI-feature som känns trög trots att benchmarken ser bra ut.