Intégrer des LLMs dans une application React
Streaming, architecture serveur et gestion des erreurs — ce qu'il faut maîtriser avant d'intégrer un LLM dans votre produit React.
La majorité des intégrations LLM en production partagent le même défaut : elles traitent l'API comme une requête REST ordinaire. On envoie, on attend, on affiche. Résultat : une UI figée pendant 10 à 15 secondes. Ce guide couvre les trois points qui font la différence.
Pourquoi le streaming est non-négociable
Les LLMs génèrent du texte token par token. Sans streaming, l'utilisateur attend la génération complète avant de voir quoi que ce soit — souvent 8 à 15 secondes pour un message de 200 tokens. Avec streaming, les premiers tokens apparaissent en moins d'une seconde. L'expérience est radicalement différente.
Les APIs OpenAI, Anthropic et Mistral supportent toutes les Server-Sent Events. Le streaming n'est pas une optimisation à ajouter plus tard — c'est l'architecture de base. Partir sans streaming, c'est construire sur des fondations qu'on devra casser.
Architecture : ne jamais appeler un LLM depuis le client
La clé API ne doit jamais être exposée dans le bundle JavaScript — l'inclure dans le code client revient à la rendre publique. La solution standard : une route API Next.js qui proxifie la requête côté serveur, avec la clé stockée dans les variables d'environnement.
// app/api/chat/route.ts
import { OpenAI } from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
export const runtime = 'edge';
export async function POST(req: Request) {
const { messages } = await req.json();
const stream = openai.beta.chat.completions.stream({
model: 'gpt-4o',
messages,
});
return new Response(stream.toReadableStream());
}Le flag `runtime = 'edge'` déploie cette route sur le réseau Edge de Vercel ou Netlify. La latence au premier token est réduite de 30 à 40 % par rapport à un serverless classique — sur une intégration LLM, chaque milliseconde de latence initiale se ressent.
Consommer le stream côté React
React n'a pas de primitif natif pour les streams de texte. L'approche la plus directe : lire le ReadableStream dans une fonction async et accumuler les chunks dans un état local.
async function send(content: string) {
setStreaming(true);
setOutput('');
const res = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ messages: [{ role: 'user', content }] }),
});
const reader = res.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
setOutput(prev => prev + decoder.decode(value, { stream: true }));
}
setStreaming(false);
}Note sur `decode({ stream: true })` : sans ce flag, les séquences UTF-8 multi-octets peuvent être coupées entre deux chunks et produire des caractères corrompus. C'est le genre de bug qui n'apparaît qu'avec des textes contenant des accents ou des émojis.
Gestion des erreurs en production
Trois cas à anticiper systématiquement avant de mettre en production :
- Timeout : un AbortController avec délai de 30 secondes. Sans ça, une requête bloquée peut rester ouverte indéfiniment côté client.
- Rate limit (HTTP 429) : intercepter le statut, lire le header Retry-After, proposer une relance automatique avec backoff exponentiel.
- Stream interrompu : vérifier en fin de lecture que la réponse est complète. Afficher un état d'erreur clair plutôt qu'un texte tronqué silencieux.
Un dernier point souvent négligé : logguer les latences. La durée entre la requête et le premier token (TTFT — time to first token) et la durée totale sont les deux métriques à surveiller. Elles révèlent les dégradations de service avant que les utilisateurs ne les signalent.
Le streaming n'est pas une optimisation à ajouter plus tard. C'est l'architecture de base. Partir sans streaming, c'est construire sur des fondations qu'on devra casser.
Écrit par
Casian Ciorba
6 ans de projets livrés en production — logiciels, SaaS, applications mobiles et intégrations IA. J'écris sur ce que j'utilise réellement en mission, pas sur ce qui fait les conférences.