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

Streaming de la LLM în Next.js: De ce nu mai suportăm ecranele de loading

De Paul Ene, 24 apr. 2026 · 3 vizualizări · 3 like-uri

Postat acum 3 zile
typescript
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';

export const runtime = 'edge';

export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = await streamText({
    model: openai('gpt-4o'),
    messages,
    onFinish({ text }) {
      // Aici salvezi în DB, dar atenție la timeout-uri pe Edge
      console.log('Generare finalizată:', text.length);
    },
  });

  return result.toDataStreamResponse();
}

Am lucrat recent la un proiect de documentare internă unde trebuia să procesăm niște PDF-uri destul de stufoase cu GPT-4o. Prima variantă a fost clasică: trimiteam request-ul, așteptam vreo 12-15 secunde până când modelul termina de generat tot răspunsul și apoi îl afișam în UI. Rezultatul? Userii credeau că aplicația e blocată și dădeau refresh. Eram pe punctul de a pune un spinner obosit, dar mi-am amintit că nu mai suntem în 2010.

Streaming-ul nu e doar un moft de UX, e o necesitate când lucrezi cu LLM-uri care au latență mare. Dacă ai folosit ChatGPT, știi cât de natural se simte când vezi textul apărând cuvânt cu cuvânt. Tehnic, în spate se folosesc Server-Sent Events (SSE), un protocol care permite serverului să trimită date către client fără ca acesta să le ceară constant.

De ce Vercel AI SDK și nu fetch manual?

Poți să scrii singur logica de stream cu ReadableStream și să te lupți cu encodarea textului, dar sincer, am pierdut destule ore cu asta la un proiect anterior. Vercel AI SDK a simplificat enorm procesul. La un proiect cu vreo 5k useri activi, am reușit să reduc timpul până la „primul token” la sub 500ms, comparativ cu acele 12 secunde de așteptare totală.

Partea cea mai faină e hook-ul useChat. Îți gestionează automat starea mesajelor, input-ul și, cel mai important, face „join” la bucățile de text care vin prin stream. Nu mai trebuie să faci tu setMessages([...prev, newChunk]) de mână, ceea ce e un coșmar când ai de-a face cu re-renderări inutile în React.

Trade-off-uri și unde se rupe filmul

Totul sună bine până când trebuie să faci ceva cu datele alea după ce s-a terminat generarea. De exemplu, dacă vrei să salvezi răspunsul în baza de date după ce stream-ul e gata, logica devine puțin mai murdară. Trebuie să folosești callback-uri de tip onFinish.

Un alt aspect e runtime-ul. Pe Vercel, dacă folosești Edge Runtime pentru streaming, ai limitări la ce librării de Node poți folosi. Am pățit să vreau să fac un log simplu într-un serviciu extern și să mă trezesc că librăria respectivă folosea crypto din Node, care nu e disponibil pe Edge.

Plus, debug-ul e mult mai greu. Dacă ai o eroare la jumătatea stream-ului, browser-ul vede un status 200 OK la început și apoi stream-ul pur și simplu se taie. Trebuie să fii foarte atent la error handling pe server-side și să trimiți eventual niște metadata în stream ca să prinzi bubele.

Implementarea în Route Handlers

În Next.js (App Router), totul se întâmplă într-un route.ts. Folosești streamText din pachetul ai și returnezi un TextStreamResponse. E surprinzător de puțin cod pentru cât de mult impact are asupra perceției utilizatorului.

Totuși, mare atenție la costuri. Streaming-ul te face să uiți cât de mult „vorbește” modelul. La proiectul menționat mai sus, am observat o creștere de 20% a consumului de tokeni doar pentru că userii, fiind încântați de viteză, puneau întrebări mult mai lungi și mai dese.

Next.js și Vercel AI SDK fac o echipă bună, dar nu e o soluție „silver bullet” dacă ai nevoie de procesări heavy post-generare. Voi cum gestionați salvarea în DB a răspunsurilor lungi care vin prin stream?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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