eduardweb.
AI & LLMsIntermediar#nextjs#typescript#react#vercel-ai-sdk#llm

Streaming de la LLM în Next.js fără bătăi de cap: Vercel AI SDK și SSE

De Ștefan Iliescu, 4 aug. 2026 · 10 vizualizări · 3 like-uri

Postat 4 aug. 2026
typescript
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';

// Mărim timeout-ul pentru Vercel serverless
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 pragmatice. Răspunzi scurt și la obiect.',
    messages,
  });

  // Transformă stream-ul într-un Response compatibil cu SSE / Vercel AI SDK
  return result.toDataStreamResponse();
}

Am integrat recent un modul de AI pentru clientul nostru pe un SaaS cu vreo 12k useri activi lunar. Prima versiune trimitea request-ul clasic, aștepta ca modelul de la OpenAI să termine tot textul și abia apoi returna JSON-ul. Rezultatul? Userul stătea 4-5 secunde în fața unui spinner inert. O mizerie de UX. Soluția evidentă a fost streaming-ul prin Server-Sent Events (SSE), iar cu Vercel AI SDK am rezolvat totul în câteva ore.

De ce SSE și nu WebSockets?

Când zici streaming, mulți juniori sar direct la WebSockets. E o greșeală frecventă. Pentru o comunicare unidirecțională — unde doar serverul îți trimite bucăți de text pe măsură ce LLM-ul generează jetoane (tokens) — WebSockets aduc o complexitate inutilă. Trebuie să gestionezi conexiuni persistente, handshaking, stateful servers sau un broker gen Redis Pub/Sub dacă scalezi serverless.

SSE folosește HTTP standard. E practic o conexiune HTTP simplă care rămâne deschisă (Content-Type: text/event-stream), iar serverul „picură” date pe măsură ce le primește. Lucrează impecabil cu arhitecturile serverless și pe Vercel, atâta timp cât respecti limitele de timeout.

Backend-ul în App Router: scurt și la obiect

În Next.js App Router, implementarea unui Route Handler de streaming e extrem de curată. Folosim streamText din pachetul ai și librăria oficială de provider @ai-sdk/openai.

Cea mai mare capcană aici este durata de execuție. Pe planul Hobby de la Vercel, un Route Handler crapă după 10 secunde. Dacă LLM-ul tău generează un răspuns lung sau folosești un model mai lent gen GPT-4o, conexiunea va fi tăiată abrupt. Trebuie să setezi export const maxDuration = 30; (sau mai mult dacă ești pe Pro) ca să eviti asta.

Frontend-ul cu useChat: magia din spate

Vercel AI SDK oferă hook-ul useChat pe frontend. Acesta face câteva lucruri grele automat:

  1. Gestionează starea listei de mesaje (messages).
  2. Când apelezi handleSubmit, trimite tot istoricul către endpoint-ul de API.
  3. Ascultă stream-ul SSE și face append în timp real la ultimul mesaj, declanșând re-render la fiecare bucată de text primită.

Unde apare trade-off-ul? În re-renderings. La un răspuns foarte lung, componenta ta de chat se va randa de zeci sau sute de ori pe secundă. Dacă ai o listă mare de mesaje fără virtualizare sau componente neseperate corect (de exemplu, dacă randezi Markdown greu la fiecare token), o să vezi că UI-ul începe să agațe pe telefoane mai vechi. Trucul e să izolezi mesajul care se află în stare de streaming sau să folosești React.memo pe componentele mesajelor anterioare care sunt deja „înghețate”.

O altă problemă reală e re-conectarea. Dacă conexiunea pică la tokenul 150 din cauza rețelei pe mobil, SSE-ul nativ încearcă să reia conexiunea, dar Vercel AI SDK va arunca o eroare în UI dacă nu pui un handler de onError. Eu am ales să afișez un buton discret de „Re-try” în loc să las aplicația blocată în stare de loading.

Voi ce folosiți pentru gestionarea erorilor când crapă stream-ul la jumătate?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.