Aide

Besoin d’aide ?

Posez votre question sur le Discord de MiniLab, dans le salon de cette page :

#questions-generation

Ouvrir le salon ↗

Pas encore membre ? Rejoindre le Discord, puis revenez sur ce bouton.

Ma progression

Sauvegarder ma progression

Chargement…

Votre progression est enregistrée dans ce navigateur, pour cette adresse seulement. Gardez ce code : il la restaure dans un autre navigateur, sur un autre ordinateur, ou si les données du site ont été effacées.

MINILAB-0-1C
Mentions légales
Affichage

Personnaliser l’affichage

Ce réglage s’applique à la vue côte à côte.
LEÇON 16LE VOYAGE D’UNE REQUÊTE

Du modèle à l’écran.

Dans les leçons 14 et 15, la requête a quitté le champ de saisie, traversé le serveur de l’application et le chat template, puis elle est entrée dans le modèle sous forme de tokens. Le modèle a fait son travail : prefill, puis decode token après token, avec son cache KV (leçon 15). Il reste le chemin du retour. Comment ces identifiants redeviennent-ils du texte ? Et pourquoi la réponse s’affiche-t-elle mot après mot, au lieu d’arriver d’un bloc ? Cette dernière leçon répond à ces questions, puis rassemble tout le parcours en une seule vue.

01

Des identifiants au texte : la détokenisation

Le modèle ne produit que des identifiants. Pour les afficher, on fait le chemin inverse de la leçon 02 : chaque identifiant est retrouvé dans le vocabulaire, et les morceaux de texte sont mis bout à bout. C’est la détokenisation (decoding, ou detokenization). Comme l’espace est collée au mot qui suit (leçon 13), recoller les tokens suffit à retrouver les espaces.

Une subtilité guette les tokenizers qui travaillent sur des octets, comme celui de GPT-2. Un « é » s’écrit avec 2 octets en UTF-8, un emoji avec 4. Il arrive qu’un caractère soit coupé entre deux tokens. Pendant l’affichage au fil de l’eau, il faut alors attendre l’octet suivant avant de montrer le caractère, sinon l’utilisateur verrait un symbole cassé. Notre tokenizer par caractère n’a pas ce problème.

02

Attendre la fin, ou envoyer au fil de l’eau

Première option : le serveur attend que le modèle ait fini, puis renvoie toute la réponse d’un coup. Simple, mais l’utilisateur fixe un écran vide pendant toute la génération. Dans le laboratoire, avec le prompt « Phileas Fogg » et 60 tokens générés, il faut attendre 3,87 s.

Seconde option : envoyer chaque token dès qu’il est généré. C’est le streaming. La génération ne va pas plus vite, mais le premier mot apparaît après 0,33 s seulement. La réponse semble instantanée, et l’utilisateur commence à lire pendant que le modèle écrit encore. C’est pourquoi tous les assistants conversationnels utilisent le streaming, avec le paramètre stream: true de la leçon 14.

03

Les Server-Sent Events

Pour streamer, le serveur garde la réponse HTTP ouverte et y écrit au fur et à mesure. Le format le plus utilisé s’appelle les Server-Sent Events (SSE) : la réponse a le type text/event-stream, et chaque événement est une ligne data:, suivie d’une ligne vide.

Le début et la fin d’un flux, dans le laboratoire
data: {"type": "start", "prompt_tokens": 13}

data: {"type": "delta", "index": 0, "id": 97, "text": "é"}

data: {"type": "delta", "index": 1, "id": 68, "text": "t"}

…

data: {"type": "done", "finish_reason": "length", "usage": {…}}

data: [DONE]

L’API Chat Completions d’OpenAI fonctionne exactement ainsi : chaque morceau (chunk) contient un petit bout de texte, le delta ; le dernier indique le finish_reason de la leçon 09 ; et le flux se termine par data: [DONE]. L’API Responses envoie des événements typés, comme response.output_text.delta. Les SSE ne vont que dans un sens, du serveur vers le navigateur. Pour un échange dans les deux sens en temps réel, comme une conversation vocale, on utilise plutôt les WebSockets.

04

Côté navigateur : lire le flux

Dans la page, le code lit la réponse morceau par morceau, au lieu d’attendre qu’elle soit complète. À chaque événement reçu, il ajoute le nouveau texte à l’écran.

Lire un flux SSE dans le navigateur
const response = await fetch(url, { method: "POST", body, signal })
const reader = response.body.getReader()
const decoder = new TextDecoder()
while (true) {
  const { value, done } = await reader.read()
  if (done) break
  // découper sur les lignes vides, lire chaque « data: »,
  // puis ajouter le texte du delta à l’écran
}

Deux détails font la différence pour l’utilisateur. D’abord, le texte arrive souvent en Markdown (titres, listes, code), qu’il faut afficher proprement alors même qu’il est incomplet. C’est délicat : au milieu du flux, les balises comme ** pour le gras ou ``` pour un bloc de code sont ouvertes, mais pas encore refermées. L’interface doit donc tolérer, à chaque token, un Markdown provisoirement incomplet, sans faire clignoter la mise en page.

Ensuite, un bouton « Arrêter » annule la requête avec un AbortController, qui coupe la connexion HTTP côté navigateur. Le serveur de l’application doit alors détecter cette déconnexion pour interrompre à son tour la boucle de génération, ou fermer sa propre connexion vers l’API du modèle. Arrêter tôt économise du calcul et des tokens, mais pas tous : les tokens du prompt, déjà traités pendant le prefill, et les tokens émis avant l’arrêt restent comptabilisés.

05

La vitesse vue par l’utilisateur

On retrouve les deux mesures de la leçon 15. Le délai du premier token (TTFT) additionne le trajet réseau, l’attente dans la file du serveur et le prefill. Le débit, en tokens par seconde, dépend du decode. Notre laboratoire imite un vrai modèle avec des délais artificiels : 200 ms plus 10 ms par token de prompt pour le prefill, soit 330 ms pour « Phileas Fogg », puis 60 ms par token généré, soit environ 16,7 tokens par seconde.

À la fin du flux, l’API envoie la raison de l’arrêt et, si on le demande, l’usage : chez OpenAI, l’option stream_options avec include_usage ajoute un dernier morceau avec les tokens consommés, ceux que vous paierez.

06

Le grand récapitulatif

Vous avez maintenant suivi tout le trajet d’un prompt. Le voici d’un seul coup d’œil, avec la leçon qui explique chaque étape :

Du clic à l’écran
1.  le navigateur envoie le message au serveur              leçon 14
2.  messages, rôles, chat template, budget de tokens         leçon 14
3.  tokenisation en sous-mots, puis identifiants            leçons 13, 01, 02
4.  embeddings et vecteurs de position                      leçons 03, 05
5.  attention et blocs Transformer, couche après couche     leçons 06, 07
6.  LayerNorm finale, logits, probabilités                  leçon 08
7.  choix du token : température, top-k, top-p              leçon 09
8.  boucle autorégressive, prefill, decode, cache KV        leçons 04, 09, 15
9.  arrêt : token de fin, séquence d’arrêt ou max_tokens    leçon 09
10. détokenisation et streaming jusqu’à l’écran             leçon 16

des poids appris par pré-entraînement, SFT et RLHF          leçons 10, 11, 12

Le laboratoire de cette leçon refait ce trajet en direct pour votre propre texte, avec un chiffre clé calculé à chaque étape.

07

Observez par vous-même

Dans le laboratoire, tapez Phileas Fogg (avec l’espace final) et cliquez sur « Envoyer ». Regardez le texte apparaître token après token, le flux SSE brut défiler et les compteurs de vitesse se remplir. Désactivez ensuite le streaming et renvoyez la même requête : l’écran reste vide pendant près de 4 secondes, puis toute la réponse arrive d’un bloc, dans un seul objet JSON que la carte 04 résume.

Pendant un envoi en streaming, essayez le bouton « Arrêter » : le flux s’interrompt aussitôt. Enfin, descendez jusqu’à la carte du trajet complet, et cliquez sur une étape pour revoir sa leçon.

08

Et maintenant ?

Notre laboratoire ne fait tourner qu’un modèle par comptage, avec des délais imités ; les vrais modèles affichent des débits bien différents selon leur taille et le matériel. Mais le format du flux, la détokenisation et la mesure de la vitesse sont exactement ceux d’une vraie application.

Vous connaissez désormais tout le trajet, du clic à l’écran, et les notions qu’un professionnel manipule chaque jour. La théorie est terminée. La prochaine partie du parcours vous fait passer à la pratique : préparer votre environnement, puis construire, étape par étape, votre propre projet MiniLab.

À retenir

La détokenisation retrouve le texte de chaque identifiant et les met bout à bout ; avec un BPE au niveau des octets, il faut attendre les octets manquants d’un caractère avant de l’afficher. Le streaming envoie chaque token dès sa génération : la durée totale ne change pas, mais le délai du premier token (TTFT = réseau + file d’attente + prefill) devient court.

Format SSE : réponse HTTP text/event-stream, une ligne data: … par événement suivie d’une ligne vide ; chez OpenAI, des chunks avec un delta, un finish_reason final, l’usage en option (include_usage) et data: [DONE]. Côté navigateur : lecture du flux avec un reader, affichage progressif du Markdown, annulation avec AbortController.

Streaming API responses · OpenAI ↗
Server-sent events · MDN ↗

VÉRIFIER SES CONNAISSANCES

Valider cette étape

Répondez aux trois questions pour débloquer la suite. Vous pouvez réessayer autant de fois que nécessaire.

Chargement de la progression…

Mise en ligne le

ESPACE DE PRATIQUE

Le laboratoire

Recevez la réponse, token après token.

● EN DIRECT
01

Votre texte

MODIFIABLE
02

Envoyer la requête

Le laboratoire génère jusqu’à 60 tokens avec les réglages de la leçon 09 (modèle par comptage, température 0,8, top-p 0,9, seed 42), en imitant les délais d’un vrai modèle.

03

Le trajet complet de votre prompt

Le même texte, suivi à travers tout le parcours : un chiffre clé par étape, calculé par le moteur Python. Cliquez sur une étape pour revoir sa leçon.

Calcul du trajet…

À retenir

Le streaming ne rend pas la génération plus rapide : il montre chaque token dès qu’il existe. Le délai du premier token devient court, et l’utilisateur lit pendant que le modèle écrit.

Le flux de ce laboratoire est un vrai flux SSE, au même format que celui d’OpenAI, mais les délais sont imités : 200 ms plus 10 ms par token de prompt, puis 60 ms par token.

04

Pour aller plus loin

Le streaming est la dernière brique d’une application de chat. Ces ressources officielles montrent comment le mettre en place.