Ein Realtime-Sprachagent für Delphi und .NET

· Komponenten
Ein Realtime-Sprachagent für Delphi und .NET

Eine Frage tippen und die Antwort lesen, so sprechen die meisten Anwendungen heute mit einem Sprachmodell. Die Realtime-APIs ändern das. OpenAI Realtime und Gemini Live nehmen die Stimme des Nutzers auf, während er spricht, und antworten mit einer eigenen Stimme, schnell genug, um ein Gespräch zu führen. Das von Hand zu bauen bedeutet, Audio in beide Richtungen zu streamen, zu entscheiden, wann der Nutzer fertig ist, den Agenten zu stoppen, wenn er unterbrochen wird, und mittendrin Tools auszuführen.

sgcWebSockets 2026.10 fügt TsgcAIVoiceAgent hinzu, eine einzige Komponente, die all das übernimmt. Sie hört zu, erkennt, wann der Nutzer einen Gesprächswechsel abgeschlossen hat, antwortet und ruft Ihre Tools auf. Sie ist für Delphi 7 bis 13 und für .NET verfügbar.

TsgcAIVoiceAgent in Aktion: Erkennung von Gesprächswechseln, Barge-in, Live-Transkripte und Tool-Aufrufe. Auch auf YouTube.

Schnellstart

Wählen Sie den Anbieter, setzen Sie den API-Schlüssel, eine Stimme und die Anweisungen, behandeln Sie OnTranscript und rufen Sie Start auf. Das ist bereits ein funktionierender Sprachassistent.

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 liefert Live-Transkripte beider Seiten des Gesprächs, des Nutzers und des Agenten, sodass der Bildschirm mitverfolgen kann, was gesagt wird:

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 oder Gemini Live, WebSocket oder WebRTC

Zwei Anbieter werden unterstützt, OpenAI Realtime und Gemini Live. Der Wechsel ist eine Eigenschaft und die passenden Optionen:

oVoice.Provider := vapGemini;
oVoice.GeminiOptions.ApiKey := 'GEMINI_API_KEY';
oVoice.Start;

Die Sitzung läuft über WebSocket. Mit OpenAI kann sie auch über WebRTC laufen:

oVoice.Provider := vapOpenAI;
oVoice.Transport := vatWebRTC;
oVoice.OpenAIOptions.ApiKey := 'API_KEY';
oVoice.Start;

Eingebautes Audio oder Ihr eigenes

Unter Windows, Android und iOS sind Mikrofon und Lautsprecher eingebaut, sodass der Schnellstart oben bereits alles ist, was Sie brauchen. Auf jeder anderen Plattform, oder wenn das Audio von woanders kommt, schalten Sie das Gerät ab. Ihre Anwendung liefert Audio mit SendAudio und empfängt die Antwort 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);

Den Anruf entgegennehmen

Die Telefonie spricht G.711, und der Sprachagent spricht es ebenfalls. Setzen Sie das Audioformat auf mu-law oder A-law bei 8 kHz, und die Bytes eines Anrufs gehen direkt hinein und direkt hinaus, ohne jede Umwandlung in Ihrem 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;

Erkennung von Gesprächswechseln

Die Erkennung von Gesprächswechseln entscheidet, wann der Nutzer zu sprechen aufgehört hat und der Agent antworten soll. Es gibt vier Modi.

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';

Bei Push-to-Talk übergeben Sie das Audio und fordern eine Antwort an, sobald der Nutzer die Taste loslässt:

procedure TForm1.btnTalkMouseUp(Sender: TObject);
begin
  // ... TurnDetection.Mode is vtdManual
  oVoice.CommitAudio;
  oVoice.CreateResponse;
end;

Barge-in

Menschen unterbrechen, und ein guter Sprachagent lässt sie das tun. Mit Barge-in stoppt der Agent das Sprechen, sobald der Nutzer zu sprechen beginnt, und die Antwort wird abgebrochen. Die Antwort wird zudem auf das gekürzt, was der Nutzer tatsächlich gehört hat, sodass der Gesprächsverlauf nicht behauptet, der Agent habe Worte gesagt, die nie abgespielt wurden.

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

Ein Sprachagent wird nützlich, wenn er Dinge erledigen kann. Deklarieren Sie ein Tool mit einem Namen, einer Beschreibung und einem JSON-Schema für seine Parameter, und beantworten Sie es 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 können auch von einem MCP-Server kommen. Weisen Sie einen MCP-Client zu, und seine Tools werden dem Agenten automatisch angeboten:

oMCP := TsgcWSAPIClient_MCP.Create(nil);
oMCP.MCPOptions.HttpOptions.URL := 'https://localhost:5001/mcp';

oVoice.MCPClient := oMCP;
oVoice.Start;

Die Demo: ein Sprachassistent für einen Shop

Die Delphi-Demo in Demos\15.AI\02.Applications\09.VoiceAgent ist ein Shop-Assistent, mit dem Sie sprechen. Sie arbeitet mit einem Produktkatalog, der in einem TDataSet gehalten wird, und gibt dem Agenten vier Tools: find_products zum Durchsuchen des Katalogs, get_product zum Lesen eines Produkts, update_stock zum Ändern des Lagerbestands und count_low_stock zum Auflisten der Produkte, die nachbestellt werden müssen. Fragen Sie, was knapp wird, sagen Sie dann, ein Produkt soll nachbestellt werden, und beobachten Sie, wie sich das Raster ändert, während der Assistent antwortet.

Verfügbarkeit

TsgcAIVoiceAgent erscheint in sgcWebSockets 2026.10, für Delphi 7 bis 13 und für .NET, in der Edition Enterprise. Was sonst noch neu im Release ist, steht im Beitrag zu sgcWebSockets 2026.10, und die übrigen AI-Komponenten finden Sie auf der AI-Produktseite.

Weiterlesen

Fragen oder Feedback? Nehmen Sie Kontakt auf. Sie erhalten eine Antwort von den Leuten, die den Code geschrieben haben.