Pular para o conteúdo

Agentes de Voz em Tempo Real: a Arquitetura Áudio-para-Áudio

Como os agentes de voz modernos abandonaram o stack ASR→LLM→TTS. Entenda WebSocket full-duplex, VAD server-side e barge-in por baixo dos panos.

Foto de Patrick Cardoso

Patrick Cardoso

Categoria Tecnologia
Agentes de Voz em Tempo Real: a Arquitetura Áudio-para-Áudio
Ilustração Editorial por IA / ai.patrickcardoso.

Por anos, construir um agente de voz significou empilhar três sistemas distintos. A conta da latência sempre estourava no final.

O modelo áudio-para-áudio nativo mudou a equação. Ele não transcreve para depois pensar: ele ouve e fala no mesmo fluxo.

A naturalidade de uma conversa não nasce da velocidade de cada etapa, mas da eliminação das costuras entre elas.

— Patrick Cardoso

O Problema da Arquitetura em Cascata

O padrão histórico era uma pipeline de três estágios: reconhecimento de fala (ASR), modelo de linguagem (LLM) e síntese de voz (TTS).

Cada estágio adiciona a própria latência, e os atrasos se compõem. Segundo a documentação de desenvolvedores do Google, essa cascata torna a interação estruturada e robótica.

Pior: a etapa de ASR joga fora informação acústica. Entonação, ritmo e hesitação viram texto plano antes que o modelo tenha a chance de interpretá-los.

O Colapso do Stack

A arquitetura moderna funde os três estágios em um único transformer. Frames de áudio passam a ser tokens de primeira classe, ao lado de texto e imagem.

O modelo processa a nuance acústica diretamente, sem transcrição intermediária. Conforme relatado pela MarkTechPost sobre o Gemini 3.1 Flash Live, isso reduz a latência e melhora o reconhecimento de pitch e cadência.

DimensãoCascata ASR→LLM→TTSÁudio-para-áudio nativo
LatênciaComposta em 3 etapasÚnica passagem
Informação acústicaPerdida no ASRPreservada
Interrupção (barge-in)Difícil de coordenarNativa no servidor
Complexidade de clienteAlta (orquestrar 3 sistemas)Baixa (um stream)

O Transporte: WebSocket Full-Duplex

Um agente de voz não pode operar em requisições HTTP de turno único. Ele exige uma conexão persistente e bidirecional.

A escolha padrão é um WebSocket stateful (WSS). Tanto a Live API do Google, via endpoint BidiGenerateContent, quanto a Realtime API da OpenAI adotam esse modelo full-duplex.

Os formatos de áudio são crus e específicos. A entrada costuma ser PCM de 16 bits a 16 kHz little-endian; a saída, PCM a 24 kHz. O cliente lida com dois fluxos simultâneos:

import asyncio

async def enviar_microfone(session, mic_queue):
    # Empurra chunks de áudio cru (PCM 16kHz) para o modelo
    while True:
        chunk = await mic_queue.get()
        await session.send_audio(chunk)

async def receber_respostas(session, player):
    # Demultiplexa cada evento do servidor
    async for evento in session.receive():
        if evento.tipo == "tool_call":
            await executar_ferramenta(evento)
        elif evento.tipo == "interrupted":
            player.flush()  # descarta o áudio em buffer
        elif evento.tipo == "audio":
            player.enqueue(evento.pcm)

async def loop(session, mic_queue, player):
    await asyncio.gather(
        enviar_microfone(session, mic_queue),
        receber_respostas(session, player),
    )

VAD e Barge-in: Interromper como Gente

O detalhe que faz a conversa parecer humana é o barge-in: poder cortar o agente no meio da fala. E o segredo está em onde essa decisão acontece.

O servidor roda um Voice Activity Detection (VAD) contínuo sobre o áudio de entrada. É um classificador que estima, quadro a quadro, a probabilidade de haver fala humana.

Como o servidor gera e escuta ao mesmo tempo, ele consegue interromper a própria saída no instante em que detecta a interrupção. Ele então emite um evento interrupted, e o cliente apenas confia no sinal:

# Ativa o VAD server-side (não desabilitar a detecção automática)
config = {
    "automatic_activity_detection": {"disabled": False},
    "input_audio": {"encoding": "pcm16", "sample_rate": 16000},
}

# Quando o servidor detecta fala, ele para de gerar e envia "interrupted".
# O cliente descarta o áudio já bufferizado e a conversa segue limpa.

Colocar o VAD no cliente reintroduz a costura que tentamos eliminar. A autoridade sobre o turno precisa morar no mesmo lugar que gera o áudio.

O Padrão de Facto e Seus Perigos

Com dois grandes protocolos em produção, surgiu uma disputa de padronização. Segundo análise da Zylos Research, o schema de eventos da Realtime API da OpenAI virou o alvo de integração de facto.

Vendors como Inworld e o Grok Voice, da xAI, já expõem endpoints compatíveis. Para o resto, o padrão vencedor é a “adaptação assimétrica”: escrever um adaptador que traduz, por exemplo, o Gemini Live para a superfície da OpenAI.

  • Resampling: conciliar 24 kHz e 16 kHz exige filtro anti-aliasing no adaptador.
  • Transcrição nativa: substitui o ASR sidecar, simplificando o pipeline.
  • Armadilha do “thinking”: um thinkingConfig mal calibrado degrada silenciosamente o barge-in.

Implicação para a Engenharia

Migrar para áudio nativo não é trocar de biblioteca: é mudar de onde vive a autoridade sobre a conversa. Turno, interrupção e nuance acústica saem do cliente e entram no servidor.

O engenheiro que entende essa fronteira constrói agentes que soam humanos. Quem insiste em orquestrar três caixas separadas continuará empacotando latência em cada costura.

Fontes

Tags relacionadas

Compartilhar

Newsletter

Novos posts direto no seu e-mail

Quando publicar algo novo, você recebe primeiro — sem feed, sem algoritmo.

Sem spam. Cancele quando quiser.

Continue lendo

Leituras relacionadas