import { openai } from '@ai-sdk/openai';
import { streamText, StreamData } from 'ai';
// Route handler simplu în Next.js (App Router)
export async function POST(req: Request) {
const { messages } = await req.json();
const data = new StreamData();
const result = await streamText({
model: openai('gpt-4o'),
messages,
onFinish() {
data.close();
},
});
return result.toDataStreamResponse({ data });
}Dacă lucrezi cu LLM-uri în Next.js, știi deja că streaming-ul nu e opțional. Utilizatorul n-o să stea 10-15 secunde să se uite la un spinner până când GPT-4 termină de generat un răspuns lung. UX-ul moare dacă nu ai feedback instantaneu.
La început, când a apărut hype-ul cu AI, am încercat să fac totul „pe genunchi” cu Server-Sent Events (SSE) scrise de mână. Mi-am bătut capul cu ReadableStream, cu encodări de caractere buclucașe și cu gestionarea stării pe client ca să fac textul ăla să apară frumos. La un proiect cu vreo 1.500 de useri activi, codul de frontend devenise un coșmar de useEffect-uri și flag-uri de isLoading care se băteau cap în cap. Atunci m-am prins că pierd prea mult timp pe infrastructură în loc să lucrez la produs.
De ce useChat e „the real deal”
Cea mai mare problemă la streaming-ul manual e sincronizarea. Trebuie să prinzi stream-ul, să-l decodifici bit cu bit și să updatezi un string în state-ul de React. Vercel AI SDK (mai exact hook-ul useChat) rezolvă asta elegant. Îți dă messages, input, handleSubmit și, cel mai important, gestionează istoricul conversației automat.
Am implementat asta recent într-un dashboard și ce mi-a plăcut e că poți să injectezi logică de „optimistic UI” foarte ușor. Când userul apasă Enter, mesajul lui apare instant în listă, chiar dacă stream-ul de la OpenAI abia pornește. Chestia asta schimbă total percepția de viteză a aplicației. Am economisit cam 30% din codul de frontend doar aruncând vechiul meu sistem de management al stării.
Trade-off-uri: Nu e totul roz
Totuși, Vercel AI SDK e extrem de „opinionat”. Dacă ai nevoie de un format de date mai exotic sau dacă vrei să trimiți metadate complexe pe lângă text (de exemplu, niște grafice generate pe parcurs), începi să te lupți cu framework-ul.
Am avut un caz unde trebuia să trimit ID-urile unor documente sursă (pentru RAG) exact înainte să înceapă stream-ul de text. Am pierdut vreo două ore bune până am înțeles cum să folosesc obiectul StreamData ca să trimit informații adiționale fără să stric parser-ul de pe frontend. Merge excelent pentru chat-uri standard, dar devine rigid dacă încerci să-l forțezi să facă altceva.
Edge vs. Node Runtime
O chestie peste care mulți sar la început e runtime-ul. Dacă vrei latență minimă, vrei Edge Runtime. Dar mare atenție: în Edge nu ai acces la toate librăriile de Node. Am pățit să am nevoie de un pachet de crypto mai vechi într-un API route și a crăpat instant la deploy pentru că nu era compatibil cu mediul Vercel Edge.
În plus, dacă folosești streamText, asigură-te că ai configurat corect timeout-urile. Uneori, dacă modelul e lent (cum e GPT-4 în orele de vârf), conexiunea poate fi închisă prematur de proxy-ul Vercel dacă nu primește niciun chunk în primele 10-15 secunde.
Voi cum gestionați stream-urile astea? Mergeți pe mâna Vercel sau preferați controlul total cu o implementare custom de SSE?