Digitar uma pergunta e ler a resposta é como a maioria das aplicações conversa hoje com um modelo de linguagem. As APIs em tempo real mudam isso. O OpenAI Realtime e o Gemini Live recebem a voz do usuário à medida que ela é falada e respondem com uma voz própria, rápido o suficiente para manter uma conversa. Construir isso à mão significa transmitir áudio nos dois sentidos, decidir quando o usuário terminou, parar o agente quando ele é interrompido e executar tools no meio de tudo isso.
O sgcWebSockets 2026.10 adiciona o TsgcAIVoiceAgent, um componente que faz tudo isso. Ele escuta, detecta quando o usuário terminou um turno, responde por voz e chama suas tools. Está disponível para Delphi 7 a 13 e para .NET.
O TsgcAIVoiceAgent em ação: detecção de turno, barge-in, transcrições ao vivo e chamadas de tools. Também no YouTube.
Início Rápido
Escolha o provedor, defina a chave de API, uma voz e as instruções, trate o OnTranscript e chame Start. Isso já é um assistente de voz funcionando.
oVoice := TsgcAIVoiceAgent.Create(nil);
oVoice.Provider := vapOpenAI;
oVoice.OpenAIOptions.ApiKey := 'API_KEY';
oVoice.OpenAIOptions.Voice := 'alloy';
oVoice.Instructions := 'You are a friendly assistant. Answer briefly.';
oVoice.OnTranscript := oVoiceTranscript;
oVoice.OnError := oVoiceError;
oVoice.Start;
O OnTranscript entrega transcrições ao vivo dos dois lados da conversa, o usuário e o agente, para que a tela possa acompanhar o que está sendo dito:
procedure TForm1.oVoiceTranscript(Sender: TObject;
aRole: TsgcAIVoiceAgentRole; const aText: string; aFinal: Boolean);
begin
if aFinal then
begin
if aRole = varUser then
Memo1.Lines.Add('You: ' + aText)
else
Memo1.Lines.Add('Agent: ' + aText);
end;
end;
OpenAI Realtime ou Gemini Live, WebSocket ou WebRTC
Dois provedores são suportados, OpenAI Realtime e Gemini Live. Trocar de um para outro é uma property e as opções correspondentes:
oVoice.Provider := vapGemini;
oVoice.GeminiOptions.ApiKey := 'GEMINI_API_KEY';
oVoice.Start;
A sessão roda sobre WebSocket. Com a OpenAI, também pode rodar sobre WebRTC:
oVoice.Provider := vapOpenAI;
oVoice.Transport := vatWebRTC;
oVoice.OpenAIOptions.ApiKey := 'API_KEY';
oVoice.Start;
Áudio integrado, ou o seu próprio
No Windows, Android e iOS, o microfone e o alto-falante já vêm integrados, então o início rápido acima é tudo o que você precisa. Em qualquer outra plataforma, ou quando o áudio vem de outro lugar, desligue o dispositivo. Sua aplicação envia áudio com SendAudio e recebe a resposta em OnAudioOutput.
oVoice.Audio.UseDevice := False;
oVoice.Audio.Format := vafPCM16;
oVoice.Audio.SampleRate := 16000;
oVoice.Start;
// ... 20 ms of PCM16 mono at 16 kHz = 640 bytes
SetLength(vChunk, 640);
FillChar(vChunk[0], Length(vChunk), 0);
oVoice.SendAudio(vChunk);
Atendendo o telefone
A telefonia fala G.711, e o agente de voz também. Defina o formato de áudio como mu-law ou A-law a 8 kHz, e os bytes de uma chamada entram e saem direto, sem nenhuma conversão no seu código.
oVoice.Provider := vapOpenAI;
oVoice.OpenAIOptions.ApiKey := 'API_KEY';
oVoice.Instructions := 'You answer the phone of a restaurant and take bookings.';
oVoice.Audio.UseDevice := False;
oVoice.Audio.Format := vafG711ULaw;
oVoice.OnAudioOutput := oVoicePhoneAudioOutput;
oVoice.Start;
procedure TForm1.DoPhoneAudioReceived(const aData: TBytes);
begin
// ... G.711 mu-law, 8 kHz, as it arrives from the RTP stream of the call
oVoice.SendAudio(aData);
end;
procedure TForm1.oVoicePhoneAudioOutput(Sender: TObject;
const aData: TBytes);
begin
// ... already G.711 mu-law at 8 kHz: send it back to the caller
SendToPhone(aData);
end;
Detecção de turno
A detecção de turno decide quando o usuário terminou de falar e o agente deve responder. Existem quatro modos.
- Server VAD deixa o provedor detectar o fim do turno com detecção de atividade de voz.
- Semantic VAD escuta o que está sendo dito, não apenas o silêncio, para que uma pausa no meio de uma frase não corte o usuário.
- Client VAD detecta o turno no cliente.
- Manual é push-to-talk: sua aplicação decide onde o turno termina.
oVoice.TurnDetection.Mode := vtdServerVAD;
oVoice.TurnDetection.Threshold := 0.6;
oVoice.TurnDetection.PrefixPaddingMs := 300;
oVoice.TurnDetection.SilenceDurationMs := 700;
oVoice.TurnDetection.Mode := vtdSemanticVAD;
oVoice.TurnDetection.Eagerness := 'low';
Com push-to-talk, confirme o áudio e peça uma resposta quando o usuário soltar o botão:
procedure TForm1.btnTalkMouseUp(Sender: TObject);
begin
// ... TurnDetection.Mode is vtdManual
oVoice.CommitAudio;
oVoice.CreateResponse;
end;
Barge-in
As pessoas interrompem, e um bom agente de voz permite isso. Com o barge-in, quando o usuário começa a falar o agente para de falar e a resposta é cancelada. A resposta também é truncada até o ponto que o usuário realmente ouviu, para que o histórico da conversa não afirme que o agente disse palavras que nunca chegaram a ser reproduzidas.
oVoice.BargeIn := True;
oVoice.OnTurnStarted := oVoiceTurnStarted;
oVoice.OnTurnEnded := oVoiceTurnEnded;
oVoice.OnBargeIn := oVoiceBargeIn;
procedure TForm1.oVoiceBargeIn(Sender: TObject);
begin
Memo1.Lines.Add('The user interrupted the agent.');
end;
Tools
Um agente de voz se torna útil quando consegue fazer coisas. Declare uma tool com um nome, uma descrição e um schema JSON para seus parâmetros, e responda a ela em OnToolCall.
procedure TForm1.StartWeatherAssistant;
var
oTool: TsgcAIVoiceAgentTool;
begin
oVoice.Provider := vapOpenAI;
oVoice.OpenAIOptions.ApiKey := 'API_KEY';
oVoice.Instructions := 'You are a weather assistant. ' +
'Call get_weather to know the weather of a city before answering.';
oVoice.Tools.Clear;
oTool := oVoice.Tools.Add;
oTool.Name := 'get_weather';
oTool.Description := 'Returns the current weather of a city.';
oTool.Parameters := '{"type":"object","properties":' +
'{"city":{"type":"string","description":"Name of the city"}},' +
'"required":["city"]}';
oVoice.OnToolCall := oVoiceWeatherToolCall;
oVoice.OnTranscript := oVoiceTranscript;
oVoice.Start;
end;
procedure TForm1.oVoiceWeatherToolCall(Sender: TObject;
const aCallId, aName, aArguments: string; var aResult: string;
var aHandled: Boolean);
var
oJSON: TsgcJSON;
vCity: string;
begin
if aName <> 'get_weather' then
Exit; // ... not mine: the MCP client, if any, gets the call
oJSON := TsgcJSON.Create(nil);
Try
oJSON.Read(aArguments);
vCity := '';
if Assigned(oJSON.Node['city']) then
vCity := oJSON.Node['city'].Value;
Finally
oJSON.Free;
End;
// ... replace with a call to your weather service
aResult := '{"city":"' + vCity + '","temperature":21,"sky":"clear"}';
aHandled := True;
end;
As tools também podem vir de um servidor MCP. Atribua um cliente MCP e suas tools são oferecidas ao agente automaticamente:
oMCP := TsgcWSAPIClient_MCP.Create(nil);
oMCP.MCPOptions.HttpOptions.URL := 'https://localhost:5001/mcp';
oVoice.MCPClient := oMCP;
oVoice.Start;
A demo: um assistente de voz para uma loja
A demo em Delphi em Demos\15.AI\02.Applications\09.VoiceAgent é um assistente de loja com quem você conversa. Ela funciona sobre um catálogo de produtos guardado em um TDataSet e dá ao agente quatro tools: find_products para buscar no catálogo, get_product para ler um produto, update_stock para alterar o estoque, e count_low_stock para listar os produtos que precisam de reposição. Pergunte a ela o que está acabando, depois diga para repor um produto, e veja a grade mudar enquanto ela responde.
Disponibilidade
O TsgcAIVoiceAgent chega no sgcWebSockets 2026.10, para Delphi 7 a 13 e para .NET, na edição Enterprise. O restante das novidades da versão está no post do sgcWebSockets 2026.10, e o resto dos componentes de IA está na página de produto de IA.
Leia também
- Extração de Documentos com IA para Delphi e .NET, também novidade na 2026.10
- Um Cliente de Server-Sent Events para Delphi e .NET
Dúvidas ou feedback? Entre em contato. Você receberá uma resposta das pessoas que escreveram o código.
