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

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

De Ștefan Iliescu, 26 iul. 2026 · 11 vizualizări · 3 like-uri

Postat 26 iul. 2026
typescript
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'),
    messages,
    system: 'Ești un asistent tehnic util. Răspunde scurt și la obiect.',
  });

  return result.toDataStreamResponse();
}

Am refăcut recent interfața pentru un asistent AI intern pe care îl folosesc băieții din support la un proiect cu peste 12k interogări pe zi. Problema veche era clasică: utilizatorul punea o întrebare, aștepta 4-5 secunde în fața unui spinner obosit, după care primea un zid de text. Trecerea pe streaming prin Server-Sent Events (SSE) a schimbat radical aplicația, iar hook-ul useChat din Vercel AI SDK mi-a salvat cam 3 zile de Boilerplate Code.

De ce streaming și ce înseamnă pentru UX

Când lucrezi cu LLM-uri (OpenAI, Anthropic, Ollama), latența e inamicul numărul unu. Să generezi 500 de tokeni durează ceva. Dacă aștepți ca backend-ul să adune tot răspunsul înainte să trimită un 200 OK, experiența e oribilă.

Cu streaming prin SSE, conexiunea HTTP rămâne deschisă și primești bucăți de text (chunk-uri) pe măsură ce sunt calculate de model. Până când utilizatorul citește primele două cuvinte, restul frazei e deja generat. În metricele noastre, Time To First Byte (TTFB) perceput de user a scăzut de la 4.2 secunde la sub 180ms.

Cum rezolvă Vercel AI SDK mizeria din frontend

Acum 2 ani, când făceam streaming manual în React, trebuia să-mi scriu singur un Fetch custom cu ReadableStream, să gestionez reconectările, să parsez manual liniile care începeau cu data: și să combin tokenii în state. Un haos de cod unde mai scăpau memory leak-uri.

Vercel AI SDK a simplificat treaba la un nivel nesimțit de simplu. Pe frontend folosești hook-ul useChat, iar pe backend folosești streamText dintr-un Route Handler de Next.js App Router.

Hook-ul useChat îți oferă direct starea messages, funcția handleSubmit, input, starea de isLoading și chiar o funcție de stop în caz că userul vrea să oprească generarea la jumătate. Nu mai stai să faci update manual în useState pentru fiecare token primit.

Unde m-am lovit de pragul de sus (Trade-offs reale)

Nu e totul numai lapte și miere, evident. Când treci la streaming, apar niște probleme tehnice specifice de care te lovești rapid:

  1. Layout shift pe Markdown: Dacă LLM-ul trimite un bloc de cod sau un link, tokenii ajung sparți. De exemplu, prima dată vine ` apoi ` apoi `js. Dacă folosești un renderer de markdown neinspirat, interfața ta va pâlpâi și va sări sus-jos ca nebuna pe măsură ce se închid și se deschid tag-urile HTML.
  2. JSON Mode / Structured Outputs: Streaming-ul e genial pentru text liber. Dacă în schimb ai nevoie ca modelul să-ți returneze un JSON valid pentru a randa niște carduri dinamice în UI, e mult mai greu. Trebuie să folosești streamObject și un schema Zod, dar parsing-ul parțial pe un JSON incomplet poate genera erori dacă nu e tratat corect.
  3. Vercel Edge Runtime vs Node.js: Dacă pui ruta pe Edge, streaming-ul pornește aproape instant (n-ai cold start de Lambda). Dar dacă în aceeași rută trebuie să apelezi o librărie mai veche care depinde de module native de Node (fs, crypto), va trebui să rămâi pe Node.js runtime, unde poți avea un mic delay la pornire.

Concluzie

Dacă construiești ceva cu LLM-uri în Next.js azi, să scrii un parser manual de SSE e o pierdere de timp. Combo-ul streamText + useChat acoperă 90% din cazuri out-of-the-box.

Voi mai scrieți handlere custom de fetch pe stream-uri sau ați trecut toți pe AI SDK?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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