O modelo que exibiu seu primeiro token visível mais rapidamente em nosso teste mais recente também foi o mais lento para finalizar. Em 03/10/2026, transmitimos um prompt através de quatro modelos. O claude-sonnet-5-5 liderou no primeiro token visível (2.981 ms) e ficou para trás no tempo total (12.384 ms). Essa lacuna é o cerne da latência vs. throughput de LLMs: um número indica quanto tempo um usuário espera para ver o texto, outro indica quão rápido o trabalho é concluído. Este artigo define cada métrica, mostra nossas pequenas medições de primeira mão com suas limitações e fornece um mecanismo que você pode executar contra a API do TokenLab.
Principais conclusões
- Três números, três funções. O tempo para o primeiro token, o tempo total e os tokens de saída por segundo respondem a perguntas diferentes. Chat, agentes e trabalho em lote dependem de métricas diferentes.
- Separe o primeiro evento do primeiro token visível. No
deepseek-v4.1-flash, as duas medianas tiveram uma diferença de 2.334 ms e 3.925 ms. Deltas de raciocínio podem chegar bem antes de qualquer texto visível. - Tokens de raciocínio consomem seu orçamento de
max_tokens. Commax_tokens400, odeepseek-v4.1-flashretornou cerca de 0 tokens visíveis e ogemini-3.8-flashcerca de 14. Em 2000, ambos responderam na íntegra. - Leia a contagem de tokens a partir do chunk de uso (usage chunk). Não os estime a partir de caracteres.
- A velocidade do modelo não aumenta seu limite de requisições. Limites de taxa, limites de tokens e velocidade do modelo são restrições separadas.
- Nossa amostra é pequena. Possui cinco execuções por modelo, um cliente, um prompt e um dia. Ela mostra como medir, não quem é o mais rápido.
Três números de velocidade: latência vs. throughput de LLM na prática
Divida a "velocidade" em partes, porque cada parte tem um responsável diferente: a rede, o modelo e sua própria fila.
send request
-> first stream event (qualquer chunk SSE; pode ser um delta de raciocínio)
-> first visible content token (primeiro delta.content não vazio)
-> last token + final usage chunk
Tempo para o primeiro token (TTFT) é o tempo desde o envio da requisição até a chegada do primeiro token. Registramos duas versões. O primeiro evento de stream é o primeiro chunk SSE de qualquer tipo. O primeiro token de conteúdo visível é o primeiro chunk cujo choices[0].delta.content não é vazio. Para modelos que raciocinam antes de responder, o primeiro evento pode ser um delta de raciocínio (delta.reasoning_content) que chega bem antes do texto visível. Um mecanismo que monitora apenas delta.content mede o tempo para o primeiro token visível, não o tempo para o primeiro byte. Os usuários sentem o visível.
Tempo total vai desde o envio da requisição até o final do stream. Inclui raciocínio, tempo de rede e qualquer espera de nova tentativa que você adicionar.
Tokens de saída por segundo são os tokens de saída divididos pelo tempo total. Obtenha a contagem de tokens de usage.completion_tokens, que inclui tokens de raciocínio. Dividimos pelo tempo total, não pela janela visível. Alguns modelos em nossa amostra entregaram texto visível em poucos chunks grandes, portanto, uma taxa baseada em janela seria enganosa.
| Carga de trabalho | Observe primeiro | Depois | Por que |
|---|---|---|---|
| Chat | Primeiro token visível | Tempo total | O usuário olha para uma caixa em branco até que o texto visível apareça. |
| Agentes | Tempo total | Primeiro token visível | Cada etapa geralmente espera pela anterior, então os totais por etapa se somam. |
| Extração ou resumos em lote | Tokens de saída por segundo e custo por tarefa | Margem do limite de requisições | Ninguém observa o primeiro token, e o limite de requisições da conta limita a rapidez com que você pode enviar trabalho. |
Chamadas sem streaming, como extração de JSON estruturado, expõem apenas o tempo total. Faça streaming delas nos testes se quiser a separação.
O que medimos em 03/10/2026
Método. Esta é uma medição de primeira mão do TokenLab, observada em 03/10/2026, contra POST https://api.tokenlab.sh/v1/chat/completions (fonte). Cada requisição usou stream=true e stream_options.include_usage=true. Executamos 5 rodadas sequenciais por modelo a partir de um único cliente no Leste Asiático, usando fetch do Node 24. O prompt foi "Explique como o HTTP keep-alive reduz a latência para clientes de API. Escreva cerca de 200 palavras." Todos os modelos usaram configurações padrão de raciocínio. Os tempos são de relógio do lado do cliente, e todas as execuções foram bem-sucedidas (5/5) para cada linha abaixo.
Modelo (max_tokens 2000) |
Mediana primeiro evento de stream | Mediana primeiro token visível | Mediana tempo total | Mediana tokens de conclusão (raciocínio) | Tokens/s estimados |
|---|---|---|---|---|---|
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 (não reportado) | 34 |
gpt-5.6-luna |
3.262 ms | 3.262 ms | 8.183 ms | 313 (42) | 38 |
A coluna tokens/s é nossa própria estimativa: mediana de tokens de conclusão dividida pela mediana de segundos totais, por exemplo 453 ÷ 5,204 ≈ 87. É uma razão de medianas, não uma mediana de taxas por execução.
O que os números mostram, e nada mais:
- A ordenação pelo primeiro token visível (
claude-sonnet-5-5,gpt-5.6-luna,deepseek-v4.1-flash,gemini-3.8-flash) difere da ordenação pelo tempo total (deepseek-v4.1-flash,gpt-5.6-luna,gemini-3.8-flash,claude-sonnet-5-5). Uma métrica não pode substituir a outra. - O
deepseek-v4.1-flashteve uma lacuna de 1.591 ms entre o primeiro evento e o primeiro token visível. Sua saída visível mediana foi de cerca de 228 tokens, entregues em 87 eventos ao longo de 1.304 ms. - Para o
gemini-3.8-flash, o primeiro evento e o primeiro token visível compartilham uma mediana de 6.892 ms. Seu texto visível veio em uma mediana de 11 eventos ao longo de 1.734 ms, então o stream foi "em blocos" em vez de token por token. - O
claude-sonnet-5-5enviou uma mediana de 371 eventos ao longo de 9.186 ms, e ogpt-5.6-lunaenviou 265 eventos ao longo de 4.901 ms.
O custo acompanha a velocidade. Os preços abaixo vêm da API de modelos do TokenLab, observados em 03/10/2026, com preços atualizados em 02/10/2026T16:53:30.068Z. A última coluna é uma estimativa: mediana de tokens de conclusão vezes a taxa de saída, apenas do lado da saída. Verifique os registros de uso para cobranças reais.
| Modelo | Entrada por 1M | Saída por 1M | Max tokens de saída | Estimativa lado da saída, rodada mediana | Fonte |
|---|---|---|---|---|---|
deepseek-v4.1-flash |
$0,15 fora de pico, $0,30 pico | $0,60 fora de pico, $1,20 pico | 384.000 | 453 × $0,60 / 1M ≈ $0,00027 fora de pico, ≈ $0,00054 pico | API de modelo |
gemini-3.8-flash |
$0,375 | $1,875 | 65.536 | 826 × $1,875 / 1M ≈ $0,00155 | API de modelo |
claude-sonnet-5-5 |
$0,60 | $3 | 128.000 | 418 × $3 / 1M ≈ $0,00125 | API de modelo |
gpt-5.6-luna |
$0,06 | $0,36 | 128.000 | 313 × $0,36 / 1M ≈ $0,00011 | API de modelo |
Para o gpt-5.6-luna, essas taxas se aplicam quando a entrada é de no máximo 272K tokens. Acima disso, a requisição completa usa 2x as taxas de entrada e 1,5x as taxas de saída.
Limites desta amostra. Cinco execuções sequenciais de um único cliente no Leste Asiático é uma fatia fina. O prompt foi um pedido de redação curta, então os resultados mudarão com a região, hora do dia, prompt e tamanho da saída. Não testamos concorrência, então nada disso diz o que acontece sob carga. Trate a tabela como um modelo para seu próprio teste, executado a partir da região onde as execuções de produção ocorrem. Se você quiser uma visão mais ampla dos modelos, o leaderboard de API de LLM do TokenLab para desenvolvedores é um ponto de partida. Verifique seu método e data antes de confiar em qualquer número de velocidade lá. Não troque modelos silenciosamente também: o guia de confiabilidade, observado em 03/10/2026, observa que uma substituição pode alterar qualidade, preço, tamanho de contexto e ferramentas.
Tokens de raciocínio e max_tokens: por que 400 retornou quase nada
Também executamos o mesmo prompt com max_tokens definido como 400. Mesmo método, mesmas cinco execuções, mesma data (fonte).
Modelo (max_tokens 400) |
Mediana tokens de conclusão | Mediana tokens de raciocínio | Saída visível (aprox.) | Mediana primeiro token visível | Mediana tempo total |
|---|---|---|---|---|---|
deepseek-v4.1-flash |
400 | 400 | 0 tokens | 3.795 ms | 4.693 ms |
gemini-3.8-flash |
396 | 382 | 14 tokens | 4.199 ms | 4.240 ms |
claude-sonnet-5-5 |
400 | não reportado | 400 tokens | 3.088 ms | 11.078 ms |
gpt-5.6-luna |
317 | 42 | 275 tokens | 3.040 ms | 8.083 ms |
As medianas são calculadas por coluna, portanto, as colunas de uma linha não precisam descrever uma única execução. É por isso que o deepseek-v4.1-flash mostra um tempo para o primeiro visível ao lado de uma mediana de zero eventos visíveis.
A descoberta é clara. deepseek-v4.1-flash e gemini-3.8-flash gastaram quase todo o orçamento de 400 tokens em raciocínio e retornaram quase nenhum texto visível. Aumentar max_tokens para 2000 produziu respostas completas. Tokens de raciocínio contam dentro de usage.completion_tokens. Eles são relatados separadamente em usage.completion_tokens_details.reasoning_tokens.
Quando vimos o primeiro resultado de 400 tokens, a falha parecia uma resposta vazia, não um problema de orçamento. Três verificações a tornam visível:
- Leia o chunk de uso final, habilitado por
stream_options={"include_usage": True}. Sereasoning_tokensestiver próximo decompletion_tokense o texto estiver vazio, o orçamento foi para o raciocínio. - Verifique
finish_reason. O guia de streaming (observado em 03/10/2026) listalengthcomo o valor quando um limite de token é atingido. - Compare com a saída máxima do modelo. Por exemplo, a API de modelo lista 384.000 para
deepseek-v4.1-flashe 65.536 paragemini-3.8-flash, então 400 foi uma pequena fatia do que os modelos permitem.
A referência Create Chat Completion (observada em 03/10/2026) também lista max_completion_tokens e reasoning_effort. Ela diz que os valores suportados dependem do modelo, então leia a página do modelo antes de definir qualquer um deles. Não os testamos, e executamos cada linha com raciocínio padrão. Dimensione o limite a partir do seu próprio prompt: em nossa execução, uma resposta de 200 palavras produziu aproximadamente 228 a 418 tokens visíveis, e até 528 tokens de raciocínio além disso.
Um mecanismo de medição para a URL base do TokenLab
Este script usa a URL base do TokenLab, lê contagens de tokens do chunk de uso e registra o primeiro evento de stream separadamente do primeiro token de conteúdo visível. Ele também mantém cabeçalhos de resposta para depuração posterior. Ele segue as configurações de cliente nos docs (timeout=30.0, max_retries=0) para que o SDK não adicione novas tentativas ocultas aos seus tempos. O ID do modelo é um que medimos; substitua por qualquer ID cujos formatos de requisição aceitos incluam 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 = "Explain how HTTP keep-alive reduces latency for API clients. Write about 200 words."
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("median total_s:", statistics.median(r["total_s"] for r in runs))
Algumas notas sobre a leitura da saída:
first_event_sdispara em qualquer chunk, incluindo um chunk apenas de função ou de raciocínio.first_visible_sdispara apenas emdelta.contentnão vazio. Se os dois diferirem por segundos, o modelo está raciocinando antes de responder.- Contagens de tokens vêm do chunk de uso final. Esse chunk tem uma lista
choicesvazia, e é por isso que o loop verificachunk.usageantes de pulá-lo. - Execute cinco vezes ou mais, registre a região e relate as medianas junto com o tamanho da amostra.
- Para modelos que listam
openai_responses, o guia de streaming mostra Responses fazendo streaming com eventosresponse.output_text.deltaeresponse.completed. A mesma separação se aplica: cronometre o primeiro evento, depois o primeiro delta de texto. - Trate um stream que fecha antes de
response.completedou um motivo de finalizaçãostopcomo incompleto, não como um sucesso rápido.
Cabeçalhos e identificadores para registrar para depuração de latência
Uma requisição lenta é difícil de depurar se você manteve apenas uma duração. A referência da API e o guia de solução de problemas, ambos observados em 03/10/2026, nomeiam os identificadores que vale a pena manter.
| Identificador | Onde aparece | Use para |
|---|---|---|
X-Request-ID |
Cabeçalho de resposta, quando disponível | Suporte e depuração para uma requisição |
request_id |
Corpos de erro, logs de dashboard, registros de uso | Suporte em nível de requisição e reconciliação |
X-Routing-Time-MS |
Cabeçalho de resposta, quando disponível | Tempo gasto selecionando a entrega, antes da geração |
X-Task-ID, task_id, poll_url |
Respostas de criação e status assíncronos | Trabalhos de imagem, vídeo, música e 3D |
X-Billing-Transaction-ID |
Cabeçalho após faturamento final, quando disponível | Reconciliação de custos |
| Seu próprio job ou ID de usuário | Sua aplicação | Encontrar a requisição por trás de uma reclamação de usuário |
Para cada chamada, registre o endpoint, método, modelo, código de status, timestamp e latência. Adicione os nomes dos campos que você enviou (não o prompt), sua contagem de novas tentativas e se uma nova tentativa criou uma nova tarefa ou retomou uma existente. Nosso mecanismo adiciona os tempos divididos e contagens de tokens do chunk de uso.
Dois cuidados. Respostas de streaming podem se estabilizar após o término do stream, então um cabeçalho de faturamento pode estar ausente mesmo quando o uso é registrado posteriormente. Para valores faturados, use os registros de uso da API de Gerenciamento em vez de apenas contagens de tokens de resposta. Registre também o valor de X-TokenLab-Delivery-Policy se você definir um. A referência diz que aceita auto, verified ou official, que um valor inválido retorna 400, e que uma opção indisponível retorna 503 com code: delivery_tier_unavailable e retryable: true. Nunca registre Authorization, chaves de API, URLs assinadas, prompts completos ou dados pessoais.
Os detalhes da requisição no console são mantidos por 30 dias a partir da captura, então copie os IDs que você precisa para seus próprios logs. Em nosso pipeline, alinhamos esses IDs com a visualização de requisições; o post do console de requisições do TokenLab cobre essa visualização.
Limites de taxa, novas tentativas e latência vs. throughput de LLM
A velocidade por stream e o throughput da conta são tetos diferentes. O guia de limites de taxa, observado em 03/10/2026, lista os valores de nível padrão abaixo. Ele observa que eles podem mudar com a configuração ativa e são aplicados por chave de API.
| Nível | Requisições por minuto |
|---|---|
| Usuário | 1.000 |
| Parceiro | 10.000 |
| VIP | 10.000 |
Quando você ultrapassa o limite, a API retorna 429 rate_limit_exceeded com um cabeçalho Retry-After. O corpo do exemplo do guia carrega "retryable": true e "retry_after": 8. O guia diz para confiar nos valores retornados de X-RateLimit-Limit e Retry-After em vez de qualquer tabela copiada. Ele também diz que um modelo mais rápido não aumenta o limite de requisições da sua conta.
Aqui está a aritmética para trabalho em lote. Esta é nossa estimativa a partir das medianas acima, não um teste de carga. Streams simultâneos são aproximadamente requisições por segundo vezes segundos por requisição. A 1.000 requisições por minuto (cerca de 16,7 por segundo):
- Com
deepseek-v4.1-flasha uma mediana total de 5,204 s, cerca de 87 streams rodam ao mesmo tempo. - Com
claude-sonnet-5-5a uma mediana de 12,384 s, cerca de 206 streams rodam ao mesmo tempo.
Um stream mais lento significa mais concorrência para atingir a mesma taxa de requisição. Atingir o limite adiciona tempo de espera sobre o tempo de geração. Limites de tokens não são cobertos nas páginas que usamos, então verifique sua conta e a página do modelo para eles.
Como tentar novamente sem destruir seus números:
- Respeite
Retry-Afterquando presente. Caso contrário, use backoff exponencial com jitter aleatório e um limite rígido de tentativas. - Defina o SDK para
max_retries=0e tente novamente em um só lugar. Caso contrário, duas camadas tentarão novamente a mesma chamada e seus tempos serão contados em dobro. - Nunca tente novamente erros de validação, autenticação, saldo ou permissão. Tente novamente respostas
5xxtransitórias com um backoff curto. - Após a chegada do primeiro evento, um stream interrompido está incompleto e não é reiniciado automaticamente. Repetir a requisição pode produzir uma saída diferente e outra cobrança.
- Registre a contagem de novas tentativas e o tempo de espera separadamente do tempo do modelo, para que uma execução limitada não pareça um modelo lento.
Este é o padrão de nova tentativa limitada do guia:
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)
Limite também a concorrência, não apenas a média de requisições por minuto, e enfileire rajadas. Acompanhe respostas 429 repetidas por chave de API para que um cliente não possa sobrecarregar o restante da sua aplicação.
FAQ
Tokens por segundo mais altos são sempre uma experiência de usuário mais rápida?
Não. Em nossa amostra de 03/10/2026, o claude-sonnet-5-5 mostrou o primeiro token visível mais cedo (2.981 ms), mas o tempo total mais longo (12.384 ms). O deepseek-v4.1-flash iniciou o texto visível mais tarde (3.925 ms) e terminou primeiro (5.204 ms). Qual deles parece mais rápido depende se o usuário assiste ao stream ou espera pela resposta completa. Cinco execuções de um único cliente não podem definir isso para sua carga de trabalho.
Por que minha resposta de stream voltou com quase nenhum texto?
Você provavelmente gastou o orçamento em raciocínio. Com max_tokens 400, o deepseek-v4.1-flash usou 400 tokens de raciocínio e retornou cerca de 0 tokens visíveis. Verifique usage.completion_tokens_details.reasoning_tokens no chunk de uso final e o finish_reason. Em seguida, aumente o limite; em 2000, ambos os modelos de raciocínio em nosso teste responderam na íntegra.
Um modelo mais rápido aumenta meu limite de taxa?
Não. O guia de limites de taxa diz que a velocidade do modelo, limites de tokens e limites de taxa da conta são restrições separadas. Um stream mais rápido termina mais cedo e libera um slot de concorrência, mas seu limite de requisições por chave permanece o mesmo. Peça ao suporte um limite diferente se precisar.
Quais IDs devo enviar ao suporte quando um stream está lento?
Envie o request_id (ou X-Request-ID), o endpoint, método, modelo, timestamp e código de status. Adicione task_id e poll_url para trabalho assíncrono e billing_transaction_id quando presente. Inclua seus tempos divididos e o corpo do erro seguro, e redija chaves, prompts e mídia privada primeiro.
Execute o mecanismo acima em seu próprio prompt, depois compare o que você mediu com os rankings de modelos do TokenLab.
Fontes
Preço observado em 2026-10-03
- TokenLab Docs: StreamingObservado em 2026-10-03
- TokenLab Docs: Rate limitsObservado em 2026-10-03
- TokenLab Docs: Logs and troubleshootingObservado em 2026-10-03
- TokenLab Docs: Build a reliable TokenLab integrationObservado em 2026-10-03
- TokenLab Docs: API ReferenceObservado em 2026-10-03
- TokenLab Docs: Create Chat CompletionObservado em 2026-10-03
- TokenLab live model API: deepseek-v4.1-flashObservado em 2026-10-03
- TokenLab live model API: gemini-3.8-flashObservado em 2026-10-03
