Introdução
A conversa em tempo real estabelece uma conexão persistente via WebSocket (um protocolo que mantém uma conexão duradoura e bidirecional entre o cliente e o servidor), envia seu áudio ou texto ao modelo de conversa em tempo real e o modelo devolve texto e voz de forma incremental. É adequada para assistentes de voz, perguntas e respostas em tempo real, prática de fala e outros cenários que exigem interação de ida e volta. Assim como a transcrição em tempo real, ela funciona sobre WebSocket, mas os usos são diferentes:
Modelo disponível:
- gpt-realtime-2.1: modelo de conversa por voz, suporta entrada de áudio e texto e produz respostas de texto e voz em tempo real.
Início rápido
Endpoint de conexão
model=gpt-realtime-2.1: obrigatório, o modelo é fixado no momento da conexão pelo parâmetro da URL e não pode mais ser alterado durante a sessão (veja as restrições abaixo).- Atenção à diferença em relação à transcrição: o endpoint de conversa não leva
intent=transcription.
Autenticação
Envie a chave em um cabeçalho HTTP padrão durante o handshake:Requisitos de formato de áudio
O áudio de entrada e de saída suporta atualmente apenas um formato. Converta seu áudio antes de enviar:- Codificação: PCM16 (inteiro com sinal de 16 bits, little-endian)
- Taxa de amostragem: 24000 Hz
- Canais: mono
audio/pcm@24000. Declarar outro formato (como G.711/µ-law) na entrada ou na saída é rejeitado e encerra a sessão.
Diferente da transcrição, as sessões de conversa suportam detecção de atividade de voz (turn_detection / VAD). Quando ativada, o modelo determina automaticamente o fim de uma fala e dispara uma resposta; quando desativada (valor
null), você controla quando confirmar o áudio e quando solicitar uma resposta. Escolha conforme a necessidade.Configuração da sessão (session.update)
Após a conexão ser estabelecida, o cliente pode enviar um quadrosession.update para configurar parâmetros da conversa (voz, instruções do sistema, se o VAD está ativo). O modelo da sessão de conversa já está ancorado pela URL de conexão, portanto você pode conversar sem enviar session.update; envie quando precisar de uma voz ou instruções personalizadas.
Parâmetros de configuração
string
obrigatório
Tipo de sessão,
realtime para o cenário de conversa.string
Instruções do sistema que definem o papel, o tom e as restrições de resposta do modelo.
string[]
Modalidades de saída,
["audio"] ou ["text"]: com ["audio"] (padrão) o modelo gera voz e o texto da resposta chega pelo evento response.output_audio_transcript.delta; com ["text"] ele gera apenas texto, entregue por response.output_text.delta. Qualquer outra combinação (por exemplo ["audio", "text"]) é rejeitada e retorna um evento error.object
obrigatório
Formato do áudio de entrada, fixado em
{ "type": "audio/pcm", "rate": 24000 }.object | null
Detecção de atividade de voz. Envie
{ "type": "server_vad" } para ativar a detecção automática de turnos; envie null para desativá-la e confirmar o áudio e solicitar respostas manualmente pelo cliente.object
obrigatório
Formato do áudio de saída, fixado em
{ "type": "audio/pcm", "rate": 24000 }.string
Voz da resposta de áudio. Ela não pode ser alterada depois do início da primeira resposta: quando a sessão entra em estado de geração, um
voice enviado novamente é ignorado (os demais ajustes continuam valendo). Portanto, se precisar de uma voz específica, defina-a antes de solicitar a primeira resposta.As capacidades a seguir não são suportadas nesta versão e fecham a sessão quando configuradas (código de fechamento
1008): ativar a transcrição embutida dentro de uma sessão de conversa (audio.input.transcription, motivo input_transcription_not_supported), injetar áudio (motivo item_audio_not_supported) ou imagens (motivo image_input_not_supported) pelos itens de conversa, e qualquer tipo de item de conteúdo diferente de texto (motivo unsupported_content_part). Envie todo o áudio pelo canal input_audio_buffer.append.Envio de entrada
Envio de áudio
Divida o áudio PCM16 em pequenos fragmentos (por exemplo, um a cada 100 ms), codifique-os em base64 e envie-os continuamente com o eventoinput_audio_buffer.append:
Envio de texto
Você também pode injetar diretamente uma mensagem de texto e então solicitar uma resposta:Recebimento de respostas
O servidor continua enviando eventos. Tipos de evento principais:event
Confirmação de que a sessão foi criada ou de que sua configuração foi atualizada. Você pode começar a enviar áudio e texto ao receber
session.created.event
Um item de conversa foi gravado: cada entrada do usuário e cada resposta do modelo adicionam um item.
event
Com a VAD ativada, o servidor detectou que o usuário começou ou parou de falar. Um evento
speech_started geralmente significa que o usuário está interrompendo o modelo; consulte Interrupção e truncamento.event
Uma resposta começou a ser gerada.
event
O item de saída da resposta começou e terminou. O campo
item.id do evento added é o ID do item de conversa que você referencia ao truncar o áudio depois.event
Um trecho incremental do áudio da resposta (PCM16 codificado em base64) e sua marca de fim, que você pode reproduzir conforme chega.
event
A transcrição incremental correspondente ao áudio da resposta, frase por frase, e sua marca de fim; o campo
delta contém o texto adicionado. Quando a saída inclui áudio, obtenha o texto da resposta neste evento, por exemplo para exibir legendas enquanto o áudio é reproduzido.event
Um trecho incremental de uma resposta somente texto e sua marca de fim, emitidos apenas quando a modalidade de saída é somente texto (
output_modalities: ["text"]).event
Uma resposta terminou. Este evento carrega o uso de tokens do turno (
usage), que é a base da cobrança.event
Confirmação de que a solicitação de truncamento teve efeito; consulte Interrupção e truncamento.
event
Evento de erro, com código e descrição. Um problema da própria solicitação (por exemplo um valor
output_modalities inválido) retorna um único evento error e a sessão continua utilizável; questões de política (troca de modelo, saldo esgotado) fecham a sessão.Escolha o evento certo para o texto da resposta. Por padrão (saída com áudio) o modelo envia apenas
response.output_audio_transcript.delta e não envia response.output_text.delta; defina a modalidade de saída como somente texto e o texto passa para response.output_text.delta. Escute os dois em qualquer um dos modos para não perder texto (veja a saída medida abaixo).Interrupção e truncamento
Quando o usuário começa a falar enquanto o modelo fala, o conteúdo já gerado mas ainda não reproduzido entra em conflito com a próxima frase do usuário. Em uma conexão WebSocket a reprodução é responsabilidade do cliente, então o cliente também conclui a limpeza após uma interrupção. Com a VAD ativada, o servidor enviainput_audio_buffer.speech_started assim que detecta que o usuário começou a falar. Ao receber esse evento, o cliente deve:
- Parar imediatamente a reprodução local e registrar até onde a resposta já havia sido reproduzida (em milissegundos).
- Enviar
conversation.item.truncatepara remover da conversa o áudio não reproduzido, para que o modelo não o trate como dito no turno seguinte.
item_id: o ID do item de conversa desta resposta, obtido deitem.idno eventoresponse.output_item.added.content_index: o índice da parte de conteúdo de áudio, sempre0.audio_end_ms: o comprimento de áudio a manter, em milissegundos, conforme a posição realmente reproduzida pelo cliente.
conversation.item.truncated quando a solicitação é processada. O truncamento afeta apenas o áudio desta resposta e a transcrição correspondente; a sessão não é afetada e você pode seguir para o próximo turno. Com o SDK da OpenAI, chame conn.conversation.item.truncate(item_id=..., content_index=0, audio_end_ms=...).
Com a VAD desativada (por exemplo, apertar para falar), o toque no botão é a interrupção: envie response.cancel para cancelar a resposta em andamento e trunque conforme descrito acima; ao soltar, envie input_audio_buffer.append, input_audio_buffer.commit e response.create nessa ordem.
Exemplos completos
Abaixo são mostradas três abordagens; escolha uma:- SDK oficial da OpenAI (recomendado): sem precisar escrever os quadros WebSocket à mão; aponte
websocket_base_url(o parâmetro de URL base de WebSocket do SDK) para o gateway e reutilize a biblioteca oficial. - SDK oficial da OpenAI Agents: a forma de voz em tempo real do framework de agentes oficial; troque a
urldemodel_configpelo endereço do gateway. - websockets puro: sem SDK, troque quadros diretamente conforme o protocolo. Menos dependências e mais fácil de depurar.
Por que passar o nome do modelo na conexão? O gateway da AiHubMix precisa do
model no momento do handshake WebSocket para selecionar o provedor de modelos, autenticar e reservar cota, enquanto o session.update chega apenas depois que o handshake termina. Por isso, com um SDK você deve passar model explicitamente para connect() (o SDK o insere na consulta da URL); sem ele, o gateway rejeita durante o handshake e nenhuma conexão é estabelecida. Diferente da transcrição, o endpoint de conversa não precisa de intent=transcription.Reutilizar exemplos oficiais
A maioria dos exemplos de conversa em tempo real publicados pela OpenAI depende apenas do parâmetro de URL base do SDK, então você pode reutilizá-los apontando o endereço para o endpoint da AiHubMix:Saída medida (em produção)
A seguir está o resultado real do exemplo do SDK da OpenAI no ambiente de produçãoaihubmix.com com o modelo gpt-realtime-2.1. A sessão ativa server_vad, e tanto os prompts quanto o áudio estão em inglês.
Entrada de texto
Confirmação medida: por padrão (saída com áudio) o texto da resposta chega caractere por caractere apenas por
response.output_audio_transcript.delta, e response.output_text.delta nunca aparece; o response.done carrega o usage do turno; o handshake leva de 2 a 4 segundos, o custo da reserva de cota ao estabelecer a sessão.Cobrança
- Cobrança por token: uma sessão de conversa devolve o uso de tokens de cada turno (
usage) com o eventoresponse.done, e a cobrança se baseia nele. O uso é medido separadamente por componente, incluindo entrada de áudio, saída de áudio, entrada de texto e saída de texto. O preço unitário de cada componente segue o preço exibido em tempo real na página de detalhes do modelo. - Liquidação conforme o uso: esta é uma conexão de longa duração, e os valores são descontados em tempo real a cada turno durante a sessão, sem uma liquidação única no final. Ao estabelecer a sessão é feita primeiro uma reserva de cota de aproximadamente um minuto de uso (apenas uma verificação de admissão, não uma cobrança real), e a reserva restante é liberada ao final da sessão. Portanto, o saldo disponível da sua conta precisa cobrir pelo menos cerca de um minuto de uso para que a sessão seja estabelecida.
- Cada registro de cobrança de conversa em tempo real pode ser consultado item por item em Uso e faturamento.
Limites e restrições
- Duração da sessão: uma conexão WebSocket dura no máximo 62 minutos, após o que o servidor a encerra (código de fechamento
1000, motivosession_duration_limit); divida em segmentos se precisar de mais tempo. - Desconexão por inatividade: quando nem o cliente nem o modelo têm atividade por 5 minutos, o servidor fecha a sessão (código de fechamento
1008, motivoidle_timeout). A atividade de qualquer um dos lados reinicia o cronômetro, então uma resposta longa que continua sendo transmitida não é interrompida. - Saldo insuficiente: ao estabelecer a sessão, se o saldo disponível não cobrir a reserva de aproximadamente um minuto, o handshake é rejeitado de imediato (HTTP 403) e nenhuma sessão é estabelecida; durante a sessão, se o saldo se esgotar, a conexão estabelecida é encerrada imediatamente.
- Somente no lado do servidor: conexões diretas do navegador não são suportadas (o cabeçalho
Originé validado); integre a partir do seu servidor. - Modelo fixado: o modelo é fixado na URL de conexão, e alterá-lo com
session.updatedurante a sessão é rejeitado e encerra a sessão. - Formato fixado: o áudio de entrada e de saída suporta apenas
audio/pcm@24000mono; outros formatos são rejeitados. - Voz fixada: o
voicenão pode ser alterado depois do início da primeira resposta; defina-o antes de solicitar a primeira resposta. - Não suportado: a transcrição embutida dentro de uma sessão de conversa, a injeção de conteúdo de áudio ou imagem pelos itens de conversa e qualquer tipo de item de conteúdo diferente de texto.
- Uma resposta por vez: uma sessão permite apenas uma resposta em andamento; enviar outro
response.createantes de o turno atual terminar é rejeitado e fecha a sessão (código de fechamento1008, motivoresponse_already_active).
Erros comuns
Última atualização: 2026-09-21