Engenharia

Construindo Agentes de Voz em Tempo Real com Vision Agents e Amazon Nova 2 Sonic

Introdução

Construir agentes de voz de nível de produção que se sintam naturais e responsivos representa um desafio de engenharia complexo. É necessário orquestrar modelos de fala para fala (speech-to-speech), gerenciar o streaming de áudio de baixa latência e lidar com o ciclo de vida da conexão, tudo isso enquanto oferece experiências consistentes em aplicações web, mobile e desktop.

Neste artigo, Jackson, Engenheiro de Software Sênior e Arquiteto de Soluções da AITY, demonstra como combinar o framework open-source Vision Agents da Stream com Amazon Bedrock e Amazon Nova 2 Sonic para construir agentes de voz em tempo real que podem estar prontos para produção em minutos. Exploraremos a integração técnica, exemplos de código e capacidades avançadas como chamada de função, reconexão automática e suporte de voz multilíngue.

O Desafio

A criação de aplicações de IA habilitadas para voz exige a orquestração de múltiplos sistemas complexos que devem funcionar juntos de forma confiável. Enfrenta-se o desafio de gerenciar a infraestrutura de streaming de áudio em tempo real, enquanto se integra simultaneamente serviços de reconhecimento de fala, modelos de linguagem e serviços de texto para fala. Cada um possui suas próprias características de latência e modos de falha. Uma interação de voz típica envolve:

Tudo isso deve ocorrer em uma janela de algumas centenas de milissegundos para parecer natural. Atrasos nesse pipeline podem quebrar o fluxo conversacional e frustrar os usuários. Além do pipeline central de IA, aplicações de voz em produção precisam lidar com as realidades da implantação no mundo real: conexões de rede não confiáveis, problemas de compatibilidade do navegador, timeouts de sessão e degradação elegante quando os serviços ficam indisponíveis. Muitas vezes, gasta-se mais tempo construindo lógica de reconexão, gerenciando conexões WebRTC e lidando com casos de borda do que nas capacidades reais de IA. O Vision Agents abstrai a complexidade da infraestrutura, proporcionando a flexibilidade para personalizar a experiência de IA.

Visão Geral da Solução

A solução reúne três componentes chave:

Juntos, esses componentes criam uma pilha completa: a Stream lida com o transporte de mídia em tempo real e a experiência do lado do cliente, o Amazon Nova 2 Sonic fornece a inteligência de IA, e o Vision Agents atua como o código "cola" que os une.

Arquitetura do Sistema

O sistema é projetado em torno de uma clara separação de preocupações: a infraestrutura da Stream lida com o transporte de mídia em tempo real e a conectividade do cliente, enquanto o Amazon Nova Sonic é executado na própria conta AWS do cliente e fornece a inteligência de IA. Esta separação ajuda a manter dados sensíveis e lógica de negócios sob o controle do cliente, enquanto a rede de borda globalmente distribuída da Stream oferece a experiência de mídia de baixa latência que os usuários esperam.

A rede de borda da Stream atua como o media broker entre os dispositivos do usuário final e os processos de worker do Vision Agent. Quando um usuário fala, o áudio é capturado, criptografado e transmitido como RTP sobre UDP para a SFU (Selective Forwarding Unit) da Stream mais próxima. A SFU encerra a conexão WebRTC, lida com NAT traversal e estimativa de largura de banda, e encaminha as trilhas de áudio para o worker do Vision Agent como se fosse outro participante da chamada. Isso significa que o agente se integra naturalmente ao modelo de chamada.

Os dados de áudio fluem bidirecionalmente através do sistema: a fala de entrada do usuário é decodificada para PCM bruto pelo worker do Vision Agent, transmitida para o Amazon Nova Sonic via API em tempo real do Bedrock, e os frames de áudio de resposta do Nova Sonic são recodificados, packetizados como RTP e entregues de volta através da SFU para o dispositivo cliente. A latência de ponta a ponta é tipicamente inferior a 500 milissegundos. A detecção de atividade de voz (VAD) é executada no worker para detectar limites de fala e eventos de barge-in, enquanto o cancelamento de eco no navegador ajuda a evitar que a própria saída do agente reative o loop VAD.

As contas da AWS são separadas: * Conta AWS do Cliente: Contém a lógica de negócios e orquestração (políticas do agente, ferramentas, acesso a dados) e a integração com Amazon Bedrock para acessar os modelos Amazon Nova. * Conta AWS da Stream: Gerencia o plano de mídia WebRTC/SFU global, TURN/STUN e sinalização, bem como o runtime do Vision Agent (processos de worker) que encerram o WebRTC como peers robôs e fazem a ponte com a integração do Amazon Bedrock do cliente.

Fluxo de Mídia Ponta a Ponta

  1. Usuário se conecta via web ou mobile.
    • O aplicativo incorpora o SDK de cliente de áudio da Stream, solicita acesso ao microfone (e opcionalmente câmera) e entra em um tipo de chamada configurado para participação de IA.
    • A mídia é enviada como RTP sobre UDP para baixa latência previsível e entrega livre de bloqueio.
  2. Terminação Regional da SFU.
    • Um nó SFU da Stream na região mais próxima encerra a conexão WebRTC do usuário, lidando com estimativa de largura de banda, simulcast e NAT traversal.
    • A SFU encaminha as trilhas de áudio relevantes para o worker do Vision Agent como se fosse outro participante.
  3. Vision Agent Worker.
    • Um processo worker dedicado do Vision Agent mantém o estado da PeerConnection para aquela sessão.
    • Ele decodifica o áudio para PCM bruto e o worker transmite frames PCM para o serviço Amazon Bedrock, encaminhando para o Amazon Nova 2 Sonic como uma sessão em tempo real na conta AWS do cliente.
  4. Amazon Nova 2 Sonic via Amazon Bedrock.
    • O Amazon Nova 2 Sonic detecta limites de fala e realiza modelagem speech-to-speech (compreensão, raciocínio e TTS) com chamadas opcionais de ferramentas para sistemas do cliente (RDS, APIs, bases de conhecimento).
    • Ele lida graciosamente com barge-in e mantém o contexto conversacional completo para que a conversa permaneça natural e coerente.
  5. Streaming da Resposta de Volta ao Usuário.
    • À medida que o Amazon Nova Sonic produz frames de áudio de resposta, o worker do Vision Agent:
      • Fatia e os encapsula em RTP com timestamps monotonicamente crescentes para evitar lacunas/desvios.
      • Envia pacotes RTP através da mesma sessão WebRTC via SFU. A pilha WebRTC do navegador decodifica e reproduz o áudio com latência sub-500ms.
  6. Barge-in, Transcrições e Dados Laterais.
    • O cancelamento de eco no navegador ajuda a evitar que a própria saída do agente reative o VAD.
    • Quando o usuário interrompe, a nova fala dispara um sinal de interrupção via um RTCDataChannel, fazendo com que o worker pare de encaminhar a saída do Amazon Nova Sonic e reinicie seu buffer local.

Primeiros Passos: Construindo Seu Agente de Voz

Esta arquitetura pode parecer complexa, mas o Vision Agents abstrai grande parte dessa complexidade. Vejamos como o código real se apresenta.

Pré-requisitos:

Passo 1: Crie um novo diretório de projeto e instale Vision Agents com o plugin AWS

mkdir voice-agent
cd voice-agent
uv init
uv add "vision-agents[getstream,aws]" python-dotenv

O extra vision-agents[aws] instala o plugin Amazon Bedrock junto com suas dependências, incluindo boto3, aws-sdk-bedrock-runtime e Silero VAD para detecção de atividade de voz.

Passo 2: Configure as variáveis de ambiente

Crie um arquivo .env na raiz do seu projeto para gerenciar sua configuração. Para credenciais AWS, recomendamos apontar para seu AWS_PROFILE neste arquivo para que o aplicativo possa acessar suas credenciais ao interagir com os recursos da AWS. Não recomendamos armazenar suas chaves de acesso AWS diretamente neste arquivo.

Para credenciais da API Stream, você pode usar uma biblioteca de terceiros como HashiCorp Vault ou AWS Secrets Manager, mas considerações de segurança não estão no escopo deste post.

# Stream API credentials
STREAM_API_KEY=test/geststream/api_key
STREAM_API_SECRET=test/getstream/api_secret

# AWS credentials
AWS_PROFILE=your_aws_profile_name
AWS_REGION=us-east-1

O Vision Agents descobre automaticamente essas variáveis de ambiente na inicialização, então você não precisa passá-las explicitamente para cada cliente.

Passo 3: Construa seu primeiro agente de voz

Crie um arquivo main.py com o seguinte código:

import asyncio
from dotenv import load_dotenv
from vision_agents.core import Agent, User, Runner
from vision_agents.core.agents import AgentLauncher
from vision_agents.plugins import aws, getstream

load_dotenv()

async def create_agent(**kwargs) -> Agent:
    agent = Agent(
        edge=getstream.Edge(),
        agent_user=User(name="Helpful Assistant", id="agent"),
        instructions="You are a helpful voice assistant. Be concise and friendly.",
        llm=aws.Realtime(
            model="amazon.nova-2-sonic-v1:0",
            region_name="us-east-1",
            voice_id="matthew",
        ),
    )
    return agent

async def join_call(agent: Agent, call_type: str, call_id: str, **kwargs) -> None:
    call = await agent.create_call(call_type, call_id)
    async with agent.join(call):
        await asyncio.sleep(2)
        await agent.llm.simple_response(
            text="Greet the user warmly and ask how you can help."
        )
        await agent.finish() # Run until the call ends

if __name__ == "__main__":
    Runner(AgentLauncher(create_agent=create_agent, join_call=join_call)).cli()

Passo 4: Execute o agente de voz

Execute o agente:

uv run main.py run

Em menos de 30 linhas de código, você tem um agente de voz totalmente funcional, em tempo real, alimentado pelo Amazon Nova Sonic, acessível a partir de um SDK de cliente Stream.

Integração com Amazon Bedrock: Detalhes Técnicos

Vamos analisar mais de perto como o plugin aws.Realtime funciona internamente.

Streaming Bidirecional com Amazon Nova 2 Sonic

O Amazon Nova 2 Sonic usa uma API de streaming bidirecional orientada a eventos. Em vez de usar um padrão de solicitação-resposta, essa abordagem permite que o áudio flua de forma quase contínua em ambas as direções simultaneamente. O plugin Vision Agents AWS gerencia essa complexidade através de uma sequência de eventos estruturada:

Cada bloco de conteúdo segue um padrão de três partes: contentStartpayload de conteúdo → contentEnd. Essa estrutura hierárquica permite que o modelo mantenha o contexto adequado durante toda a interação.

Aqui está como o evento de início de sessão aparece no plugin:

def _create_session_start_event(self) -> Dict[str, Any]:
    return {
        "event": {
            "sessionStart": {
                "inferenceConfiguration": {
                    "maxTokens": 1024,
                    "topP": 0.9,
                    "temperature": 0.7,
                }
            },
            "turnDetectionConfiguration": {
                "endpointingSensitivity": "MEDIUM"
            },
        }
    }

Adicionando Chamada de Função (Function Calling)

Uma das principais capacidades do Amazon Nova 2 Sonic é a chamada de função nativa durante conversas em tempo real. Isso permite que seu agente de voz execute ações como consultar bancos de dados, chamar APIs e acionar fluxos de trabalho, mantendo uma conversa natural.

Use o decorador @llm.register_function para definir funções que o modelo pode chamar:

import asyncio
from dotenv import load_dotenv
from typing import Dict, Any
from vision_agents.core import Agent, User, Runner
from vision_agents.core.agents import AgentLauncher
from vision_agents.plugins import aws, getstream

load_dotenv()

async def create_agent(**kwargs) -> Agent:
    agent = Agent(
        edge=getstream.Edge(),
        agent_user=User(name="Weather Assistant", id="agent"),
        instructions="""You are a helpful weather assistant. When users ask
about weather, use the get_weather function to fetch current conditions.
You can also help with simple calculations.""",
        llm=aws.Realtime(
            model="amazon.nova-2-sonic-v1:0",
            region_name="us-east-1",
        ),
    )

    @agent.llm.register_function(
        name="get_weather",
        description="Get the current weather for a given city"
    )
    async def get_weather(location: str) -> Dict[str, Any]:
        # In production, call a real weather API
        return {
            "city": location,
            "temperature": 72,
            "condition": "Sunny",
            "humidity": "45%"
        }

    @agent.llm.register_function(
        name="calculate",
        description="Perform a mathematical calculation"
    )
    def calculate(operation: str, a: float, b: float) -> dict:
        operations = {
            "add": lambda x, y: x + y,
            "subtract": lambda x, y: x - y,
            "multiply": lambda x, y: x * y,
            "divide": lambda x, y: x / y if y != 0 else None,
        }
        result = operations.get(operation, lambda x, y: None)(a, b)
        return {"operation": operation, "a": a, "b": b, "result": result}
    return agent

async def join_call(agent: Agent, call_type: str, call_id: str, **kwargs) -> None:
    await agent.create_user()
    call = await agent.create_call(call_type, call_id)
    async with agent.join(call):
        await asyncio.sleep(2)
        await agent.llm.simple_response(
            text="Greet the user and let them know you can check the weather."
        )
        await agent.finish()

if __name__ == "__main__":
    Runner(AgentLauncher(create_agent=create_agent, join_call=join_call)).cli()

Como funciona a chamada de função com Amazon Nova 2 Sonic:

Quando o modelo decide invocar uma função, a seguinte sequência ocorre:

Você pode construir fluxos de trabalho complexos e de várias etapas com esta abordagem. Por exemplo, um agente de voz poderia procurar um registro de cliente, verificar o inventário e fazer um pedido, tudo dentro de uma única conversa natural.

Opções Avançadas de LLM e TTS

Além do speech-to-speech em tempo real, o plugin AWS também oferece uma integração padrão de LLM via aws.LLM. Isso é útil para arquiteturas de pipeline personalizadas onde você deseja emparelhar um modelo Amazon Bedrock com provedores de STT e TTS separados:

from vision_agents.core import Agent, User
from vision_agents.plugins import aws, getstream, cartesia, deepgram, smart_turn

agent = Agent(
    edge=getstream.Edge(),
    agent_user=User(name="Custom Pipeline Agent"),
    instructions="Be helpful and concise.",
    llm=aws.LLM(
        model="anthropic.claude-3-haiku-20240307-v1:0",
        region_name="us-east-1"
    ),
    tts=cartesia.TTS(),
    stt=deepgram.STT(),
    turn_detection=smart_turn.TurnDetection(
        buffer_duration=2.0,
        confidence_threshold=0.5
    ),
)

O LLM padrão suporta streaming de respostas via converse_stream(), gerenciamento completo do histórico de conversas, entradas de visão para modelos como Claude e chamada de ferramentas multi-rodada com até 3 rodadas de execução de função por solicitação.

Text-to-speech com Amazon Polly

Para arquiteturas de pipeline personalizadas, o plugin AWS também inclui uma integração TTS do Amazon Polly. Isso é útil quando você está usando um LLM não em tempo real (como Claude no Amazon Bedrock ou outro provedor) e precisa de síntese de voz de alta qualidade:

from vision_agents.plugins import aws

tts = aws.TTS(
    region_name="us-east-1",
    voice_id="Joanna",
    engine="neural", # 'standard' or 'neural'
    language_code="en-US"
)

O Amazon Polly TTS suporta motores padrão e neurais, entrada SSML para controle de fala granular e múltiplos idiomas e vozes. O motor neural produz fala com som mais natural, tornando-o uma excelente escolha ao construir um pipeline STT → LLM → TTS personalizado na infraestrutura AWS.

Limpeza de Recursos

Para deletar a chamada da Stream e encerrar os processos do Vision Agent em execução:

uv run main.py stop

Importante: Cobranças do Amazon Bedrock se aplicam a todas as chamadas de API para o Amazon Nova 2 Sonic. Você pode executar o comando de limpeza para encerrar as sessões e evitar cobranças contínuas. Sessões ativas podem continuar a incorrer em custos até serem explicitamente encerradas.

Casos de Uso Práticos

Com a fundação técnica estabelecida, vale a pena explorar onde essas capacidades se traduzem em impacto significativo no mundo real. A combinação de voz de baixa latência, gerenciamento de conversas e integração de ferramentas abre uma ampla gama de aplicações em indústrias onde a interação falada natural pode substituir ou aumentar as interfaces tradicionais.

Conclusão

Este artigo detalhou como construir agentes de voz em tempo real usando o framework Vision Agents da Stream e o Amazon Bedrock com Amazon Nova 2 Sonic. Cobrimos a arquitetura, o protocolo de streaming bidirecional, o tratamento de reconexão automática, a chamada de função, o suporte multilíngue e a implantação em produção.

A combinação da rede de borda de baixa latência da Stream e das capacidades nativas de speech-to-speech do Amazon Nova Sonic fornece uma base sólida para a construção de aplicações de IA de voz. O framework Vision Agents abstrai a orquestração complexa do gerenciamento do ciclo de vida da conexão, codificação de áudio, reconexão sensível ao VAD e execução de ferramentas, para que você possa se concentrar na lógica do seu agente e na experiência do usuário.

Se você está pronto para explorar ainda mais, encorajamos você a tentar estender seu agente com funções personalizadas para seu caso de uso específico ou explorar as capacidades multilíngues para aplicações globais. O repositório Vision Agents em https://github.com/GetStream/Vision-Agents é um bom ponto de partida. Lá você encontrará exemplos adicionais, documentação de plugins e discussões da comunidade. Para detalhes de integração mais aprofundados, a documentação do plugin AWS está disponível em https://visionagents.ai/integrations/aws-bedrock, e a documentação do Amazon Nova 2 Sonic no AWS Nova User Guide fornece uma referência abrangente para a API de streaming bidirecional. Você pode se inscrever para uma conta de desenvolvedor da Stream em https://getstream.io/ e começar a construir hoje mesmo sem custo adicional.

Comentários

Interações
Seu Perfil

Aguardando Login...