Aller au contenu principal

Le streaming des réponses

Mis à jour le 30 juillet 2026

Une réponse de Claude peut prendre 10 à 30 secondes à générer — davantage encore sur les longues sorties. Servie d’un bloc, cette attente est mortelle pour l’expérience utilisateur : trente secondes face à un indicateur de chargement, c’est un utilisateur qui recharge la page. Le streaming résout le problème en livrant le texte au fur et à mesure de sa génération, comme le font toutes les interfaces de chat que vous connaissez. Et l’enjeu n’est pas que cosmétique : sur les très longues générations, une connexion qui reste silencieuse pendant toute la durée du calcul finit par dépasser les timeouts réseau — le flux continu d’événements maintient la connexion vivante.

Types d’événements

Côté protocole, une réponse streamée n’est plus un objet unique mais une séquence d’événements typés, envoyés dans un ordre précis :

  • MessageStart : début d’un nouveau message
  • ContentBlockStart : début d’un bloc de contenu
  • ContentBlockDelta : fragments du texte généré
  • ContentBlockStop : fin du bloc de contenu
  • MessageDelta : fin du message courant
  • MessageStop : plus rien à envoyer

La structure est emboîtée : un message contient un ou plusieurs blocs de contenu, chaque bloc s’ouvre, émet ses fragments (les deltas), puis se ferme. L’essentiel du volume est fait de ContentBlockDelta — c’est là que le texte arrive, quelques mots à la fois. Les événements d’encadrement, eux, transportent les métadonnées : identifiant du message au départ, décompte de tokens et raison d’arrêt à l’arrivée.

Implémentation basique

Le paramètre stream=True suffit à basculer en mode flux :

stream = client.messages.create(
    model=model,
    max_tokens=1000,
    messages=messages,
    stream=True
)

for event in stream:
    print(event)

Au lieu d’attendre puis de retourner un message complet, create retourne immédiatement un itérateur. La boucle affiche ici les événements bruts — exécutez-la une fois, c’est le meilleur moyen de voir le protocole défiler en vrai et de comprendre ce que le SDK manipule pour vous. En pratique, on n’écrit presque jamais ce code en production : filtrer les deltas, accumuler le texte, gérer les types d’événements, tout cela est du travail répétitif que le SDK sait faire lui-même.

Interface simplifiée

C’est le rôle de la seconde interface, client.messages.stream :

with client.messages.stream(
    model=model,
    max_tokens=1000,
    messages=messages
) as stream:
    for text in stream.text_stream:
        print(text, end="")

Deux détails font le confort de cette version. Le gestionnaire de contexte (with) garantit que la connexion est proprement fermée, même si votre code lève une exception en cours de flux. Et text_stream est un itérateur qui a déjà fait le tri : il ne produit que les fragments de texte, débarrassés de tout l’échafaudage d’événements. Le end="" évite que print insère un saut de ligne entre chaque fragment — le texte s’affiche d’un seul tenant, mot après mot, exactement comme dans une interface de chat.

Récupérer le message final

Streamer ne dispense pas de conserver la réponse : il faut bien ajouter le message assistant à l’historique de conversation, ou l’enregistrer en base. Plutôt que d’accumuler les fragments à la main, le SDK reconstitue l’objet complet :

with client.messages.stream(
    model=model,
    max_tokens=1000,
    messages=messages
) as stream:
    for text in stream.text_stream:
        pass  # Afficher côté client en production

    final_message = stream.get_final_message()

Une fois le flux épuisé, get_final_message() retourne un objet Message identique à celui qu’aurait renvoyé un appel sans streaming — même contenu, mêmes métadonnées, même décompte de tokens. Vous avez donc le meilleur des deux mondes : l’affichage progressif pendant la génération, et l’objet complet pour la persistance après.

Dernière pièce du puzzle en production : le streaming décrit ici relie votre serveur à l’API. Pour que l’utilisateur final en profite dans son navigateur, votre serveur doit relayer les fragments au fur et à mesure, typiquement via WebSockets ou Server-Sent Events — le même principe de flux, appliqué un cran plus loin dans la chaîne.

Points clés à retenir

  • Le streaming livre le texte pendant la génération : latence perçue quasi nulle, connexion maintenue vivante
  • Une réponse streamée est une séquence d’événements typés, dont l’essentiel sont des ContentBlockDelta
  • stream=True donne les événements bruts ; client.messages.stream + text_stream donne directement le texte
  • get_final_message() reconstitue l’objet Message complet pour l’historique et la persistance
  • En production, relayez les fragments jusqu’au navigateur via WebSockets ou Server-Sent Events