Een vraag typen en het antwoord lezen is hoe de meeste applicaties vandaag met een taalmodel praten. De realtime API's veranderen dat. OpenAI Realtime en Gemini Live nemen de stem van de gebruiker op zoals die wordt uitgesproken en antwoorden met een eigen stem, snel genoeg om een gesprek te voeren. Dit met de hand bouwen betekent audio in beide richtingen streamen, bepalen wanneer de gebruiker klaar is, de agent stoppen wanneer die wordt onderbroken, en tools uitvoeren midden in dat alles.
sgcWebSockets 2026.10 voegt TsgcAIVoiceAgent toe, één component dat dat allemaal doet. Het luistert, detecteert wanneer de gebruiker een beurt heeft afgerond, praat terug en roept je tools aan. Het is beschikbaar voor Delphi 7 tot en met 13 en voor .NET.
TsgcAIVoiceAgent in actie: beurtdetectie, barge-in, live transcripties en tool calls. Ook op YouTube.
Aan de slag
Kies de provider, stel de API-sleutel in, een stem en de instructies, verwerk OnTranscript en roep Start aan. Dat is al een werkende spraakassistent.
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 levert live transcripties van beide kanten van het gesprek, de gebruiker en de agent, zodat het scherm kan volgen wat er gezegd wordt:
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 of Gemini Live, WebSocket of WebRTC
Er worden twee providers ondersteund, OpenAI Realtime en Gemini Live. Overschakelen is één property en de bijbehorende opties:
oVoice.Provider := vapGemini;
oVoice.GeminiOptions.ApiKey := 'GEMINI_API_KEY';
oVoice.Start;
De sessie loopt over WebSocket. Met OpenAI kan die ook over WebRTC lopen:
oVoice.Provider := vapOpenAI;
oVoice.Transport := vatWebRTC;
oVoice.OpenAIOptions.ApiKey := 'API_KEY';
oVoice.Start;
Ingebouwde audio, of je eigen
Op Windows, Android en iOS zijn de microfoon en de luidspreker ingebouwd, dus aan de slag hierboven is alles wat je nodig hebt. Op elk ander platform, of wanneer de audio ergens anders vandaan komt, schakel je het apparaat uit. Je applicatie levert audio aan met SendAudio en ontvangt het antwoord in 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);
De telefoon beantwoorden
Telefonie spreekt G.711, en de spraakagent ook. Stel het audioformaat in op mu-law of A-law op 8 kHz, en de bytes van een gesprek gaan er rechtstreeks in en rechtstreeks uit, zonder enige conversie in je code.
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;
Beurtdetectie
Beurtdetectie bepaalt wanneer de gebruiker klaar is met spreken en de agent moet antwoorden. Er zijn vier modi.
- Server VAD laat de provider het einde van de beurt detecteren met voice activity detection.
- Semantic VAD luistert naar wat er gezegd wordt, niet alleen naar stilte, zodat een pauze midden in een zin de gebruiker niet afkapt.
- Client VAD detecteert de beurt op de client.
- Manual is push-to-talk: je applicatie bepaalt waar de beurt eindigt.
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';
Bij push-to-talk bevestig je de audio en vraag je om een antwoord wanneer de gebruiker de knop loslaat:
procedure TForm1.btnTalkMouseUp(Sender: TObject);
begin
// ... TurnDetection.Mode is vtdManual
oVoice.CommitAudio;
oVoice.CreateResponse;
end;
Barge-in
Mensen onderbreken, en een goede spraakagent laat dat toe. Met barge-in stopt de agent met praten en wordt het antwoord geannuleerd zodra de gebruiker begint te spreken. Het antwoord wordt ook afgekapt tot wat de gebruiker daadwerkelijk hoorde, zodat de gespreksgeschiedenis niet beweert dat de agent woorden zei die nooit zijn afgespeeld.
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
Een spraakagent wordt pas nuttig als hij dingen kan doen. Declareer een tool met een naam, een beschrijving en een JSON-schema voor de parameters, en beantwoord die in 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;
Tools kunnen ook van een MCP-server komen. Wijs een MCP-client toe en de tools ervan worden automatisch aan de agent aangeboden:
oMCP := TsgcWSAPIClient_MCP.Create(nil);
oMCP.MCPOptions.HttpOptions.URL := 'https://localhost:5001/mcp';
oVoice.MCPClient := oMCP;
oVoice.Start;
De demo: een spraakassistent voor een winkel
De Delphi-demo in Demos\15.AI\02.Applications\09.VoiceAgent is een winkelassistent waarmee je praat. Hij werkt op een productcatalogus die wordt bijgehouden in een TDataSet en geeft de agent vier tools: find_products om de catalogus te doorzoeken, get_product om één product te lezen, update_stock om de voorraad te wijzigen, en count_low_stock om de producten te tonen die moeten worden aangevuld. Vraag hem wat er bijna op is, zeg hem dan een product aan te vullen, en kijk hoe het raster verandert terwijl hij antwoordt.
Beschikbaarheid
TsgcAIVoiceAgent komt in sgcWebSockets 2026.10, voor Delphi 7 tot en met 13 en voor .NET, in de Enterprise-editie. Wat er verder nieuw is in deze release staat in de post over sgcWebSockets 2026.10, en de rest van de AI-componenten staat op de AI-productpagina.
Lees verder
- AI-documentextractie voor Delphi en .NET, ook nieuw in 2026.10
- Een Server-Sent Events-client voor Delphi en .NET
Vragen of feedback? Neem contact op. Je krijgt een antwoord van de mensen die de code hebben geschreven.
