import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';
export const maxDuration = 30;
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai('gpt-4o-mini'),
system: 'Ești un asistent tehnic direct și concis.',
messages,
});
return result.toDataStreamResponse();
}Să aștepți 12 secunde după un răspuns complet de la un LLM e rețeta garantată să-ți pierzi userii. La un proiect de analiză pe documente cu vreo 4.000 de utilizatori activi, aveam un bounce rate imens pur și simplu pentru că ecranul stătea înghețat pe un skeleton loader.
Trecerea la streaming a coborât latența percepută de la 9 secunde la sub 600ms până la apariția primului token. Utilizatorul vede că sistemul „gândește” în timp real, iar senzația de blocaj dispare complet.
De ce nu merită să scrii SSE de mână în App Router
La prima încercare am vrut să fiu minimalist. Fără librării terțe, doar un ReadableStream nativ într-un Route Handler din Next.js, headere de text/event-stream și Cache-Control: no-cache.
Pe mașina locală totul mergea brici. În producție, pe infrastructură serverless, au apărut bubele reale:
- Buffering agresiv de la proxy-uri intermediare (chunk-urile veneau grămadă, toate deodată, la final);
- Gestionarea conexiunilor întrerupte — dacă userul închidea tabul, funcția pe backend continua să ruleze și să consume tokeni din OpenAI fără sens;
- Parsing-ul manual pe client cu
TextDecoderși recombinarea bucăților tăiate la jumătatea unui caracter UTF-8.
Dacă ai de livrat ceva într-un sprint, pierzi două zile doar ca să stabilizezi parsarea de evenimente în loc să lucrezi la logica de business.
Cum rezolvă Vercel AI SDK problema
Pachetul ai împreună cu providerul dedicat (de exemplu @ai-sdk/openai) abstractizează complet protocolul. Pe backend ai funcția streamText, iar răspunsul îl transformi instant într-un Response standard compatibil cu stream-urile web prin .toDataStreamResponse().
Pe client, hook-ul useChat preia tot calvarul: ține evidența array-ului de mesaje, leagă inputul din formular, gestionează automat starea de isLoading și trimite cererea de anulare (abort) dacă utilizatorul apasă pe butonul de stop.
Un mare avantaj nespus: gestionează nativ tool calling-ul. Dacă LLM-ul tău decide să execute o funcție intermediară, SDK-ul rutează corect apelul fără să-ți crape parserul de text de pe frontend.
Trade-off-uri de care te lovești repede
Nu e totul perfect și merită să știi dinainte costurile ascunse.
În primul rând, durata de execuție pe serverless. Un stream ține conexiunea deschisă 10-25 de secunde. Pe Vercel sau AWS Lambda ești taxat exact pe durata asta. Dacă ai volum mare, ești obligat să treci handlerul pe Edge Runtime sau să scoți bucata de AI pe un VPS separat cu Node.js/Go unde plătești resursa fixă, nu secunda de execuție.
În al doilea rând, randarea de Markdown pe client. Dacă trântești direct react-markdown peste un string care se actualizează la fiecare 20ms, browserul va suferi serios pe telefoane mid-range din cauza refacerii continue a arborelui DOM. Noi a trebuit să punem un mic throttle la update-urile vizuale pentru a păstra scroll-ul fluid.
Voi ați mers pe AI SDK în producție sau preferați un microserviciu separat în Python cu WebSockets?