TL;DR:
– P95, não P50, é a métrica que define se 1 em cada 20 usuários vai sair frustrado da chamada.
– LLM TTFT domina o pipeline na maioria dos casos — medir por componente é o único jeito de saber onde está o gargalo.
– Snippet Python para Pipecat 0.0.57+ incluído e validado tecnicamente — cola direto no seu repo.
Você sabe que seu voice agent tem latência “aceitável”. Seus testes mostram 450ms de média. O produto está em produção há três semanas e o dashboard parece tranquilo.
O problema é que um de cada vinte usuários está saindo da chamada frustrado — e a métrica que você monitora não captura isso.
Este artigo é para um perfil específico: o engenheiro que já fez o voice agent funcionar, conectou STT, LLM e TTS, testou em staging, e subiu para produção. O que ainda não fez foi medir como o sistema se comporta nos piores 5% das chamadas. Não a latência média. A latência P95.
A diferença entre as duas métricas é o que separa um produto conversacional de um produto frustrante.
1. Por que P95, não P50
Latência média (P50) responde à pergunta errada. Ela diz que metade das suas chamadas está abaixo de X milissegundos. O que ela esconde é o comportamento nos casos fora do caminho feliz — LLM com contexto longo, STT com sotaque regional, TTS em servidor sobrecarregado, usuário em rede 4G com jitter.
O dado que muda a leitura: análise publicada pela AssemblyAI em dezembro de 2025 (Martin Schweiger, Sr Technical PMM) mostra que um sistema com P50 de 200ms e P95 de 2000ms frustra um em cada vinte usuários. Em termos absolutos: se seu sistema recebe 10.000 chamadas por dia, 500 pessoas por dia têm uma experiência ruim — mesmo com latência média “OK”.
P95 mede o pior caso que um usuário real ainda encontra com frequência. Não é outlier, não é incidente: é o percentil que define a qualidade da cauda da distribuição.
A metodologia de benchmark por componente do paper arXiv:2508.04721 (Ethiraj et al., agosto 2025) reforça a abordagem: os autores medem RTF (Real-Time Factor) por estágio do pipeline — não latência agregada — exatamente porque a média do sistema inteiro mascara gargalos em componentes individuais.
O que medir:
- P50 (mediana): referência de “comportamento típico”
- P95: threshold de aceitabilidade em produção
- P99: para SLAs formais e contratos enterprise
A regra prática: se P95 > 800ms, o produto está fora do threshold de conversação natural percebida. Se P95 > 1500ms, o produto está na faixa de interação frustrante para qualquer tipo de script.
2. Os cinco componentes da latência end-to-end
Latência end-to-end em voice agents não é uma métrica — é uma soma de cinco componentes sequenciais, com possibilidade de paralelização parcial entre LLM e TTS. Tratar como uma caixa preta impede diagnóstico.
O benchmark HumDial-FDBench do ICASSP 2026 (Wang et al., abr/2026) formaliza três métricas distintas para sistemas de diálogo de voz em tempo real: first response latency (tempo até a primeira palavra do agente), stop latency (tempo até o agente parar de falar quando interrompido), e response latency (tempo total de processamento por turno). Este artigo foca em first response latency — o componente mais relevante para a percepção do usuário no início de cada troca.
Componente 1: VAD / EOT Detection (End-of-Turn)
O agente precisa saber que o usuário parou de falar antes de começar a processar. O VAD (Voice Activity Detector) identifica silêncio; o EOT detection decide que o turno terminou.
Os Docs do Deepgram sobre latência de streaming definem EOT latency via Flux como o tempo entre o usuário parar de falar e o sistema reconhecer o fim de turno. Intervalo típico: 100–500ms. Sistemas que usam threshold de silêncio fixo (ex.: 500ms de silence) adicionam essa espera artificialmente a toda chamada.
Alternativa: modelos semânticos de turn detection como o SmartTurn do Pipecat reduzem falsos finais de turno sem aumentar o timeout de silêncio.
Componente 2: STT Streaming
O STT começa a processar áudio enquanto o usuário ainda fala (streaming), mas o transcript final — com pontuação e confiança — só fica disponível após o EOT. Latência do STT = tempo entre fim de fala do usuário e entrega do transcript ao LLM.
Os Deepgram Docs definem transcription latency como (audio cursor - transcription cursor). Para o Deepgram Nova-3, o intervalo típico é 150–300ms em condições normais de rede.
Componente 3: LLM TTFT (Time to First Token)
O LLM TTFT é o tempo entre o envio do prompt e o recebimento do primeiro token da resposta. É a maior variável no pipeline — depende de tamanho do modelo, contexto de entrada, carga do servidor e estratégia de quantização.
Valores de referência baseados em Schweiger (AssemblyAI, dez/2025) e Ethiraj et al. (arXiv:2508.04721). Variam com hardware, carga do servidor e tamanho do contexto:
| Tamanho do modelo | TTFT típico |
|---|---|
| < 3B parâmetros | 50–150ms |
| 7B parâmetros | 150–400ms |
| 13B+ parâmetros | 400–800ms+ |
| Modelos grandes via API (GPT-4o, Claude Sonnet) | 300–800ms, altamente variável no P95 |
A quantização 4-bit reduz TTFT significativamente. O paper arXiv:2508.04721 demonstra RTF < 1.0 para pipeline completo usando quantização 4-bit no componente LLM — o que viabiliza streaming em tempo real mesmo com modelos maiores.
Componente 4: TTS TTFA (Time to First Audio)
O TTS começa a gerar áudio assim que recebe os primeiros tokens do LLM (streaming TTS). TTFA = tempo entre o início do streaming de texto e o primeiro chunk de áudio emitido para o canal.
Os ElevenLabs Docs sobre latência documentam que modelos Flash têm TTFA de inferência de aproximadamente 75ms. O trade-off está explicitado pelo próprio vendor: “there is no way to get Eleven v3 quality at Flash speeds”. Região geográfica afeta: US, EU (Amsterdam) e Asia (Singapura) têm roteamento automático para o servidor mais próximo.
Componente 5: Rede e codec
Frequentemente ignorado em testes de staging. Em produção com usuário em rede móvel (4G/5G com jitter), o round-trip de rede adiciona 40–200ms e pode aumentar o P95 sozinho. Codec G.711 (usado em PSTN) introduz compressão com qualidade inferior ao Opus; latência de packetização de 20ms por pacote.
Total típico (pipeline sequencial): 450–1700ms
Com paralelização LLM→TTS: 350–900ms
A paralelização funciona assim: o TTS começa a gerar áudio com os primeiros tokens do LLM, antes de ter o texto completo. Reduz a latência percebida significativamente em respostas longas.
3. Como medir cada componente em produção com Pipecat
Código genérico de latência não serve para o caso real — depende de qual framework você usa e quais hooks de métricas ele expõe. O código abaixo é específico para Pipecat 0.0.57+ (Python, Daily), que emite métricas por componente via MetricsFrame e TTFBMetricsData.
Stack instrumentada: Pipecat 0.0.57+ com serviços Deepgram (STT), OpenAI (LLM) e ElevenLabs (TTS). Para outras combinações de serviços, troque os nomes de serviço nos filtros — a interface TTFBMetricsData é a mesma. Validado tecnicamente em MESA-96 com Pipecat 1.1.0 e 0.0.57.
# stack: Pipecat 0.0.57+ | Python 3.11+
# Validado em MESA-96 (Pipecat 0.0.57 e 1.1.0)
import numpy as np
from collections import defaultdict
from pipecat.frames.frames import MetricsFrame
from pipecat.metrics.metrics import TTFBMetricsData, MetricsData
from pipecat.observers.base_observer import BaseObserver
from pipecat.pipeline.task import PipelineTask, PipelineParams
from pipecat.processors.frame_processor import FrameDirection
class LatencyTracker:
"""Coleta amostras de TTFB por componente Pipecat e calcula percentis."""
def __init__(self):
self._samples: dict[str, list[float]] = defaultdict(list)
def record(self, component: str, latency_ms: float) -> None:
self._samples[component].append(latency_ms)
def report(self) -> None:
print(f"
{'Componente':40s} {'P50':>8} {'P95':>8} {'n':>5}")
print("-" * 68)
for component, samples in self._samples.items():
if len(samples) < 2:
print(f"{component:40s} {'—':>8} {'—':>8} {len(samples):>5}")
continue
p50 = np.percentile(samples, 50)
p95 = np.percentile(samples, 95)
flag = " ← CRÍTICO" if p95 > 800 else (" ← alerta" if p95 > 400 else "")
print(f"{component:40s} {p50:>7.0f}ms {p95:>7.0f}ms {len(samples):>5}{flag}")
tracker = LatencyTracker()
class MetricsObserver(BaseObserver):
"""Observer de métricas — Pipecat 0.0.57.
Nota de migração para 1.x: a assinatura de on_push_frame muda para
(self, data: FramePushed) — acesse o frame via data.frame.
"""
async def on_push_frame(
self,
src,
dst,
frame,
direction: FrameDirection,
timestamp: int,
) -> None:
if isinstance(frame, MetricsFrame):
for metric in frame.data:
if isinstance(metric, TTFBMetricsData):
# metric.value está em segundos — convertendo para ms
tracker.record(metric.processor, metric.value * 1000)
# Observador registrado em PipelineParams (único modo suportado em 0.0.57)
task = PipelineTask(
pipeline,
params=PipelineParams(
enable_metrics=True,
enable_usage_metrics=True,
observers=[MetricsObserver()],
),
)
# Ao final da sessão ou em intervalo de diagnóstico:
tracker.report()
Saída esperada:
Componente P50 P95 n
--------------------------------------------------------------------
DeepgramSTTService 152ms 185ms 30
OpenAILLMService 409ms 527ms 30 ← alerta
ElevenLabsTTSService 69ms 105ms 30
O que este código mede: TTFB por componente — STT (tempo até transcript), LLM (tempo até primeiro token), TTS (tempo até primeiro chunk de áudio). Não mede VAD/EOT nem latência de rede; esses requerem instrumentação no nível de transporte (WebRTC ou WebSocket).
Limitação: TTFBMetricsData mede tempo até o primeiro resultado, não a duração completa do componente. Para medir duração total do STT (ex.: para chamadas com múltiplas interrupções), você precisa de timestamps em UserStartedSpeakingFrame, UserStoppedSpeakingFrame, e TranscriptionFrame.
codigo-validado
4. O que os números significam para o ouvido humano
Dois thresholds aparecem na literatura com frequências diferentes. Entender a diferença entre eles evita erro de interpretação.
300ms — o limite cognitivo
Pesquisas em percepção temporal humana indicam que respostas abaixo de 300ms são percebidas como “instantâneas”. Acima disso, o cérebro registra uma pausa. A análise da AssemblyAI usa esse threshold como referência para o que seria “ideal” em interações conversacionais.
É um objetivo de produto, não um threshold de qualidade mínima.
800ms P95 — o threshold de conversação natural
Este é o threshold prático. Abaixo de 800ms P95 end-to-end, usuários percebem a pausa como “processamento natural”. Acima disso, a pausa começa a quebrar o ritmo da conversa.
Os Deepgram Docs definem: P95 > 400ms = alerta; P95 > 800ms = crítico. Esses thresholds são para STT isolado. O pipeline completo pode ter latência maior mantendo experiência aceitável porque o usuário já espera que o “sistema pense”.
1500ms — tolerância para IVR transacional
Para scripts fechados (confirmação de agendamento, autenticação por voz, respostas sim/não), a tolerância de usuários é maior do que em diálogo aberto. O limiar de 1500ms para IVR transacional é uma estimativa editorial baseada na divergência documentada entre contextos de uso pelo benchmark HumDial-FDBench (Wang et al., abr/2026), que demonstra que métricas de latência aceitáveis variam significativamente conforme o tipo de interação — e pela distinção estabelecida pela própria Deepgram entre thresholds de alerta (400ms) e crítico (800ms) aplicáveis a diálogo de voz em geral: contextos transacionais com script fechado toleram latências maiores porque o usuário não espera continuidade conversacional, mas sim resposta a uma ação específica.
Reconciliando os três thresholds:
| Threshold | Contexto | Interpretação |
|---|---|---|
| < 300ms P95 | Diálogo aberto | Ideal — percebido como instantâneo |
| < 800ms P95 | Agente conversacional genérico | Aceitável — pausa percebida como processamento |
| < 1500ms P95 | IVR transacional com script fechado | Tolerável — usuário entende que é sistema |
| > 1500ms P95 | Qualquer contexto | Problemático — abandono de chamada |
5. O que cada plataforma expõe para você medir
A condição para uma comparação honesta de latência entre plataformas seria um benchmark primário replicável com hardware, dataset e versão de stack documentados. Esse benchmark não existe de forma independente e pública para Vapi, LiveKit Agents e Pipecat em condições equivalentes.
Esta seção documenta o que cada plataforma expõe para instrumentação — que é o que você precisa saber antes de escolher uma.
Pipecat
O Pipecat emite métricas via MetricsFrame com lista de TTFBMetricsData por padrão quando enable_metrics=True está ativo no PipelineTask. Cada serviço (STT, LLM, TTS) emite seu próprio evento com processor (nome do serviço), value (segundos até o primeiro resultado), e model (nome do modelo usado).
Ferramentas nativas:
– Whisker: debugger visual que exibe frames em tempo real, incluindo timing por componente
– Tail: terminal dashboard para inspeção de pipeline em desenvolvimento
Documentação: Pipecat Metrics
LiveKit Agents
O LiveKit Agents expõe métricas via telemetria integrada ao LiveKit Server. O AgentSession (versão 1.0+, abril 2025) emite eventos de ciclo de vida — incluindo timing de STT, LLM e TTS — via LiveKit room events.
Para medição em produção, o caminho padrão é LiveKit Analytics + exportação via webhook ou Prometheus exporter (disponível no LiveKit Server OSS e Cloud). A vantagem do LiveKit para medição é a infraestrutura WebRTC nativa: jitter, packet loss e round-trip de rede são métricas nativas da sala, sem instrumentação adicional.
Documentação: LiveKit Agents Observability
Vapi
O Vapi expõe métricas via webhooks de evento de chamada e pela API de call analytics. Os eventos incluem timestamps de início/fim de chamada e de ferramenta/função. Latência de pipeline interno (STT→LLM→TTS) não é exposta diretamente via API pública.
Para medição granular em Vapi, a estratégia é instrumentar o servidor de webhook com timestamps próprios e correlacionar com os eventos da API. O overhead de medição existe porque o Vapi é uma plataforma gerenciada: você não tem acesso ao loop interno do pipeline.
Documentação: Vapi Webhook Events
Conclusão prática: para quem precisa medir latência com granularidade de componente, Pipecat e LiveKit Agents têm vantagem sobre Vapi — não porque são mais rápidos, mas porque expõem mais instrumentação. Vapi compensa com time-to-market e abstração operacional.
6. Onde otimizar primeiro
A sequência de otimização segue a contribuição de cada componente para o P95 total:
1. VAD/EOT — timeout de silêncio
Se você usa threshold de silêncio fixo de 500ms, cada turno paga 500ms de latência constante antes de qualquer processamento começar. Reduzir para 200ms ou usar turn detection semântico (SmartTurn) é a otimização com maior impacto imediato e menor risco.
Cuidado: timeout muito baixo aumenta taxa de interrupções prematuras. Calibre com dados reais de chamada.
2. LLM TTFT — modelo proporcional ao caso de uso
LLM TTFT domina o pipeline na maioria dos casos. Antes de otimizar STT ou TTS, verifique se está usando um modelo proporcional ao contexto necessário. Um roteiro fechado de atendimento ao cliente não precisa de GPT-4o — conforme a tabela de referência da Seção 3 (baseada em Schweiger, AssemblyAI, dez/2025 e Ethiraj et al., arXiv:2508.04721), modelos de 7B como Llama 3.1 8B operam com TTFT de 150–400ms, enquanto modelos grandes via API ficam entre 300–800ms com variabilidade elevada no P95.
3. TTS — streaming e região geográfica
Habilite streaming TTS se ainda não habilitou. A diferença entre enviar texto completo e usar streaming parcial pode ser de 300–800ms em respostas longas. Região importa: usar servidor do ElevenLabs errado adiciona 100–200ms de rede desnecessária.
4. STT — streaming vs. batch
STT streaming já é o padrão nos principais providers (Deepgram, AssemblyAI, Whisper via Groq). Se você ainda usa STT batch (envio de áudio completo pós-EOT), a migração para streaming é prioritária.
7. Quando não otimizar latência
Reduzir latência tem custo: custo financeiro (modelos mais rápidos são mais caros ou piores), custo de qualidade (TTS Flash vs. v3), e custo de complexidade (pipeline paralelo vs. sequencial).
Não otimize latência quando:
O script é fechado e o usuário espera isso. IVR de autenticação por PIN, confirmação de horário de entrega, pesquisa de satisfação com opções numeradas — usuários não percebem 1200ms como lento porque o contexto é transacional. Você vai pagar por otimização que não melhora retenção nem CSAT.
A qualidade do TTS importa mais que a velocidade. Se o diferencial do produto é voz natural e expressiva (narração, assistente de saúde, atendimento premium), o trade-off de qualidade de ElevenLabs v3 vs. Flash pode não valer. Measure first: se P95 está abaixo de 1200ms com voz de alta qualidade, não quebre a voz para ganhar 300ms.
Você ainda não tem dados de produção suficientes. Otimizar P95 com base em testes de staging é otimizar uma distribuição fictícia. P95 de staging não captura variabilidade de rede real, sotaques regionais, ou padrões de fala de usuários reais. Suba para produção com instrumentação, colete pelo menos 1000 chamadas, e então otimize.
O gargalo não é latência, é compreensão. Se o WER (Word Error Rate) do STT está alto para o vocabulário do seu domínio, reduzir latência de pipeline vai entregar respostas rápidas e erradas. Resolver WER primeiro.
A métrica mais importante é a que você ainda não coleta
A maioria dos voice agents em produção não tem instrumentação de P95. Têm logs de chamada com duração total, às vezes latência média, raramente P95 por componente.
A cadência correta: instrumentar → coletar dados reais → identificar o componente gargalo → otimizar esse componente → repetir. Não pular para otimização antes de ter os dados.
O snippet de Pipecat neste artigo é o ponto de entrada para instrumentação por componente. O próximo passo é adaptá-lo para o seu pipeline, coletar pelo menos 100 amostras por componente, e olhar P95 antes de P50.
Se P95 end-to-end estiver acima de 800ms, você sabe onde procurar. Se estiver abaixo, você tem evidência — não só intuição — de que o produto está dentro do threshold de conversação natural.
Bio: Mateus Vidal é engenheiro de software especializado em sistemas de tempo real. Trabalha com Python, infraestrutura de voz e LLMs em produção. Escreve sobre o que aprende testando em produção, não em sandbox.
Fontes e datas de acesso:
– AssemblyAI Blog — “The 300ms rule” (Schweiger, dez/2025) — acessado em 11/05/2026
– Deepgram Docs — Measuring Streaming Latency — acessado em 11/05/2026
– ElevenLabs Docs — Understanding Latency — acessado em 11/05/2026
– arXiv:2508.04721 — Ethiraj et al. (ago/2025) — Toward Low-Latency End-to-End Voice Agents — acessado em 11/05/2026
– arXiv:2604.21406 — Wang et al. (abr/2026) — Full-Duplex Interaction in Spoken Dialogue Systems, ICASSP 2026 HumDial Challenge — acessado em 11/05/2026
– Pipecat SmartTurn — github.com/pipecat-ai/smart-turn — acessado em 11/05/2026