For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
Navegação principal
25 de mar. de 2026 Áudio

Como a Perplexity levou a pesquisa por voz a milhões de pessoas usando a Realtime API

Lições da criação do agente de voz do Perplexity Computer com a Realtime API.

Autores: Paul Fryzel (Perplexity), Charu Jaiswal (OpenAI)

Como a Perplexity levou a pesquisa por voz a milhões de pessoas usando a Realtime API

Na Perplexity, damos muita importância a criar produtos que sejam incríveis de usar. No Perplexity Comet, nosso navegador agêntico, e no Perplexity Computer, nosso poderoso assistente digital de uso geral, uma parte importante disso foi permitir que tudo pudesse ser feito por voz. Há algo especialmente satisfatório em simplesmente dizer o que você quer, delegar a tarefa e acompanhar a execução. Apostamos na voz como interface porque ela faz a interação parecer um pouco mais mágica.

Usamos o Realtime-1.5 em produção para levar essa magia aos milhões de sessões de voz que a Perplexity gerencia todos os meses. Acompanhar o crescimento do uso de voz pela interface do Computer tem sido incrivelmente empolgante e uma grande fonte de aprendizado. Vamos compartilhar algumas das coisas surpreendentes que aprendemos até agora. Convidamos você a experimentar o Realtime-1.5 e compartilhar conosco o que aprender também.

1. Defina sua estratégia de gerenciamento de contexto

Conteúdos longos, especialmente podcasts densos com várias horas de duração, foram um dos nossos testes mais reveladores de gerenciamento de contexto. Queríamos permitir a consulta de transcrições de podcasts por voz, para que o usuário pudesse começar uma conversa, perguntar o que estava acontecendo em um momento específico, duas horas e meia após o início, e receber uma resposta coerente.

Não dá para colocar a transcrição inteira no contexto. Nossa primeira tentativa foi enviá-la em blocos grandes. Logo descobrimos que as falhas com atualizações grandes seguem uma lógica de tudo ou nada. Se você tentar enviar uma atualização de 10.000 tokens para uma janela que só tem espaço para mais 5.000 tokens, o modelo perderá todo o histórico anterior. Isso tornava os blocos grandes muito mais arriscados, porque uma única atualização grande demais poderia apagar um bloco inteiro de contexto, em vez de permitir que o sistema esquecesse as informações de forma mais gradual.

Então mudamos de abordagem. Em vez de enviar atualizações grandes, começamos a dividir tudo em blocos bem menores, de 2.000 tokens, e a fornecê-los de forma incremental. Isso gera mais sobrecarga, mas o comportamento é muito mais estável. Quando ocorre truncamento, ele remove um pouco do histórico em vez de apagar tudo.

Outra sutileza que aprendemos foi que nem todo contexto deve entrar no modelo da mesma forma. Ao usar conversation.item.create para atualizar o contexto, item.type: "message" tem três papéis: system, user e assistant. Esses papéis indicam ao modelo que tipo de mensagem ele está recebendo. system serve para instruções e para orientar o comportamento, user para entradas do usuário final e assistant para saídas geradas pelo modelo.

Quando errávamos nisso, a interação começava a parecer estranha. Se muito contexto entrava como user, o modelo se comportava como se o usuário estivesse narrando cada bloco de texto, incluindo trechos de páginas da Web e comentários, em vez de simplesmente fazer uma pergunta com base naquele material. Se muito contexto entrava como system, acontecia o contrário. O modelo deixava de distinguir o que já “sabia”, o que havia sido fornecido como contexto e o que o usuário estava de fato perguntando naquele momento.

Os fluxos de navegação são um bom exemplo. À medida que alguém rola uma página, atualizamos continuamente o modelo com o que aparece na tela. Se tudo isso é apresentado como entrada do usuário, o modelo começa a agir como se o usuário tivesse lido cada parágrafo em voz alta. Esse não é o modelo mental adequado. Queremos que o sistema pareça acompanhar a página em segundo plano e responda naturalmente quando o usuário perguntar algo. No fim, isso dependia menos do volume bruto de contexto e mais de acertar a semântica da conversa.

2. Padronize o áudio entre as interfaces dos produtos

A Perplexity tem várias interfaces de produto, como Ask, Comet e Computer. Cada uma é construída com uma stack de cliente diferente. Swift, TypeScript, Rust e C++ podem produzir buffers de áudio nativos diferentes. Quando deixamos cada cliente enviar seu próprio formato de áudio bruto ou nativo à Realtime API, surgiram inconsistências de desempenho.

Acabamos criando um SDK em Rust para abstrair essas diferenças específicas de cada plataforma e garantir que todos os clientes enviassem áudio à API seguindo o mesmo contrato. Na prática, isso significava processar a forma de onda antes mesmo de ela chegar ao servidor: reamostrar para 48 kHz em mono, de acordo com a preferência do codec Opus e a taxa interna do WebRTC, passar o áudio pelo WebRTC APM para cancelamento de eco, controle automático de ganho, redução de ruído e filtragem passa-altas e, por fim, codificá-lo para transporte. O SDK nos deu um único lugar para padronizar as constantes de áudio, fazer a reamostragem e configurar todo o pipeline de processamento, em vez de fazer isso cliente por cliente.

3. Ajuste para as condições do mundo real

É importante ajustar a VAD no ambiente em que os usuários vivem. Isso significa calibrá-la levando em conta microfones reais, o volume dos alto-falantes e o ruído de fundo. Um dos nossos cenários de teste internos era um bar barulhento em São Francisco, porque parecia uma situação real de uso do produto. Alguém diz: “Você já experimentou o novo aplicativo da Perplexity?” O amigo pega o celular e, se a voz falhar, acabamos de perder dois usuários. Quando funciona, a reação é mais próxima de “p**ra, que incrível”. Esse cenário foi útil porque nos obrigou a encarar o problema. O que funciona em condições ideais muitas vezes falha no mundo real. É melhor começar ajustando para ambientes com interferências.

Uma das partes mais difíceis da experiência de voz foi lidar bem com as pausas. As pessoas naturalmente param para pensar, abrir algo na tela ou se preparar para ler alguma coisa em voz alta. O modelo pode facilmente interpretar essa pausa como o fim do turno e responder cedo demais. Vimos isso em situações como alguém pedindo ajuda com uma dedução matemática. A pessoa fazia uma pausa para encontrar a fórmula, e o modelo respondia antes que ela terminasse a pergunta. Foi isso que nos levou à trava de voz. Em vez de usar a abordagem tradicional de pressionar para falar, em que a voz fica desativada por padrão e o usuário precisa pressionar um botão para falar, invertemos a lógica. A interação por voz fica disponível por padrão, mas, quando o usuário quer manter a palavra por um momento, pode travar a voz e assumir o controle do turno. Também vemos isso como algo além de um recurso isolado. À medida que as interfaces de voz passam a fazer parte de fluxos de trabalho mais complexos, acreditamos que alguma versão desse padrão de interação se tornará padrão.

4. Use apenas as ferramentas essenciais e mantenha-as dentro da distribuição esperada pelo modelo

Restrinja o conjunto às poucas ferramentas que mais importam, o que, no nosso caso, significou menos de dez. Focamos em um pequeno conjunto essencial que cobria as ações de maior valor. Essa escolha fez sentido, e esse equilíbrio tende a melhorar à medida que novas versões do modelo evoluírem.

Adicionamos instruções explícitas ao nosso prompt de sistema sobre quando e como cada ferramenta deveria ser chamada. Tivemos o cuidado de manter tanto os esquemas das ferramentas quanto suas saídas dentro da distribuição esperada pelo modelo. Na prática, isso significava formatar as saídas como dados estruturados comuns de ferramentas, em vez de falas do assistente. Retornávamos JSON estruturado com campos claramente separados, como response_text para a fala destinada ao usuário e flags como require_repeat_verbatim para o comportamento, em vez de misturar o conteúdo falado com instruções no mesmo texto. Isso tornou o uso de ferramentas mais estável e manteve o padrão de interação mais próximo do que o modelo provavelmente havia visto durante o treinamento.

// Good:
{
  "response_text": "I kicked-off the task to create a market research dashboard",
  "require_repeat_verbatim": true
}
// Avoid:

I kicked-off the task to create a market research dashboard

# Response Instructions

Read the above instructions EXACTLY as they are

Realtime está pronto

O Realtime-1.5 é um ponto de virada para o setor. Certamente há espaço para melhorar no processamento de contextos longos, no uso de mais ferramentas e em tarefas que exigem mais inteligência. Mas esperamos que os modelos melhorem. Na Perplexity, pensamos em construir hoje para esse futuro. Queremos tornar os sistemas atuais utilizáveis enquanto nos preparamos para a próxima geração de modelos Realtime e as novas experiências de voz que eles vão possibilitar.