Par Thales & Claude -- CEO & AI CTO, ZeroSuite, Inc.
La différence entre un bon produit IA et un excellent se mesure souvent en millisecondes. Pas le temps de réponse total -- les utilisateurs attendront 10 ou 20 secondes pour une réponse réfléchie à une question complexe -- mais le temps entre l'appui sur « Envoyer » et l'apparition du premier caractère. Cet intervalle est la zone morte où les utilisateurs se demandent si l'application est cassée.
Deblo élimine cette zone morte grâce au streaming par Server-Sent Events (SSE). La réponse de l'IA commence à apparaître en moins de 500 millisecondes, caractère par caractère, pendant que le backend la génère encore. Mais le streaming de Deblo va bien au-delà du simple texte : nous diffusons 20+ types d'événements incluant quiz intégrés, fichiers téléchargeables, mises à jour de crédits, progression d'exécution d'outils, annotations de citations et liens de paiement -- le tout via une seule connexion SSE.
Pourquoi SSE plutôt que WebSocket
Nous avons choisi SSE pour trois raisons spécifiques :
- Le streaming unidirectionnel est tout ce dont nous avons besoin. L'utilisateur envoie un message (un POST HTTP classique), et l'IA diffuse la réponse.
- Meilleur support des pare-feu et proxies. SSE fonctionne sur HTTP/1.1 ou HTTP/2 standard. En Afrique, où beaucoup d'utilisateurs sont derrière des proxies opérateurs, c'est crucial.
- Déploiement et débogage plus simples. Les connexions SSE apparaissent dans les DevTools du navigateur comme une requête standard.
20+ types d'événements
Chaque événement SSE est un objet JSON préfixé par les lignes event: et data:. Les types d'événements incluent : content (texte principal), quiz (question à choix multiples intégrée), file (fichier généré téléchargeable), tool_start/tool_end (exécution d'outils), credit_update (crédits déduits), suggestions (puces de réponse rapide), bonus_credits (crédits bonus attribués), annotations (citations URL), reasoning (chaîne de pensée), heartbeat (keep-alive toutes les 15 secondes) et done (flux terminé).
Le pattern de streaming backend
Le backend produit les événements SSE depuis un générateur asynchrone. Le pattern de base pour le streaming augmenté par les outils : le LLM diffuse des tokens de texte comme événements content, et quand il décide d'appeler un outil, le serveur émet tool_start, exécute l'outil, puis émet tool_end. C'est du SSE-dans-SSE : nous recevons un flux SSE d'OpenRouter et le ré-émettons comme un flux SSE vers le frontend, en transformant et enrichissant les événements au passage.
Le frontend : streamChat() avec 42+ paramètres
La fonction frontend streamChat() est le hub central pour toute communication SSE. Elle utilise fetch avec getReader() plutôt que l'API EventSource du navigateur, car EventSource ne supporte que les requêtes GET, mais notre endpoint de chat est un POST. La gestion du buffer est critique : les événements SSE peuvent être répartis sur plusieurs appels read(), surtout sur les connexions mobiles lentes.
Un quiz arrive en plein streaming
L'une des fonctionnalités distinctives de Deblo est les quiz intégrés. L'IA peut, à tout moment pendant sa réponse, insérer une question à choix multiples que l'élève doit répondre avant que la conversation continue. Quand le frontend reçoit cet événement, il rend un composant QuizWidget intégré dans la bulle de message de l'assistant.
Visualisation de la progression des outils : ProcessingSteps
Quand l'IA utilise des outils, l'utilisateur voit une chronologie en temps réel de ce qui se passe. C'est le composant ProcessingSteps, qui rend une chronologie verticale avec des indicateurs d'état animés pour chaque invocation d'outil. Chaque outil passe par trois phases : loading (animation spinner), completed (icône statique), ou error (X rouge).
Ce que nous avons appris sur le streaming
- La gestion du buffer n'est pas optionnelle. Les événements SSE répartis sur les paquets TCP sont la norme.
- Les heartbeats empêchent les timeouts des proxies. Sans événements keep-alive périodiques, les proxies inverses fermeront les connexions inactives après 30-60 secondes.
- Le typage des événements vaut la complexité. Avoir 20+ types d'événements distincts semble du sur-engineering, mais chaque type active une fonctionnalité UI spécifique.
- Désactivez le buffering à chaque couche. L'en-tête
X-Accel-Buffering: no,Cache-Control: no-cacheet la classeStreamingResponsede FastAPI gèrent la plupart de cela, mais il faut vérifier de bout en bout.
Le streaming est une de ces fonctionnalités où la complexité d'implémentation est invisible pour l'utilisateur. Quand ça marche, l'IA parle tout simplement. Les caractères apparaissent fluidement, les outils s'exécutent visuellement, les quiz surgissent en ligne. L'utilisateur ne pense jamais au SSE ou au parsing d'événements. Il voit juste un tuteur qui répond instantanément.
Ceci est l'article 7 de 20 dans la série « Comment nous avons construit Deblo.ai ».