Aller au contenu principal

Streaming SSE

Réponses en temps réel

En mode normal, vous attendez que le modèle ait fini de générer sa réponse complète avant de la recevoir. Avec le streaming SSE (Server-Sent Events), les tokens arrivent au fur et à mesure de leur génération. C’est indispensable pour les interfaces conversationnelles où l’utilisateur veut voir la réponse apparaître progressivement.

Streaming SSE dans le terminal

SSE
Server-Sent Events
~50ms
Premier token visible
text/event-stream
Content-Type
stream: true
Un seul paramètre

Activer le streaming

Ajoutez "stream": true à votre requête :

curl https://api.x.ai/v1/responses \
  -H "Authorization: Bearer $XAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "grok-4.20-reasoning",
    "input": "Écris un poème sur la programmation.",
    "stream": true
  }'

La réponse arrive sous forme de flux SSE :

data: {"type": "response.created", "response": {...}}
data: {"type": "response.output_item.added", ...}
data: {"type": "response.content_part.added", ...}
data: {"type": "response.output_text.delta", "delta": "La "}
data: {"type": "response.output_text.delta", "delta": "programmation "}
data: {"type": "response.output_text.delta", "delta": "est "}
...
data: {"type": "response.completed", "response": {...}}

Types d’événements

ÉvénementDescription
response.createdDébut de la génération
response.output_item.addedNouvel élément dans la sortie
response.content_part.addedNouvelle partie de contenu
response.output_text.deltaFragment de texte (le plus fréquent)
response.output_text.doneTexte complet d’un élément
response.completedRéponse finalisée avec usage
response.failedErreur pendant la génération

Streaming en Python

stream = client.responses.create(
    model="grok-4.20-reasoning",
    input="Explique le fonctionnement d'un compilateur.",
    stream=True
)

full_text = ""
for event in stream:
    if event.type == "response.output_text.delta":
        print(event.delta, end="", flush=True)
        full_text += event.delta
    elif event.type == "response.completed":
        usage = event.response.usage
        print(f"\n\nTokens : {usage.total_tokens}")
        print(f"Coût : {usage.cost_in_nano_usd / 1e9:.6f} USD")

Le flush=True force l’affichage immédiat de chaque fragment.

Streaming avec les outils

Quand le modèle utilise des outils en mode streaming, vous recevez des événements supplémentaires :

data: {"type": "response.output_item.added", "item": {"type": "web_search_call"}}
data: {"type": "response.web_search_call.in_progress", ...}
data: {"type": "response.web_search_call.completed", ...}
data: {"type": "response.output_text.delta", "delta": "Selon les résultats..."}

Pour les appels de fonctions client, vous recevez les arguments progressivement :

data: {"type": "response.function_call.arguments.delta", "delta": "{\"city\""}
data: {"type": "response.function_call.arguments.delta", "delta": ": \"Paris\"}"}
data: {"type": "response.function_call.arguments.done", ...}

Intégration frontend

Pour une application web, envoyez le flux SSE au navigateur via un endpoint serveur :

const response = await fetch('/api/chat', {
  method: 'POST',
  body: JSON.stringify({ message: userInput })
});

const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const text = decoder.decode(value);
  outputElement.textContent += text;
}

Streaming et facturation

Le streaming ne change pas la facturation. Le coût est identique qu’il soit activé ou non — seul le mode de livraison diffère. L’objet usage complet est disponible dans l’événement response.completed.

Points clés à retenir

  • stream: true active le streaming SSE — les tokens arrivent au fur et à mesure
  • L’événement response.output_text.delta contient chaque fragment de texte
  • L’événement response.completed contient la réponse finale avec les métadonnées d’usage
  • Le streaming fonctionne avec les outils (web_search, functions)
  • Le coût est identique avec ou sans streaming