Le modèle qui a affiché son premier jeton visible le plus rapidement lors de notre dernier test était également le plus lent à terminer. Le 03/10/2026, nous avons diffusé une invite (prompt) via quatre modèles. claude-sonnet-5-5 a pris la tête sur le premier jeton visible (2 981 ms) et a terminé en dernier sur le temps total (12 384 ms). Cet écart constitue le cœur du débat entre latence et débit des LLM : un chiffre indique combien de temps un utilisateur attend pour voir du texte, l'autre indique à quelle vitesse le travail est accompli. Cet article définit chaque métrique, présente nos mesures internes avec leurs limites, et fournit un outil de test que vous pouvez exécuter avec l'API TokenLab.
Points clés
- Trois chiffres, trois rôles. Le temps jusqu'au premier jeton (TTFT), le temps total et les jetons de sortie par seconde répondent à des questions différentes. Le chat, les agents et le traitement par lots reposent chacun sur une métrique différente.
- Séparez le premier événement du premier jeton visible. Sur
deepseek-v4.1-flash, les deux médianes étaient espacées de 2 334 ms et 3 925 ms. Les deltas de raisonnement peuvent arriver bien avant tout texte visible. - Les jetons de raisonnement consomment votre budget
max_tokens. Avecmax_tokensà 400,deepseek-v4.1-flasha renvoyé environ 0 jeton visible etgemini-3.8-flashenviron 14. À 2000, les deux ont répondu intégralement. - Lisez les nombres de jetons à partir du bloc d'utilisation (usage chunk). Ne les estimez pas à partir des caractères.
- La vitesse du modèle n'augmente pas votre limite de requêtes. Les limites de débit, les limites de jetons et la vitesse du modèle sont des contraintes distinctes.
- Notre échantillon est restreint. Il comprend cinq exécutions par modèle, un client, une invite et une journée. Il montre comment mesurer, pas qui est le plus rapide.
Trois chiffres de vitesse : latence vs débit des LLM en pratique
Divisez la « vitesse » en plusieurs parties, car chaque partie a un responsable différent : le réseau, le modèle et votre propre file d'attente.
envoyer la requête
-> premier événement de flux (n'importe quel bloc SSE ; peut être un delta de raisonnement)
-> premier jeton de contenu visible (premier delta.content non vide)
-> dernier jeton + bloc d'utilisation final
Le temps jusqu'au premier jeton (TTFT) est le temps écoulé entre l'envoi de la requête et l'arrivée du premier jeton. Nous enregistrons deux versions. Le premier événement de flux est le premier bloc SSE de toute nature. Le premier jeton de contenu visible est le premier bloc dont choices[0].delta.content n'est pas vide. Pour les modèles qui raisonnent avant de répondre, le premier événement peut être un delta de raisonnement (delta.reasoning_content) qui arrive bien avant le texte visible. Un outil qui ne surveille que delta.content mesure le temps jusqu'au premier jeton visible, pas le temps jusqu'au premier octet. Les utilisateurs ressentent le jeton visible.
Le temps total s'écoule de l'envoi de la requête à la fin du flux. Il inclut le raisonnement, le temps réseau et tout délai de nouvelle tentative que vous ajoutez.
Les jetons de sortie par seconde correspondent aux jetons de sortie divisés par le temps total. Prenez le nombre de jetons depuis usage.completion_tokens, qui inclut les jetons de raisonnement. Nous divisons par le temps total, et non par la fenêtre visible. Certains modèles de notre échantillon ont fourni du texte visible en quelques gros blocs, donc un taux basé sur la fenêtre serait trompeur.
| Charge de travail | Surveiller en priorité | Ensuite | Pourquoi |
|---|---|---|---|
| Chat | Premier jeton visible | Temps total | L'utilisateur regarde une zone vide jusqu'à ce que le texte apparaisse. |
| Agents | Temps total | Premier jeton visible | Chaque étape attend généralement la précédente, donc les totaux par étape s'additionnent. |
| Extraction par lots ou résumés | Jetons de sortie par seconde, et coût par tâche | Marge de limite de requêtes | Personne ne surveille le premier jeton, et la limite de requêtes du compte plafonne la vitesse de soumission. |
Les appels sans streaming, comme l'extraction JSON structurée, n'exposent que le temps total. Utilisez le streaming lors des tests si vous souhaitez obtenir la répartition.
Ce que nous avons mesuré le 03/10/2026
Méthode. Il s'agit d'une mesure interne TokenLab, observée le 03/10/2026, via POST https://api.tokenlab.sh/v1/chat/completions (source). Chaque requête utilisait stream=true et stream_options.include_usage=true. Nous avons effectué 5 exécutions séquentielles par modèle depuis un client unique en Asie de l'Est, en utilisant fetch de Node 24. L'invite était : "Expliquez comment le keep-alive HTTP réduit la latence pour les clients API. Écrivez environ 200 mots." Chaque modèle utilisait les paramètres de raisonnement par défaut. Les temps sont mesurés côté client, et toutes les exécutions ont réussi (5/5) pour chaque ligne ci-dessous.
Modèle (max_tokens 2000) |
Médiane 1er événement flux | Médiane 1er jeton visible | Médiane temps total | Médiane jetons complétion (raisonnement) | Jetons/s estimés |
|---|---|---|---|---|---|
deepseek-v4.1-flash |
2 334 ms | 3 925 ms | 5 204 ms | 453 (225) | 87 |
gemini-3.8-flash |
6 892 ms | 6 892 ms | 8 626 ms | 826 (528) | 96 |
claude-sonnet-5-5 |
2 981 ms | 2 981 ms | 12 384 ms | 418 (non rapporté) | 34 |
gpt-5.6-luna |
3 262 ms | 3 262 ms | 8 183 ms | 313 (42) | 38 |
La colonne jetons/s est notre propre estimation : médiane des jetons de complétion divisée par la médiane des secondes totales, par exemple 453 ÷ 5,204 ≈ 87. Il s'agit d'un ratio de médianes, et non d'une médiane des taux par exécution.
Ce que montrent les chiffres, et rien de plus :
- Le classement par premier jeton visible (
claude-sonnet-5-5,gpt-5.6-luna,deepseek-v4.1-flash,gemini-3.8-flash) diffère du classement par temps total (deepseek-v4.1-flash,gpt-5.6-luna,gemini-3.8-flash,claude-sonnet-5-5). Une métrique ne peut pas remplacer l'autre. deepseek-v4.1-flashprésentait un écart de 1 591 ms entre le premier événement et le premier jeton visible. Sa sortie visible médiane était d'environ 228 jetons, livrés en 87 événements sur 1 304 ms.- Pour
gemini-3.8-flash, le premier événement et le premier jeton visible partagent une médiane de 6 892 ms. Son texte visible est arrivé en une médiane de 11 événements sur 1 734 ms, le flux était donc par blocs plutôt que jeton par jeton. claude-sonnet-5-5a envoyé une médiane de 371 événements sur 9 186 ms, etgpt-5.6-lunaa envoyé 265 événements sur 4 901 ms.
Le coût accompagne la vitesse. Les prix ci-dessous proviennent de l'API modèle TokenLab, observés le 03/10/2026, avec des tarifs mis à jour le 02/10/2026T16:53:30.068Z. La dernière colonne est une estimation : médiane des jetons de complétion multipliée par le taux de sortie, côté sortie uniquement. Vérifiez les enregistrements d'utilisation pour les frais réels.
| Modèle | Entrée par 1M | Sortie par 1M | Max jetons sortie | Estimation côté sortie, exécution médiane | Source |
|---|---|---|---|---|---|
deepseek-v4.1-flash |
0,15 $ creux, 0,30 $ pic | 0,60 $ creux, 1,20 $ pic | 384 000 | 453 × 0,60 $ / 1M ≈ 0,00027 $ creux, ≈ 0,00054 $ pic | API modèle |
gemini-3.8-flash |
0,375 $ | 1,875 $ | 65 536 | 826 × 1,875 $ / 1M ≈ 0,00155 $ | API modèle |
claude-sonnet-5-5 |
0,60 $ | 3 $ | 128 000 | 418 × 3 $ / 1M ≈ 0,00125 $ | API modèle |
gpt-5.6-luna |
0,06 $ | 0,36 $ | 128 000 | 313 × 0,36 $ / 1M ≈ 0,00011 $ | API modèle |
Pour gpt-5.6-luna, ces tarifs s'appliquent lorsque l'entrée est au maximum de 272K jetons. Au-delà, la requête complète utilise des tarifs d'entrée 2x et de sortie 1,5x.
Limites de cet échantillon. Cinq exécutions séquentielles depuis un client en Asie de l'Est constituent un échantillon restreint. L'invite était une demande d'essai courte, donc les résultats varieront selon la région, l'heure, l'invite et la longueur de sortie. Nous n'avons pas testé la concurrence, donc rien de ceci ne prédit ce qui se passe sous charge. Traitez le tableau comme un modèle pour votre propre test, exécuté depuis la région où se trouvent vos déploiements de production. Si vous souhaitez une vue plus large des modèles, le classement des API LLM TokenLab pour les développeurs est un point de départ. Vérifiez sa méthode et sa date avant de vous fier à un chiffre de vitesse. Ne remplacez pas non plus les modèles silencieusement : le guide de fiabilité, observé le 03/10/2026, note qu'un remplacement peut modifier la qualité, le prix, la longueur du contexte et les outils.
Jetons de raisonnement et max_tokens : pourquoi 400 n'a presque rien renvoyé
Nous avons également exécuté la même invite avec max_tokens réglé sur 400. Même méthode, mêmes cinq exécutions, même date (source).
Modèle (max_tokens 400) |
Médiane jetons complétion | Médiane jetons raisonnement | Sortie visible (approx.) | Médiane 1er jeton visible | Médiane temps total |
|---|---|---|---|---|---|
deepseek-v4.1-flash |
400 | 400 | 0 jetons | 3 795 ms | 4 693 ms |
gemini-3.8-flash |
396 | 382 | 14 jetons | 4 199 ms | 4 240 ms |
claude-sonnet-5-5 |
400 | non rapporté | 400 jetons | 3 088 ms | 11 078 ms |
gpt-5.6-luna |
317 | 42 | 275 jetons | 3 040 ms | 8 083 ms |
Les médianes sont calculées par colonne, donc les colonnes d'une ligne ne décrivent pas nécessairement une seule exécution. C'est pourquoi deepseek-v4.1-flash affiche un temps de premier jeton visible à côté d'une médiane de zéro événement visible.
Le constat est clair. deepseek-v4.1-flash et gemini-3.8-flash ont dépensé la quasi-totalité du budget de 400 jetons en raisonnement et n'ont renvoyé presque aucun texte visible. Augmenter max_tokens à 2000 a produit des réponses complètes. Les jetons de raisonnement comptent dans usage.completion_tokens. Ils sont rapportés séparément dans usage.completion_tokens_details.reasoning_tokens.
Lorsque nous avons vu le premier résultat de 400 jetons, l'échec ressemblait à une réponse vide, pas à un problème de budget. Trois vérifications le rendent visible :
- Lisez le bloc d'utilisation final, activé par
stream_options={"include_usage": True}. Sireasoning_tokensest proche decompletion_tokenset que le texte est vide, le budget est allé au raisonnement. - Vérifiez
finish_reason. Le guide de streaming (observé le 03/10/2026) listelengthcomme valeur lorsqu'une limite de jetons est atteinte. - Comparez avec la sortie maximale du modèle. Par exemple, l'API modèle liste 384 000 pour
deepseek-v4.1-flashet 65 536 pourgemini-3.8-flash, donc 400 était une minuscule fraction de ce que les modèles autorisent.
La référence Create Chat Completion (observée le 03/10/2026) liste également max_completion_tokens et reasoning_effort. Elle indique que les valeurs prises en charge dépendent du modèle, lisez donc la page du modèle avant de définir l'un ou l'autre. Nous ne les avons pas testés, et nous avons exécuté chaque ligne avec le raisonnement par défaut. Dimensionnez le plafond selon votre propre invite : dans notre exécution, une réponse de 200 mots a produit environ 228 à 418 jetons visibles, et jusqu'à 528 jetons de raisonnement en plus.
Un outil de mesure pour l'URL de base TokenLab
Ce script utilise l'URL de base TokenLab, lit les nombres de jetons depuis le bloc d'utilisation, et enregistre le premier événement de flux séparément du premier jeton de contenu visible. Il conserve également les en-têtes de réponse pour un débogage ultérieur. Il suit les paramètres client de la documentation (timeout=30.0, max_retries=0) afin que le SDK n'ajoute pas de nouvelles tentatives cachées à vos mesures. L'ID de modèle est celui que nous avons mesuré ; remplacez-le par tout ID dont les formats de requête acceptés incluent openai_chat_completions.
import json
import os
import statistics
import time
from openai import OpenAI
client = OpenAI(
api_key=os.environ["TOKENLAB_API_KEY"],
base_url="https://api.tokenlab.sh/v1",
timeout=30.0,
max_retries=0,
)
PROMPT = "Expliquez comment le keep-alive HTTP réduit la latence pour les clients API. Écrivez environ 200 mots."
def measure(model: str, max_tokens: int = 2000) -> dict:
start = time.perf_counter()
raw = client.chat.completions.with_raw_response.create(
model=model,
messages=[{"role": "user", "content": PROMPT}],
max_tokens=max_tokens,
stream=True,
stream_options={"include_usage": True},
)
headers = raw.headers
first_event = first_visible = None
visible_events = 0
usage = None
finish_reason = None
for chunk in raw.parse():
now = time.perf_counter() - start
if first_event is None:
first_event = now
if chunk.usage is not None:
usage = chunk.usage
if not chunk.choices:
continue
choice = chunk.choices[0]
if choice.delta.content:
visible_events += 1
if first_visible is None:
first_visible = now
if choice.finish_reason:
finish_reason = choice.finish_reason
total = time.perf_counter() - start
details = getattr(usage, "completion_tokens_details", None)
completion = usage.completion_tokens if usage else None
return {
"model": model,
"request_id": headers.get("x-request-id"),
"routing_time_ms": headers.get("x-routing-time-ms"),
"first_event_s": first_event,
"first_visible_s": first_visible,
"total_s": total,
"completion_tokens": completion,
"reasoning_tokens": getattr(details, "reasoning_tokens", None),
"visible_events": visible_events,
"finish_reason": finish_reason,
"tokens_per_s": completion / total if completion else None,
}
if __name__ == "__main__":
runs = [measure("gemini-3.8-flash") for _ in range(5)]
print(json.dumps(runs[0], indent=2))
print("médiane total_s:", statistics.median(r["total_s"] for r in runs))
Quelques notes sur la lecture de la sortie :
first_event_sse déclenche sur n'importe quel bloc, y compris un bloc de rôle seul ou de raisonnement.first_visible_sse déclenche uniquement sur undelta.contentnon vide. Si les deux diffèrent de plusieurs secondes, le modèle raisonne avant de répondre.- Les nombres de jetons proviennent du bloc d'utilisation final. Ce bloc a une liste
choicesvide, c'est pourquoi la boucle vérifiechunk.usageavant de l'ignorer. - Exécutez-le cinq fois ou plus, enregistrez la région, et rapportez les médianes ainsi que la taille de l'échantillon.
- Pour les modèles qui listent
openai_responses, le guide de streaming montre des réponses diffusées avec des événementsresponse.output_text.deltaetresponse.completed. La même séparation s'applique : chronométrez le premier événement, puis le premier delta de texte. - Traitez un flux qui se ferme avant
response.completedou une raison de finstopcomme incomplet, et non comme un succès rapide.
En-têtes et identifiants à journaliser pour le débogage de latence
Une requête lente est difficile à déboguer si vous n'avez conservé qu'une durée. La référence API et le guide de dépannage, observés le 03/10/2026, nomment les identifiants qui valent la peine d'être conservés.
| Identifiant | Où il apparaît | Utilisation |
|---|---|---|
X-Request-ID |
En-tête de réponse, si disponible | Support et débogage pour une requête |
request_id |
Corps d'erreur, logs tableau de bord, enregistrements d'utilisation | Support au niveau de la requête et réconciliation |
X-Routing-Time-MS |
En-tête de réponse, si disponible | Temps passé à sélectionner la livraison, avant génération |
X-Task-ID, task_id, poll_url |
Réponses de création asynchrone et de statut | Tâches image, vidéo, musique et 3D |
X-Billing-Transaction-ID |
En-tête après facturation finale, si disponible | Réconciliation des coûts |
| Votre propre ID de travail ou utilisateur | Votre application | Trouver la requête derrière une plainte utilisateur |
Pour chaque appel, journalisez le point de terminaison, la méthode, le modèle, le code de statut, l'horodatage et la latence. Ajoutez les noms de champs que vous avez envoyés (pas l'invite), votre nombre de tentatives, et si une nouvelle tentative a créé une nouvelle tâche ou en a repris une. Notre outil ajoute les temps de répartition et les nombres de jetons du bloc d'utilisation.
Deux mises en garde. Les réponses en streaming peuvent se stabiliser après la fin du flux, donc un en-tête de facturation peut être absent même lorsque l'utilisation est enregistrée plus tard. Pour les montants facturés, utilisez les enregistrements d'utilisation de l'API de gestion plutôt que les nombres de jetons de réponse seuls. Journalisez également la valeur X-TokenLab-Delivery-Policy si vous en définissez une. La référence indique qu'elle accepte auto, verified ou official, qu'une valeur invalide renvoie 400, et qu'une option indisponible renvoie 503 avec code: delivery_tier_unavailable et retryable: true. Ne journalisez jamais Authorization, les clés API, les URL signées, les invites complètes ou les données personnelles.
Les détails des requêtes de la console sont conservés pendant 30 jours à partir de la capture, copiez donc les ID dont vous avez besoin dans vos propres logs. Dans notre pipeline, nous alignons ces ID avec la vue des requêtes ; le post sur la console de requêtes TokenLab couvre cette vue.
Limites de débit, nouvelles tentatives et latence vs débit des LLM
La vitesse par flux et le débit du compte sont des plafonds différents. Le guide des limites de débit, observé le 03/10/2026, liste les valeurs de niveau standard ci-dessous. Il note qu'elles peuvent changer avec la configuration active et sont appliquées par clé API.
| Niveau | Requêtes par minute |
|---|---|
| Utilisateur | 1 000 |
| Partenaire | 10 000 |
| VIP | 10 000 |
Lorsque vous dépassez la limite, l'API renvoie 429 rate_limit_exceeded avec un en-tête Retry-After. Le corps d'exemple du guide contient "retryable": true et "retry_after": 8. Le guide indique de se fier aux valeurs X-RateLimit-Limit et Retry-After renvoyées plutôt qu'à tout tableau copié. Il indique également qu'un modèle plus rapide n'augmente pas la limite de requêtes de votre compte.
Voici l'arithmétique pour le travail par lots. Il s'agit de notre estimation à partir des médianes ci-dessus, pas d'un test de charge. Les flux simultanés correspondent approximativement aux requêtes par seconde multipliées par les secondes par requête. À 1 000 requêtes par minute (environ 16,7 par seconde) :
- Avec
deepseek-v4.1-flashà une médiane totale de 5,204 s, environ 87 flux s'exécutent en même temps. - Avec
claude-sonnet-5-5à une médiane de 12,384 s, environ 206 flux s'exécutent en même temps.
Un flux plus lent signifie plus de concurrence pour atteindre le même taux de requêtes. Atteindre la limite ajoute alors du temps d'attente en plus du temps de génération. Les limites de jetons ne sont pas couvertes dans les pages que nous avons utilisées, vérifiez donc votre compte et la page du modèle pour celles-ci.
Comment réessayer sans ruiner vos chiffres :
- Respectez
Retry-Afterlorsqu'il est présent. Sinon, utilisez un backoff exponentiel avec une gigue aléatoire et un plafond strict de tentatives. - Réglez le SDK sur
max_retries=0et réessayez à un seul endroit. Sinon, deux couches réessayeront le même appel et vos mesures seront comptées en double. - Ne réessayez jamais les erreurs de validation, d'authentification, de solde ou de permission. Réessayez les réponses transitoires
5xxavec un court backoff. - Une fois que le premier événement arrive, un flux interrompu est incomplet et n'est pas redémarré automatiquement. Répéter la requête peut produire une sortie différente et une autre facturation.
- Journalisez le nombre de tentatives et le temps d'attente séparément du temps du modèle, afin qu'une exécution limitée ne ressemble pas à un modèle lent.
Voici le modèle de nouvelle tentative borné du guide :
import random
import time
from openai import RateLimitError
def chat_with_rate_limit_retry(client, model, messages, attempts=4):
for attempt in range(attempts):
try:
return client.with_options(max_retries=0).chat.completions.create(
model=model,
messages=messages,
)
except RateLimitError as exc:
if attempt == attempts - 1:
raise
header = exc.response.headers.get("Retry-After")
wait = float(header) if header else min(30, 2 ** attempt + random.random())
time.sleep(wait)
Limitez également la concurrence, pas seulement les requêtes moyennes par minute, et mettez en file d'attente les rafales. Suivez les réponses 429 répétées par clé API afin qu'un client ne puisse pas évincer le reste de votre application.
FAQ
Un nombre de jetons par seconde plus élevé est-il toujours une expérience utilisateur plus rapide ?
Non. Dans notre échantillon du 03/10/2026, claude-sonnet-5-5 a montré le premier jeton visible le plus tôt (2 981 ms) mais le temps total le plus long (12 384 ms). deepseek-v4.1-flash a commencé le texte visible plus tard (3 925 ms) et a terminé en premier (5 204 ms). Ce qui semble plus rapide dépend du fait que l'utilisateur regarde le flux ou attend la réponse complète. Cinq exécutions depuis un client ne peuvent pas trancher cela pour votre charge de travail.
Pourquoi ma réponse en streaming est-elle revenue avec presque pas de texte ?
Vous avez probablement dépensé le budget en raisonnement. À max_tokens 400, deepseek-v4.1-flash a utilisé 400 jetons de raisonnement et a renvoyé environ 0 jeton visible. Vérifiez usage.completion_tokens_details.reasoning_tokens dans le bloc d'utilisation final et le finish_reason. Augmentez ensuite le plafond ; à 2000, les deux modèles de raisonnement de notre test ont répondu intégralement.
Un modèle plus rapide augmente-t-il ma limite de débit ?
Non. Le guide des limites de débit indique que la vitesse du modèle, les limites de jetons et les limites de débit du compte sont des contraintes séparées. Un flux plus rapide se termine plus tôt et libère un emplacement de concurrence, mais votre limite de requêtes par clé reste la même. Demandez au support une limite différente si vous en avez besoin.
Quels ID dois-je envoyer au support lorsqu'un flux est lent ?
Envoyez le request_id (ou X-Request-ID), le point de terminaison, la méthode, le modèle, l'horodatage et le code de statut. Ajoutez task_id et poll_url pour le travail asynchrone et billing_transaction_id lorsqu'il est présent. Incluez vos temps de répartition et le corps d'erreur sûr, et rédigez d'abord les clés, les invites et les médias privés.
Exécutez l'outil ci-dessus sur votre propre invite, puis comparez ce que vous mesurez avec les classements des modèles TokenLab.
Sources
Prix observé le 2026-10-03
- TokenLab Docs: StreamingObservé le 2026-10-03
- TokenLab Docs: Rate limitsObservé le 2026-10-03
- TokenLab Docs: Logs and troubleshootingObservé le 2026-10-03
- TokenLab Docs: Build a reliable TokenLab integrationObservé le 2026-10-03
- TokenLab Docs: API ReferenceObservé le 2026-10-03
- TokenLab Docs: Create Chat CompletionObservé le 2026-10-03
- TokenLab live model API: deepseek-v4.1-flashObservé le 2026-10-03
- TokenLab live model API: gemini-3.8-flashObservé le 2026-10-03
