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

Streaming de la LLM în Next.js: Cum am redus latența percepută cu 90%

De Adrian Voicu, 3 iul. 2026 · 14 vizualizări · 3 like-uri

Postat 3 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 = await streamText({
    model: openai('gpt-4-turbo'),
    messages,
  });

  return result.toDataStreamResponse({
    headers: {
      // Prevenim buffering-ul pe proxy-uri gen Nginx
      'X-Accel-Buffering': 'no',
    },
  });
}

Am avut de implementat un chatbot pentru un client cu vreo 12.000 de utilizatori activi lunar. La prima versiune, fără streaming, UX-ul era pur și simplu horror. Userul punea o întrebare complexă, API-ul de la OpenAI stătea să gândească vreo 8-9 secunde, timp în care pe ecran se învârtea un loader obosit. Rata de abandon era uriașă. Când am trecut pe streaming cu Server-Sent Events (SSE), timpul până la primul token afișat a scăzut sub 300ms. Senzația e complet alta: utilizatorul vede că aplicația "scrie" instant.

De la un parser manual la useChat

Dacă vrei să scrii tu manual parserul de stream din Fetch API, îți urez succes. Am încercat asta acum un an: trebuie să citești dintr-un ReadableStream, să decodezi bytes în text, să gestionezi caracterele speciale tăiate la mijloc și să updatezi state-ul din React fără să provoci un infinite loop de re-render-uri. E o muncă de chinez bătrân.

Vercel AI SDK (pachetul @ai-sdk/openai și hook-ul useChat) abstractizează tot calvarul ăsta. Pe frontend primești direct un hook care se ocupă de trimiterea mesajelor, salvarea istoricului în state și citirea stream-ului.

Pe frontend, tot ce trebuie să faci este să folosești hook-ul în componentă:

const { messages, input, handleInputChange, handleSubmit } = useChat();

Și gata, legi input la un <input>, handleSubmit la <form> și randezi array-ul de messages care se updatează automat pe măsură ce vin tokenii de pe backend.

Trade-off-urile de care nu-ți zice nimeni în tutoriale

Sună prea frumos ca să fie perfect, nu? Iată ce am pățit noi în producție și unde ne-am spart capul două zile:

  1. Nginx și Cloudflare Buffer: Dacă ai aplicația în spatele unui proxy (cum e Nginx) sau folosești Cloudflare, s-ar putea să vezi că stream-ul nu merge deloc. Serverul trimite datele, dar proxy-ul le ține în buffer până se termină tot răspunsul. Pentru Nginx, a trebuit să adăugăm manual headerul X-Accel-Buffering: no în răspuns.
  2. Serverless Timeout pe Vercel: Pe planul Hobby sau Pro de la Vercel, funcțiile serverless clasice au un timeout de 10 sau 15 secunde. Dacă LLM-ul tău generează un răspuns gigantic, conexiunea se va închide brutal la jumătate. Soluția este să folosești runtime: 'edge' în ruta de API, unde timeout-urile nu sunt la fel de drastice pentru streaming, dar pierzi accesul la anumite librării de Node.js clasice.
  3. Costurile ascunse: Utilizatorii tind să genereze mult mai mult text când văd că se scrie în timp real. Ne-am trezit cu o factură la OpenAI cu 30% mai mare doar pentru că userii nu mai dădeau cancel la fel de des și lăsau chat-ul să curgă.

Concluzia mea

Dacă ai de făcut un simplu wrapper peste GPT-4, Vercel AI SDK e no-brainer. Îți salvează câteva zile bune de boilerplate și funcționează brici. Dar dacă ai nevoie de logică complexă de backend, cum ar fi salvarea intermediară în DB în timpul streamingului sau formatări custom de markdown pe client, pregătește-te să sapi adânc în documentație.

Voi cum gestionați erorile de rețea la streaming? Le faceți retry automat în fundal sau lăsați userul să apese manual pe un buton de 'regenerate'?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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