Agentes de voz em tempo real com Stream Vision Agents e Amazon Nova 2 Sonic

O desafio de construir agentes de voz para produção

Criar aplicações de voz com Inteligência Artificial (IA) que pareçam naturais e responsivas é um dos desafios de engenharia mais complexos no ecossistema de nuvem atual. Não basta conectar um modelo de linguagem a um microfone — é preciso orquestrar reconhecimento de fala, modelos de linguagem, síntese de voz e transporte de áudio em tempo real, tudo isso dentro de uma janela de poucos centenas de milissegundos para que a conversa flua de forma natural.

Além do pipeline de IA em si, aplicações de voz em produção precisam lidar com conexões de rede instáveis, compatibilidade entre navegadores, timeouts de sessão e reconexão automática. Na prática, as equipes acabam gastando mais tempo construindo essa infraestrutura do que desenvolvendo as capacidades de IA em si.

É exatamente esse problema que a solução apresentada pela AWS em parceria com a Stream busca resolver, combinando o framework Vision Agents com o Amazon Nova 2 Sonic via Amazon Bedrock.

Os três componentes da solução

A arquitetura proposta é composta por três peças principais que trabalham em conjunto:

  • Amazon Nova 2 Sonic: modelo de fundação do tipo fala-para-fala (speech-to-speech), disponível via Amazon Bedrock. Ele aceita áudio como entrada e produz áudio como saída, eliminando a necessidade de serviços separados de Reconhecimento Automático de Fala (STT — Speech-to-Text) e Síntese de Texto para Fala (TTS — Text-to-Speech). Oferece detecção nativa de turnos de conversa, streaming bidirecional em tempo real e chamada de funções (function calling).
  • Vision Agents (Stream): framework Python open-source para construir agentes de voz e vídeo em tempo real. Conta com arquitetura baseada em plugins, mais de 25 integrações, ferramentas de deploy para produção e SDKs de cliente para React, iOS, Android, Flutter e React Native.
  • Rede de borda (edge) da Stream: rede globalmente distribuída que entrega tempos de entrada tipicamente abaixo de 500ms e latência de áudio inferior a 30ms, funcionando como camada de transporte de mídia em tempo real entre clientes e o backend do agente.

Como a arquitetura funciona

O design do sistema é construído em torno de uma separação clara de responsabilidades: a infraestrutura da Stream cuida do transporte de mídia em tempo real e da conectividade com os clientes, enquanto o Amazon Nova Sonic roda na conta AWS do próprio cliente, mantendo dados sensíveis e lógica de negócio sob seu controle.

Diagrama de arquitetura da solução com Stream Edge Network e conta AWS do cliente
Imagem original — fonte: Aws

O fluxo de mídia ponta a ponta funciona assim: o usuário se conecta via web ou mobile, e o áudio capturado pelo microfone é transmitido como Protocolo de Transporte em Tempo Real (RTP — Real-time Transport Protocol) sobre UDP até o nó de Unidade de Encaminhamento Seletivo (SFU — Selective Forwarding Unit) mais próximo da Stream. O SFU encerra a conexão WebRTC e repassa as faixas de áudio para o processo worker do Vision Agents, que decodifica o áudio para Modulação por Código de Pulso (PCM — Pulse Code Modulation) bruto e o transmite ao Amazon Nova 2 Sonic via API em tempo real do Bedrock. As respostas de áudio geradas pelo Nova Sonic percorrem o caminho inverso, chegando ao dispositivo do usuário com latência ponta a ponta tipicamente inferior a 500ms.

A detecção de atividade de voz (VAD — Voice Activity Detection) roda no worker para identificar os limites da fala e eventos de interrupção (barge-in). O cancelamento de eco no navegador impede que o áudio do próprio agente redispare o VAD.

Começando na prática

Pré-requisitos

Para começar, são necessários: credenciais AWS configuradas (via variáveis de ambiente, perfil da Interface de Linha de Comando (CLI — Command Line Interface) da AWS ou função IAM), uma conta Stream com chave e segredo da API de Áudio, Python 3.12 ou superior, o gerenciador de pacotes uv e o Vision Agents instalado.

Passo 1: Criar o projeto e instalar as dependências

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

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

Passo 2: Configurar variáveis de ambiente

Crie um arquivo .env na raiz do projeto. Para credenciais AWS, a recomendação é apontar para o perfil AWS via AWS_PROFILE, evitando armazenar chaves de acesso diretamente no arquivo.

# 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

Passo 3: Construir o primeiro agente de voz

Com menos de 30 linhas de código Python, é possível ter um agente de voz totalmente funcional em tempo real, alimentado pelo Amazon Nova Sonic:

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: Executar o agente

uv run main.py run

Como funciona a integração com o Amazon Bedrock

O Amazon Nova 2 Sonic utiliza uma API de streaming bidirecional orientada a eventos. Em vez do padrão requisição-resposta, essa abordagem permite que o áudio flua continuamente em ambas as direções de forma simultânea. O plugin AWS do Vision Agents gerencia essa complexidade por meio de uma sequência estruturada de eventos:

  • Inicialização da sessão: um evento sessionStart é enviado com a configuração de inferência (temperatura, máximo de tokens, top-p).
  • Configuração do prompt: um evento promptStart define o formato de saída de áudio (PCM a 24kHz), a voz selecionada e as definições de ferramentas.
  • Instruções do sistema: enviadas como bloco de conteúdo de texto com o papel SYSTEM.
  • Streaming de áudio: frames de áudio do microfone (~32ms cada) são transmitidos como eventos audioInput.
  • Streaming de resposta: o Nova Sonic retorna eventos audioOutput com a fala gerada.
  • Encerramento da sessão: eventos promptEnd e sessionEnd fecham a conexão de forma limpa.

Cada bloco de conteúdo segue um padrão de três partes: contentStart → payload do conteúdo → contentEnd. Essa estrutura hierárquica permite que o modelo mantenha o contexto adequado ao longo da interação.

Adicionando chamada de funções (function calling)

Uma das capacidades mais relevantes do Amazon Nova 2 Sonic é a chamada de funções nativa durante conversas em tempo real. Isso permite que o agente de voz execute ações como consultar bancos de dados, chamar APIs e disparar fluxos de trabalho enquanto mantém uma conversa falada natural. O decorator @agent.llm.register_function é usado para definir as funções disponíveis ao modelo:

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()

Quando o modelo decide invocar uma função, o Nova 2 Sonic emite um evento toolUse com o nome da função e os argumentos. O plugin do Vision Agents intercepta esse evento, desserializa os argumentos, executa a função Python registrada e devolve o resultado via evento toolResult. O modelo então incorpora o resultado em sua resposta falada de forma natural.

Integrações adicionais do plugin AWS

Além do modo de fala-para-fala em tempo real, o plugin AWS do Vision Agents também oferece integração com modelos padrão via aws.LLM. Isso é útil para arquiteturas de pipeline customizadas que combinam um modelo do Amazon Bedrock com provedores separados de STT e TTS:

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
    ),
)

Para síntese de voz em pipelines customizados, o plugin também inclui integração com o Amazon Polly via aws.TTS, com suporte a motores padrão e neural, entrada em Linguagem de Marcação de Síntese de Fala (SSML — Speech Synthesis Markup Language) para controle fino da fala, e múltiplos idiomas e vozes.

Casos de uso relevantes

Interfaces de voz em ambientes sem tela

A combinação do Vision Agents com o Amazon Nova 2 Sonic é especialmente adequada para contextos onde os usuários não podem interagir com uma tela — como direção, serviços de campo, logística, saúde ou operações no local. Nesses cenários, a voz se torna a interface principal. O agente mantém o contexto ao longo da conversa, permitindo comandos de acompanhamento sem repetição de informações. Por exemplo, um motorista de entrega pode perguntar “Qual é minha próxima parada?”, receber as instruções faladas, dizer “Marcar a última entrega como concluída” e em seguida “Chamar o despachante”, tudo sem tocar na tela.

Suporte telefônico de alto volume em escala

O Vision Agents combinado ao Amazon Nova 2 Sonic também é projetado para lidar com grandes volumes de chamadas de suporte, onde agentes humanos se tornam um gargalo. Em horários de pico, centenas de clientes podem ligar com a mesma dúvida. Em vez de aguardar na fila, os chamadores são atendidos imediatamente por um agente de voz que consulta o status do pedido, explica o problema, oferece próximos passos e só encaminha para um agente humano quando necessário — transformando o sistema telefônico em uma camada de resolução contínua.

Limpeza de recursos

Para encerrar a chamada Stream e 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 ao Amazon Nova 2 Sonic. Sessões ativas podem continuar gerando custos até serem explicitamente encerradas.

Para explorar mais

O repositório do Vision Agents em https://github.com/GetStream/Vision-Agents é um bom ponto de partida, com exemplos adicionais, documentação de plugins e discussões da comunidade. Para detalhes de integração mais profundos, a documentação do plugin AWS está disponível em https://visionagents.ai/integrations/aws-bedrock. É possível criar uma conta de desenvolvedor Stream em https://getstream.io/ e começar a construir sem custo adicional.

Fonte

Real-time voice agents with Stream Vision Agents and Amazon Nova 2 Sonic (https://aws.amazon.com/blogs/machine-learning/real-time-voice-agents-with-stream-vision-agents-and-amazon-nova-2-sonic/)

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *