Digitare una domanda e leggere la risposta è il modo in cui oggi la maggior parte delle applicazioni parla con un modello linguistico. Le API in tempo reale cambiano questo scenario. OpenAI Realtime e Gemini Live prendono la voce dell'utente mentre viene pronunciata e rispondono con una voce propria, abbastanza veloce da sostenere una conversazione. Arrivarci a mano significa trasmettere l'audio in streaming in entrambe le direzioni, decidere quando l'utente ha finito, fermare l'agente quando viene interrotto ed eseguire strumenti nel mezzo di tutto questo.
sgcWebSockets 2026.10 aggiunge TsgcAIVoiceAgent, un componente che fa tutto questo. Ascolta, rileva quando l'utente ha finito un turno, risponde a voce e chiama i tuoi strumenti. È disponibile per Delphi da 7 a 13 e per .NET.
TsgcAIVoiceAgent in azione: rilevamento dei turni, barge-in, trascrizioni live e chiamate a strumenti. Anche su YouTube.
Avvio rapido
Scegli il provider, imposta la chiave API, una voce e le istruzioni, gestisci OnTranscript e chiama Start. Questo è già un assistente vocale funzionante.
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 consegna le trascrizioni live di entrambi i lati della conversazione, l'utente e l'agente, così lo schermo può seguire cosa viene detto:
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
Sono supportati due provider, OpenAI Realtime e Gemini Live. Passare dall'uno all'altro richiede una sola proprietà e le opzioni corrispondenti:
oVoice.Provider := vapGemini;
oVoice.GeminiOptions.ApiKey := 'GEMINI_API_KEY';
oVoice.Start;
La sessione funziona su WebSocket. Con OpenAI può funzionare anche su WebRTC:
oVoice.Provider := vapOpenAI;
oVoice.Transport := vatWebRTC;
oVoice.OpenAIOptions.ApiKey := 'API_KEY';
oVoice.Start;
Audio integrato, o il tuo
Su Windows, Android e iOS il microfono e l'altoparlante sono integrati, quindi l'avvio rapido descritto sopra è tutto ciò che serve. Su qualsiasi altra piattaforma, o quando l'audio arriva da un'altra fonte, disattiva il device. La tua applicazione fornisce l'audio con SendAudio e riceve la risposta 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);
Rispondere al telefono
La telefonia parla G.711, e così fa l'agente vocale. Imposta il formato audio su mu-law o A-law a 8 kHz e i byte di una chiamata entrano ed escono direttamente, senza alcuna conversione nel tuo codice.
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;
Rilevamento dei turni
Il rilevamento dei turni decide quando l'utente ha finito di parlare e l'agente deve rispondere. Ci sono quattro modalità.
- Server VAD lascia che il provider rilevi la fine del turno con il voice activity detection.
- Semantic VAD ascolta ciò che viene detto, non solo il silenzio, così una pausa nel mezzo di una frase non interrompe l'utente.
- Client VAD rileva il turno lato client.
- Manual è push to talk: la tua applicazione decide dove finisce il 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 il push to talk, esegui il commit dell'audio e richiedi una risposta quando l'utente rilascia il pulsante:
procedure TForm1.btnTalkMouseUp(Sender: TObject);
begin
// ... TurnDetection.Mode is vtdManual
oVoice.CommitAudio;
oVoice.CreateResponse;
end;
Barge-in
Le persone interrompono, e un buon agente vocale glielo permette. Con il barge-in, quando l'utente inizia a parlare l'agente smette di parlare e la risposta viene annullata. La risposta viene anche troncata a ciò che l'utente ha effettivamente sentito, così la cronologia della conversazione non afferma che l'agente ha detto parole che non sono mai state riprodotte.
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;
Strumenti
Un agente vocale diventa utile quando può fare delle cose. Dichiara uno strumento con un nome, una descrizione e uno schema JSON per i suoi parametri, e rispondi 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;
Gli strumenti possono arrivare anche da un server MCP. Assegna un client MCP e i suoi strumenti vengono offerti automaticamente all'agente:
oMCP := TsgcWSAPIClient_MCP.Create(nil);
oMCP.MCPOptions.HttpOptions.URL := 'https://localhost:5001/mcp';
oVoice.MCPClient := oMCP;
oVoice.Start;
La demo: un assistente vocale per un negozio
La demo Delphi in Demos\15.AI\02.Applications\09.VoiceAgent è un assistente per un negozio con cui parli. Funziona su un catalogo prodotti contenuto in un TDataSet e dà all'agente quattro strumenti: find_products per cercare nel catalogo, get_product per leggere un prodotto, update_stock per modificare lo stock, e count_low_stock per elencare i prodotti da riordinare. Chiedigli cosa sta scarseggiando, poi digli di riordinare un prodotto, e guarda la griglia cambiare mentre risponde.
Disponibilità
TsgcAIVoiceAgent arriva in sgcWebSockets 2026.10, per Delphi da 7 a 13 e per .NET, nell'edizione Enterprise. Tutto il resto di nuovo nella release è nel post sgcWebSockets 2026.10, e il resto dei componenti AI è nella pagina di prodotto AI.
Continua a leggere
- Estrazione documenti AI per Delphi e .NET, anch'esso nuovo nella 2026.10
- Un client Server-Sent Events per Delphi e .NET
Domande o feedback? Mettiti in contatto. Riceverai una risposta dalle persone che hanno scritto il codice.
