Escribir una pregunta y leer la respuesta es como la mayoría de las aplicaciones hablan hoy con un modelo de lenguaje. Las API en tiempo real cambian eso. OpenAI Realtime y Gemini Live toman la voz del usuario según se pronuncia y responden con una voz propia, lo bastante rápido como para sostener una conversación. Llegar ahí a mano significa transmitir audio en ambas direcciones, decidir cuándo el usuario ha terminado, detener al agente cuando lo interrumpen y ejecutar herramientas en medio de todo eso.
sgcWebSockets 2026.10 añade TsgcAIVoiceAgent, un componente que hace todo eso. Escucha, detecta cuándo el usuario ha terminado un turno, responde y llama a tus herramientas. Está disponible para Delphi 7 a 13 y para .NET.
TsgcAIVoiceAgent en acción: detección de turnos, barge-in, transcripciones en vivo y llamadas a herramientas. También en YouTube.
Inicio rápido
Elige el proveedor, establece la clave de API, una voz y las instrucciones, gestiona OnTranscript y llama a Start. Eso ya es un asistente 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;
OnTranscript entrega transcripciones en vivo de ambos lados de la conversación, el usuario y el agente, para que la pantalla pueda seguir lo que se está diciendo:
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 o Gemini Live, WebSocket o WebRTC
Se admiten dos proveedores, OpenAI Realtime y Gemini Live. Cambiar de uno a otro es una propiedad y las opciones correspondientes:
oVoice.Provider := vapGemini;
oVoice.GeminiOptions.ApiKey := 'GEMINI_API_KEY';
oVoice.Start;
La sesión se ejecuta sobre WebSocket. Con OpenAI también puede ejecutarse sobre WebRTC:
oVoice.Provider := vapOpenAI;
oVoice.Transport := vatWebRTC;
oVoice.OpenAIOptions.ApiKey := 'API_KEY';
oVoice.Start;
Audio integrado, o el tuyo propio
En Windows, Android e iOS, el micrófono y el altavoz están integrados, así que el inicio rápido de arriba es todo lo que necesitas. En cualquier otra plataforma, o cuando el audio viene de otro sitio, desactiva el dispositivo. Tu aplicación entrega audio con SendAudio y recibe la respuesta en 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);
Contestando el teléfono
La telefonía habla G.711, y el agente de voz también. Establece el formato de audio a mu-law o A-law a 8 kHz y los bytes de una llamada entran y salen directamente, sin ninguna conversión en tu 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;
Detección de turnos
La detección de turnos decide cuándo el usuario ha terminado de hablar y el agente debe responder. Hay cuatro modos.
- Server VAD deja que el proveedor detecte el final del turno con detección de actividad de voz.
- Semantic VAD escucha lo que se dice, no solo el silencio, para que una pausa en mitad de una frase no corte al usuario.
- Client VAD detecta el turno en el cliente.
- Manual es pulsar para hablar: tu aplicación decide dónde termina el turno.
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';
Con pulsar para hablar, confirma el audio y pide una respuesta cuando el usuario suelta el botón:
procedure TForm1.btnTalkMouseUp(Sender: TObject);
begin
// ... TurnDetection.Mode is vtdManual
oVoice.CommitAudio;
oVoice.CreateResponse;
end;
Barge-in
La gente interrumpe, y un buen agente de voz se lo permite. Con barge-in, cuando el usuario empieza a hablar el agente deja de hablar y la respuesta se cancela. La respuesta también se trunca a lo que el usuario realmente oyó, para que el historial de la conversación no afirme que el agente dijo palabras que nunca se reprodujeron.
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;
Herramientas
Un agente de voz se vuelve útil cuando puede hacer cosas. Declara una herramienta con un nombre, una descripción y un esquema JSON para sus parámetros, y respóndela en 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;
Las herramientas también pueden venir de un servidor MCP. Asigna un cliente MCP y sus herramientas se ofrecen al agente automáticamente:
oMCP := TsgcWSAPIClient_MCP.Create(nil);
oMCP.MCPOptions.HttpOptions.URL := 'https://localhost:5001/mcp';
oVoice.MCPClient := oMCP;
oVoice.Start;
La demo: un asistente de voz para una tienda
La demo de Delphi en Demos\15.AI\02.Applications\09.VoiceAgent es un asistente de tienda con el que hablas. Funciona sobre un catálogo de productos guardado en un TDataSet y da al agente cuatro herramientas: find_products para buscar en el catálogo, get_product para leer un producto, update_stock para cambiar el stock, y count_low_stock para listar los productos que necesitan reposición. Pregúntale qué está escaseando, luego dile que reponga un producto, y observa cómo cambia la cuadrícula mientras responde.
Disponibilidad
TsgcAIVoiceAgent llega en sgcWebSockets 2026.10, para Delphi 7 a 13 y para .NET, en la edición Enterprise. El resto de novedades de la versión está en el post de sgcWebSockets 2026.10, y el resto de los componentes de IA está en la página de producto de IA.
Sigue leyendo
- Extracción de documentos con IA para Delphi y .NET, también nuevo en 2026.10
- Un cliente Server-Sent Events para Delphi y .NET
¿Preguntas o comentarios? Ponte en contacto. Recibirás respuesta de las personas que escribieron el código.
