Duas respostas levam oito segundos cada. Na primeira, o texto começa a aparecer em 0,4 s e vai fluindo. Na segunda, a tela fica parada por 8 s e a resposta aparece de uma vez.
Tecnicamente empatadas. Na percepção do usuário, a primeira é rápida e a segunda está travada. Entender essa diferença é praticamente toda a otimização de latência que a maioria dos produtos precisa.
Os três números
| Métrica | O que é | O usuário sente? |
|---|---|---|
| TTFT — tempo até o primeiro token | Da chamada até o primeiro pedaço da resposta | Muito. É a "velocidade" percebida |
| TPOT — tempo entre tokens | Ritmo de saída depois que começou | Sim, se ficar abaixo da velocidade de leitura |
| Tempo total | Até a última palavra | Pouco, quando há transmissão contínua |
A velocidade de leitura confortável em português fica em torno de 15 a 25 tokens por segundo. Acima disso, o texto aparece mais rápido do que a pessoa lê — e ganho adicional é invisível. É um teto útil: se o seu sistema já entrega 40 tokens por segundo, otimizar para 60 não muda nada para o usuário.
Otimize o TTFT. Entregue TPOT suficiente. Ignore o tempo total.
Com transmissão contínua ligada e primeiro token abaixo de um segundo, quase ninguém reclama de uma resposta que leva quinze segundos para terminar.
De onde vem o TTFT
Antes do primeiro token, acontecem quatro coisas, e cada uma tem uma correção diferente:
- Rede até o servidor: dezenas a poucas centenas de milissegundos.
- Fila, se o servidor estiver ocupado: de zero a segundos.
- Processamento do contexto (a fase de leitura do prompt): proporcional ao tamanho do contexto.
- Primeiro passo de geração: rápido.
O item 3 é o mais subestimado. Ler o prompt custa tempo, e esse custo cresce com o tamanho. Um contexto de 30 mil tokens pode gastar vários segundos só sendo lido, antes de a primeira palavra sair.
Traduzindo em decisão prática: mandar menos contexto é uma otimização de latência, não só de custo. Aquele corte de 10 trechos para 4 na busca melhora as duas coisas de uma vez.
Meça antes de mexer
import time, requests, json
def medir(payload, url, chave):
t0 = time.perf_counter()
ttft = None
tokens = 0
with requests.post(url, headers={"Authorization": f"Bearer {chave}"},
json={**payload, "stream": True},
stream=True, timeout=120) as r:
for linha in r.iter_lines():
if not linha or not linha.startswith(b"data: "):
continue
corpo = linha[6:]
if corpo == b"[DONE]":
break
pedaco = json.loads(corpo)
delta = pedaco["choices"][0]["delta"].get("content")
if delta:
if ttft is None:
ttft = time.perf_counter() - t0
tokens += 1
total = time.perf_counter() - t0
return {
"ttft_s": round(ttft or total, 3),
"total_s": round(total, 3),
"tokens": tokens,
"tokens_por_s": round(tokens / max(total - (ttft or 0), 1e-6), 1),
}
Rode 20 vezes e olhe a mediana e o percentil 95, nunca a média. Latência tem cauda longa: a média esconde que uma em cada vinte chamadas leva quatro vezes mais — e é essa que gera a reclamação.
As correções, em ordem de retorno
1. Ligue a transmissão contínua
Se ainda não está ligada, é a maior melhoria disponível e não custa nada. "stream": true na chamada e renderização incremental na interface. Transforma 8 segundos de espera em 0,4 segundo de espera com texto fluindo.
2. Encurte o contexto
Menos trechos recuperados, histórico com janela, prompt de sistema sem redundância. Efeito direto e proporcional no TTFT.
3. Escolha o modelo pela tarefa
Modelo menor tem TTFT menor e ritmo maior. Numa classificação de intenção, a diferença entre 0,3 s e 2 s decide se a interface parece viva.
E atenção especial aos modelos que raciocinam antes de responder: o bloco de pensamento acontece antes do primeiro token visível. O TTFT percebido pode passar de dez segundos mesmo com o servidor perfeitamente saudável. Em interação com pessoa esperando, ou você exibe o raciocínio (o que dá sensação de progresso) ou usa um modelo que não pensa.
4. Mostre progresso antes da primeira palavra
Truque de interface que vale mais que otimização de servidor: quando há etapas antes da geração — buscar documentos, consultar sistema —, mostre-as. "Procurando nos documentos… encontrei 4 trechos… redigindo" ocupa o tempo com informação, e o usuário percebe o sistema como rápido mesmo que o relógio diga o contrário.
5. Comece a trabalhar antes de o usuário terminar
Em fluxos com etapa previsível, dispare o trabalho enquanto a pessoa ainda digita ou revisa. A busca de documentos, por exemplo, pode começar assim que a pergunta parece completa.
Placa mais cara. Numa GPU maior, o TTFT melhora bem menos do que se espera — o gargalo com um pedido só é memória, não cálculo. O ganho aparece em vazão total, com muitos usuários.
Reduzir max_tokens. Corta o tempo total, não o TTFT. Com transmissão contínua, o usuário nem percebe.
Trocar de servidor de inferência. Faz diferença sob carga; com um pedido de cada vez, quase nada.
Metas razoáveis
| Tipo de aplicação | TTFT alvo | Ritmo alvo |
|---|---|---|
| Autocompletar de código | < 200 ms | Alto — a resposta é curta |
| Chat com pessoa esperando | < 800 ms | > 20 tokens/s |
| Assistente com busca em documentos | < 2 s (com progresso visível) | > 15 tokens/s |
| Análise ou relatório | < 5 s | Irrelevante — mostre barra de progresso |
| Processamento em lote | Irrelevante | Otimize vazão, não latência |
Repare na última linha. Em trabalho de lote, otimizar latência é desperdício: o que importa é quantos itens saem por hora, e as duas coisas às vezes puxam para lados opostos — lote maior piora a latência individual e melhora a vazão.
Meça na sua carga real
API por token com transmissão contínua e GPUs por hora para testar o seu próprio servidor. Cobrança em reais, sem assinatura.
Criar conta →O erro de diagnóstico mais comum
"Ficou lento" quase nunca é o modelo. Na ordem em que costumam aparecer:
- O contexto cresceu — o histórico da conversa não tem janela.
- A busca de documentos passou a devolver mais trechos.
- Alguém aumentou o número de trechos "para melhorar a qualidade".
- O servidor está enfileirando porque a carga subiu.
- Um passo anterior (consulta a banco, chamada externa) ficou lento e foi contado como latência de IA.
Por isso o registro por chamada precisa separar as etapas. Sem isso, você vai passar uma semana otimizando o modelo para descobrir que o problema era uma consulta ao banco de dados.
Conclusão
Latência de LLM é, sobretudo, um problema de percepção. Ligue a transmissão contínua, corte o contexto, escolha o modelo pela tarefa e mostre progresso durante as etapas anteriores.
Meça TTFT e ritmo separadamente, olhe o percentil 95 e pare de otimizar quando o texto já aparece mais rápido do que a pessoa lê. Depois desse ponto, o esforço rende zero.
Continue: dimensionar o servidor · cortar a conta · medir em produção