Latência P99 é o tempo de resposta que 99% das requisições superam. Se o P99 de uma API é 400 milissegundos, 99 de cada cem requisições voltam em 400 ms ou menos e uma demora mais. O P95 é a mesma ideia em 95%: uma em cada vinte requisições é mais lenta. Os dois descrevem a cauda da distribuição, as requisições lentas que a média disfarça.
A cauda importa mais do que o tamanho dela sugere. Quem faz uma única requisição raramente percebe. Quem conversa com um agente de voz por vinte turnos provavelmente percebe. Este guia explica como os percentis funcionam, como calculá-los, os erros que os fazem mentir e o que eles significam para IA de voz em tempo real.
P50, P95 e P99 em resumo
| Percentil | O que indica | Requisições mais lentas |
|---|---|---|
| P50 | A mediana, uma requisição típica | 1 em 2 |
| P90 | O começo da cauda lenta | 1 em 10 |
| P95 | A meta comum de painéis e SLOs | 1 em 20 |
| P99 | Lentidões raras: pausas, novas tentativas, filas | 1 em 100 |
| P99.9 | Casos isolados que só aparecem com muito volume | 1 em 1.000 |
Percentis altos precisam de mais amostras para significar algo. Um P99 de 100 requisições depende de uma só. Use pelo menos algumas centenas de amostras para o P95 e alguns milhares para o P99, e mostre o número de amostras ao lado do resultado.
Por que a média esconde a cauda
Pegue 100 requisições. 94 terminam em 200 ms e 6 levam dois segundos. A média é 308 ms, um tempo que nenhuma requisição teve. A mediana é 200 ms, o que parece ótimo. O P95 e o P99 são 2.000 ms, que foi o que seis dos seus usuários viram.
Distribuições reais de latência são desiguais assim. A maioria das requisições segue pelo caminho rápido, e uma minoria espera atrás de um disco lento, um cache frio, uma pausa de coleta de lixo ou uma fila cheia. A média mistura os dois grupos num número que não descreve nenhum deles. A mediana ignora o grupo lento por completo. Os percentis o mantêm à vista.
Como calcular P95 e P99
Ordene as medições da mais rápida para a mais lenta e leia o valor que está a 95% ou 99% do caminho. Com 200 amostras, o P95 é o 190º valor e o P99, o 198º. É o método do posto mais próximo:
import math
def percentile(samples, p):
"""Nearest rank: the smallest sample with at least p% of samples at or below it."""
ordered = sorted(samples)
rank = math.ceil(p / 100 * len(ordered))
return ordered[max(rank, 1) - 1]
latencies_ms = [200] * 94 + [2000] * 6
print(percentile(latencies_ms, 50)) # 200
print(percentile(latencies_ms, 95)) # 2000
print(percentile(latencies_ms, 99)) # 2000
O NumPy interpola por padrão, então numpy.percentile pode devolver um valor entre duas amostras. Passe method="inverted_cdf" para obter o posto mais próximo. Com poucas amostras, os dois métodos podem divergir bastante, mais um motivo para informar o número de amostras.
Sistemas de monitoramento normalmente não guardam cada amostra. Eles contam requisições em faixas de latência e estimam o percentil a partir do histograma, como faz o histogram_quantile() do Prometheus. A estimativa só é tão precisa quanto as faixas ao redor, então coloque os limites perto das latências que importam para você.
Três erros que fazem os percentis mentirem
Tirar a média de percentis. Um servidor atende 900 requisições, todas em 200 ms, e outro atende 100, das quais dez levam um segundo. Os P95 são 200 ms e 1.000 ms, e a média deles é 600 ms. O P95 real das 1.000 requisições é 200 ms. A documentação do Prometheus diz o mesmo: quantis calculados separadamente não podem ser agregados. Combine os histogramas ou as amostras e só então calcule.
Somar os percentis das etapas. Um agente de voz executa em sequência reconhecimento de fala, um modelo de linguagem e texto para fala. Suponha que o reconhecimento sempre leve 300 ms, o LLM leve 500 ms mas 1.500 ms em uma de cada dez chamadas, e o TTS leve 150 ms mas 600 ms em uma de cada dez. Somar os P95 das etapas dá 2.400 ms. O P95 real do turno inteiro é 1.950 ms, porque os dois casos lentos raramente caem no mesmo turno. Meça o tempo de ponta a ponta diretamente em vez de estimá-lo pelas partes.
Medir com um cliente que espera. Um gerador de carga que só envia a próxima requisição quando a anterior volta envia menos requisições justamente quando o servidor está lento, então os períodos lentos ficam sub-representados. Gil Tene chama isso de omissão coordenada, e o gerador de carga dele, o wrk2, existe para evitar o problema enviando a uma taxa fixa. Para números de produção, meça o tráfego real e não um cliente de teste.
Por que a cauda decide como um agente de voz soa
A conversa funciona com tempos apertados. Uma revisão da pesquisa sobre troca de turnos de Levinson e Torreira conclui que as pausas entre turnos são da ordem de 200 ms. Em um estudo de chamadas telefônicas, Kendrick e Torreira viram que respostas após pausas de mais de uns 700 ms eram em sua maioria recusas e outras respostas não preferidas, e que até pausas de mais de uns 300 ms tornavam uma aceitação direta menos provável. Quem ouve dá sentido às pausas, então, para quem liga, um agente que fica 900 ms em silêncio pode soar relutante, não só lento.
Agora multiplique pelos turnos. Se cada turno tem, de forma independente, 5% de chance de passar do P95, uma chamada de 20 turnos tem 64% de chance de encontrar pelo menos um deles (1 − 0,95²⁰). Até o P99 aparece em cerca de 18% das chamadas de 20 turnos. A mediana descreve um turno típico; a cauda descreve uma chamada típica. Jeff Dean e Luiz André Barroso, do Google, apontaram o mesmo para grandes serviços em The Tail at Scale: quando uma ação do usuário se divide em muitas requisições, respostas lentas raras se tornam comuns.
O que medir em um pipeline de voz
Meça o que a pessoa ouve. Para um agente de voz, é o tempo entre o fim da fala de quem liga e a primeira amostra audível da resposta, registrado do lado de quem liga. Depois divida por etapa para saber de onde vem a cauda:
| Etapa | O que cronometrar | Causas comuns da cauda |
|---|---|---|
| Detecção de turno | Do fim da fala até o turno ser dado como encerrado | Hesitações, ruído de fundo, pausas longas |
| Fala para texto | Do fim do turno à transcrição final | Turnos longos, jitter de rede |
| LLM e ferramentas | Da transcrição ao primeiro token, com ferramentas | Ferramentas lentas, prompts longos, filas do provedor |
| Texto para fala | Do primeiro texto enviado ao primeiro áudio audível | Conexões novas, primeiras frases longas |
| Rede e telefonia | Do áudio saindo do seu servidor até quem liga | Roteamento da operadora, buffers de jitter |
O tempo até o primeiro áudio (TTFA) é o número de TTS a acompanhar, porque um modelo em streaming começa a tocar antes de a frase ficar pronta. O silêncio inicial também conta: um trecho que começa com 300 ms de silêncio são 300 ms a mais de espera. O script abaixo cronometra os primeiros bytes, então verifique o silêncio inicial do seu áudio separadamente.
Este script mede percentis de TTFA do texto para fala Sonic da Cartesia. Ele agenda 205 requisições com meio segundo de intervalo, descarta as cinco primeiras e cronometra cada uma do horário agendado até os primeiros bytes de áudio. Medir a partir do horário agendado, e não do envio, faz uma resposta lenta que atrasa a próxima requisição aparecer nos números, o que evita a omissão coordenada descrita acima:
import math
import os
import time
from cartesia import Cartesia
def percentile(samples, p):
"""Nearest rank: the smallest sample with at least p% of samples at or below it."""
ordered = sorted(samples)
rank = math.ceil(p / 100 * len(ordered))
return ordered[max(rank, 1) - 1]
# max_retries=0: a retried request would hide a failure inside a slow sample.
client = Cartesia(api_key=os.environ["CARTESIA_API_KEY"], max_retries=0)
interval = 0.5 # seconds between scheduled requests
ttfa_ms = []
failures = 0
first = time.perf_counter() + interval
for i in range(205):
# Each request has a fixed start time. If a slow response makes us late,
# the wait counts against latency instead of quietly thinning the sample.
scheduled = first + i * interval
time.sleep(max(0.0, scheduled - time.perf_counter()))
got_audio = False
try:
with client.tts.with_streaming_response.generate(
model_id="sonic-3.6",
transcript="Your order shipped this morning and should arrive on Thursday.",
voice="6ccbfb76-1fc6-48f7-b71d-91ac6298247b",
output_format={"container": "raw", "encoding": "pcm_s16le", "sample_rate": 16000},
language="en",
) as response:
for chunk in response.iter_bytes():
if chunk:
got_audio = True
if i >= 5: # the first requests pay for connection setup
ttfa_ms.append((time.perf_counter() - scheduled) * 1000)
break
except Exception:
pass
if not got_audio:
failures += 1
print(f"{len(ttfa_ms)} timed requests, {failures} failed or returned no audio")
if ttfa_ms:
for p in (50, 90, 95, 99):
print(f"p{p}: {percentile(ttfa_ms, p):.0f} ms")
print(f"max: {max(ttfa_ms):.0f} ms")
Instale o SDK com pip install cartesia e defina CARTESIA_API_KEY pelo painel. Rode o script na região onde seus servidores rodam, no horário de pico do tráfego, porque um notebook no Wi-Fi de casa mede o Wi-Fi. Por padrão, o SDK repete duas vezes as requisições que falham, o que juntaria uma falha e a nova tentativa numa única amostra lenta; por isso o script desliga as novas tentativas e conta à parte as falhas, incluindo respostas sem áudio. Não as tire do relatório: uma requisição que nunca respondeu é a pior latência de todas. Para um agente ao vivo, cronometre o caminho por WebSocket que você realmente usa, já que ele mantém uma conexão aberta entre os turnos.
O que os benchmarks públicos mostram
O Coval roda a cada 30 minutos benchmarks independentes de texto para fala, fala para texto e fala para fala em APIs públicas, e publica medianas, percentis e número de amostras. A metodologia inclui o silêncio inicial no TTFA e exclui o estabelecimento de conexões.
No ranking de texto para fala de 30 dias, consultado em 15 de outubro de 2026, a distância entre mediana e P95 variava muito entre 33 modelos com pelo menos 260 amostras cada. No modelo típico, o P95 era 1,38 vez a mediana. Nos extremos, o P95 de um modelo era 1,1 vez a mediana, e o de outro, mais de sete vezes: 624 ms no caso típico e 4.751 ms em uma de cada vinte requisições.
A lição é a do começo deste guia: dois modelos com medianas parecidas podem soar muito diferentes numa chamada. Compare os P95, com o número de amostras, medidos do jeito que seus usuários os vivem.
Como reduzir a latência de cauda
- Mantenha as conexões abertas. Cada nova requisição HTTPS paga de novo o estabelecimento de TCP e TLS, e a documentação da Cartesia observa que esse custo costuma ser da mesma ordem do tempo até o primeiro byte de áudio. Um WebSocket aberto durante a chamada paga isso uma vez só.
- Guarde em cache o que se repete. Saudações, mensagens de espera e despedidas não precisam ser geradas de novo a cada chamada. Guarde-as em cache como áudio bruto e intercale-as no fluxo ao vivo.
- Comece a falar antes. Envie os tokens do LLM para o texto para fala conforme chegam, em vez de esperar um parágrafo inteiro.
- Dê um prazo às ferramentas. Uma chamada de ferramenta que leva dois segundos soma dois segundos ao turno, toda vez. Defina um tempo limite e faça o agente dizer o que está fazendo enquanto espera.
- Duplique as requisições lentas. The Tail at Scale descreve enviar uma requisição reserva quando a primeira passa do P95 habitual e usar a que responder antes. Esperar até o P95 limita a carga extra a cerca de 5%. Faça isso só com requisições que podem ser enviadas duas vezes sem risco, como gerar o mesmo áudio de novo, nunca com uma ferramenta que grava dados.
- Rode os modelos perto da chamada. Se a sua cauda vem da distância de rede ou de infraestrutura compartilhada, a implantação on-premise coloca os modelos ao lado da sua telefonia.
Se você prefere não montar e ajustar o pipeline por conta própria, o Cartesia Managed Agents executa detecção de turno, fala para texto do Ink, o LLM e o Sonic em um número de telefone, e você pode criar um no playground e ligar para ele. Se o seu próprio pipeline estiver lento, a solução normalmente está na etapa que as suas medições apontarem, e o script acima é o ponto de partida.