← Telefonagent mit Terminbuchung
Technische Umsetzung

Telefonagent mit Terminbuchung: technische Umsetzung

Wie der Agent Anrufe annimmt, freie Zeiten sucht und bucht, was die KI allein darf und wie Fehler und Sonderfälle abgefangen werden.

Werkzeuge für den Agenten
10
Schritte bis zur Buchung: Vorschlag, dann Buchung
2
Buchungsfenster im Voraus
60 min bis 14 Tage
Zeitlimit für Anfragen ans Buchungssystem
15 s
Testdateien (pytest)
10

So wird aus einem Anruf ein Termin

Jeder Schritt lässt sich aufklappen.

Eingang
Eingehender Anruf · über den SIP-Trunk des Betriebs

Der Anruf kommt über einen SIP-Trunk in einen LiveKit-Raum. Die angerufene Nummer liegt als Teilnehmer-Attribut vor; der Code normalisiert sie und schlägt den Betrieb in einer Registry nach. Daraus ergeben sich der Schlüssel für die Buchungs-API und der Team-Chat. Kommt ein Anruf über einen Trunk, der keinem Betrieb zugeordnet ist, beendet der Agent die Sitzung, statt ihn einem anderen Betrieb zuzuschlagen.
LiveKit SIP

Parallel prüft der Code, ob die Nummer des Anrufers eine Mobilnummer ist, und lädt das Leistungsangebot aus der Buchungs-API. Der Prompt enthält Datum und Uhrzeit (Zeitzone Berlin), die Rufnummer bereits Ziffer für Ziffer ausgeschrieben und das Menü mit gültigen Kennungen für Leistungen, Dauern und Pflichtfelder. Weil das Menü schon im Prompt steht, spart jede Terminfrage einen Durchlauf des Sprachmodells.
REST-API

Spracherkennung, Sprachmodell und Sprachausgabe laufen über LiveKit Inference. Wann der Anrufer ausgeredet hat, entscheidet der Turn Detector von LiveKit anhand von Inhalt und Tonfall; Unterbrechungen erkennt LiveKit adaptiv. Fachbegriffe, die die Spracherkennung sonst verwechselt, bekommt sie als Schlüsselwörter mit. Der Agent spricht zuerst mit einer festen Begrüßung, stellt sich als KI-Assistent vor und spricht Deutsch in der Sie-Form.
Deepgram FluxOpenAI GPT-4.1Cartesia SonicLiveKit Turn Detector

Der Agent fragt nach Leistung und Dauer, dann nach Tag und Uhrzeit, und ruft find_times auf. Einen genannten Wochentag gibt er als Wort weiter; das Datum rechnet der Code aus. Fehlt die Dauer, setzt der Code die Standarddauer der Leistung ein. Laut Arbeitsregel nennt der Agent nur Zeiten aus dieser Abfrage und bietet ein bis drei davon an, nie zwei dicht beieinander. Während die Abfrage läuft, überbrückt ein vorab erzeugter Füller die Stille.
find_times

Erst wenn eine Uhrzeit feststeht, fragt der Agent nach Name und Mobilnummer. Ruft jemand vom Handy an, fragt er, ob diese Nummer hinterlegt werden soll; eine andere Nummer prüft er mit check_callback_number und liest sie Ziffer für Ziffer zurück. Festnetznummern reichen nicht, weil die Bestätigung per SMS kommt. Dann holt er die Zustimmung zu den Pflichthinweisen des Betriebs ein. preview_booking legt einen Vorschlag mit eigener Kennung an, den die Buchungs-API prüft; die Zusammenfassung liest der Agent einmal vor.
check_callback_numberpreview_booking

Nach einem klaren Ja ruft der Agent book mit der Kennung des Vorschlags und den Pflichtfeldern auf. Fehlen Pflichtfelder, antwortet die API mit missing_required_fields, und der Agent fragt nach. Ist die Zeit inzwischen vergeben oder der Vorschlag abgelaufen, meldet die API das ausdrücklich. Die SMS-Bestätigung mit Link zum Absagen und Umbuchen verschickt das Buchungssystem.
book
Ergebnis
Nachricht ans Team · take_message, direkt im Team-ChatGebuchter Termin und SMS

Berechtigungen des Modells

Kein Zugriff

  • Bestehende Termine nachschlagen, stornieren oder umbuchen
  • Termine bei Personen vergeben, die der Betrieb von der automatischen Vergabe ausnimmt
  • Sich als Mensch ausgeben
  • Interne Kennungen, Fehlercodes oder Werkzeugnamen nennen
  • Anrufe weiterleiten (nicht vorgesehen)

Erlaubt ohne Freigabe

  • Fragen zu Leistungen, Preisen, Öffnungszeiten und Anfahrt beantworten
  • Freie Zeiten suchen und anbieten
  • Einen Buchungsvorschlag anlegen und nach klarem Ja buchen
  • Termine für zwei Personen zur gleichen Zeit suchen und buchen
  • Eine Nachricht mit Rückrufwunsch ans Team schicken
  • Das Gespräch nach der Verabschiedung beenden

Kontrollen

Zwei Schritte bis zur Buchung

Zuerst entsteht mit preview_booking ein Vorschlag mit eigener Kennung, erst book bucht wirklich. Das erzwingt die Buchungs-API: book arbeitet nur mit der Kennung eines Vorschlags und prüft die Pflichtfelder des Betriebs. Ob die Zeit frei ist und die Eingaben stimmen, entscheidet die API.

Datum und Uhrzeit aus dem Code

Einen genannten Wochentag rechnet der Code in ein Datum um, nie in die Vergangenheit. Uhrzeiten zwischen 1 und 8 Uhr liest er als Abendzeiten, weil am Telefon „halb acht“ fast immer 19:30 meint. Beides war vorher eine Fehlerquelle des Sprachmodells.

Rufnummer fertig zum Vorlesen

Die Nummer des Anrufers steht im Prompt bereits in nationaler Form und Ziffer für Ziffer ausgeschrieben. Ob eine Nummer SMS-tauglich ist, liefert die Buchungs-API, nicht das Modell.

Belegte Zeit mit Alternativen

Meldet preview_booking eine belegte Zeit, sucht der Code sofort die nächstgelegenen freien Zeiten und gibt sie mit der Anweisung zurück, nur diese anzubieten. Das spart einen ganzen Durchlauf von Sprachmodell und Suche.

Kein Werkzeug für Stornos

Bestehende Termine nachschlagen, absagen oder verschieben kann der Agent gar nicht, weil er dafür kein Werkzeug hat. Das ist keine Arbeitsregel, sondern fehlt schlicht.

Fehler mit nächster Anweisung

Lehnt die API eine Anfrage wegen unbekannter Kennungen ab, bekommt der Agent den Hinweis, nur Kennungen aus dem Menü zu verwenden, statt denselben Aufruf zu wiederholen. Platzhalter wie „any“, die Sprachmodelle gern als Parameter schicken, entfernt der Code vor dem Aufruf.

Arbeitsregeln im Prompt

Einige Regeln stehen nur im Prompt und sind keine technische Sperre: freie Zeiten nur aus find_times nennen, nach Name und Nummer erst fragen, wenn eine Uhrzeit feststeht, unklare Antworten nicht als Zustimmung werten und nie behaupten, etwas geprüft zu haben, ohne ein Werkzeug aufgerufen zu haben. Unabhängig davon prüft die Buchungs-API jede Buchung.

Sonderfälle

  • Wenn der Anruf über einen Trunk kommt, der keinem Betrieb zugeordnet ist, beendet der Agent die Sitzung, statt ihn einem anderen Betrieb zuzuordnen.
  • Wenn der Anrufer von einer Festnetznummer anruft, weist der Agent früh darauf hin, dass für die Buchung eine Mobilnummer nötig ist, sucht aber zuerst normal weiter.
  • Wenn die genannte Dauer für diese Leistung nicht angeboten wird, nennt der Agent die angebotenen Dauern und sucht erst nach der Wahl des Anrufers.
  • Wenn find_times für die gewünschte Leistung nichts liefert, prüft der Agent, ob an einem früheren Tag eine andere Leistung frei wäre, und nennt beides in einem Satz.
  • Wenn der Termin zwischen Suche und Vorschlag vergeben wurde, liefert der Code die nächstgelegenen freien Zeiten gleich mit, und der Agent bietet nur diese an.
  • Wenn der Vorschlag vor der Buchung abgelaufen ist, meldet die API proposal_expired, und der Agent legt einen neuen Vorschlag an.
  • Wenn das Buchungssystem nicht antwortet, bricht die Anfrage nach 15 Sekunden mit transport_error ab. Der Agent nimmt dann eine Nachricht auf.
  • Wenn jemand einen Termin absagen oder verschieben will, verweist der Agent auf den Link in der SMS-Bestätigung und nimmt auf Wunsch eine Nachricht auf.
  • Wenn ein Termin bei einer Person gewünscht ist, die der Betrieb von der automatischen Vergabe ausnimmt, bucht der Agent nicht, sondern bietet an, das Anliegen ans Team weiterzugeben.
  • Wenn zwei Personen zur gleichen Zeit einen Termin möchten, nutzt der Agent eigene Werkzeuge für Termine zu zweit, mit demselben Ablauf aus Vorschlag und Buchung.
  • Wenn ein Werkzeug läuft und das Ergebnis noch nicht da ist, spielt ein vorab in der Agentenstimme erzeugter Füller, ohne eigenen Durchlauf des Sprachmodells.
  • Wenn jemand eine unangemessene Anfrage stellt, lehnt der Agent höflich, aber bestimmt ab und beendet das Gespräch.

Technische Hürden

  1. 01

    Problem

    Die erste Version lief mit Amazon Nova Sonic, einem Sprachmodell, das direkt hört und spricht, über ein eigenes SIP-Gateway in Java. Das Modell hielt sich nicht verlässlich an den Prompt, kündigte Prüfungen an, ohne ein Werkzeug aufzurufen, und blieb danach still.

    Lösung

    Umstieg auf LiveKit mit getrennter Spracherkennung, Sprachmodell und Sprachausgabe. Die Erfahrungen aus der ersten Version sind in den Code gewandert, etwa dass Datum, Rufnummer und Ausweichzeiten nicht dem Modell überlassen werden.

  2. 02

    Problem

    Ein selbst betriebener LiveKit-Server mit Diensten aus der EU erkannte Sprecherwechsel unzuverlässig. Self-hosted steht nur die kleinere Variante des Turn Detectors zur Verfügung, die adaptive Erkennung von Unterbrechungen nur in der Cloud, und die Spracherkennung lieferte fertige Sätze teils mehrere Sekunden zu spät.

    Lösung

    Betrieb in LiveKit Cloud mit dem vollständigen Turn Detector und adaptiver Unterbrechung. Die Variante mit EU-Diensten bleibt im Code erhalten und lässt sich über eine Umgebungsvariable umschalten.

  3. 03

    Problem

    Jede Terminfrage braucht Sprachmodell, Werkzeug und einen zweiten Durchlauf des Modells. In einem Testanruf entstanden so knapp vier Sekunden Stille, bei einer belegten Zeit bis zu 15 Sekunden.

    Lösung

    Ein vorab erzeugter Füller überbrückt die Wartezeit, das Menü steht schon im Prompt, und bei belegten Zeiten liefert der Code die Alternativen gleich mit. Die Latenz jeder Runde wird geloggt.

  4. 04

    Problem

    Die Spracherkennung machte aus Fachbegriffen ähnlich klingende Wörter, aus „Thai“ etwa „drei“ oder „Teil“, und das Modell las Rufnummern falsch vor.

    Lösung

    Schlüsselwörter für die Spracherkennung, eine Arbeitsregel für die häufigsten Verwechslungen und Rufnummern, die der Code bereits in gesprochener Form in den Prompt schreibt.

Dienste und Datenschutz

AufgabeAnbieter
Sprachagent, Medien und GesprächsverlaufLiveKit Cloud
SpracherkennungDeepgram (über LiveKit Inference)
SprachmodellOpenAI GPT-4.1 (über LiveKit Inference)
SprachausgabeCartesia (über LiveKit Inference)
TelefonieSIP-Anbieter
Buchungssystemeigene Buchungs-API des Betriebs
Nachrichten ans TeamInfomaniak (kChat)
  • Gesprächsverlauf, Traces und Logs in der Observability von LiveKit Cloud, keine Audioaufzeichnung

Deepgram, OpenAI und Cartesia sind US-Anbieter. Eine Variante mit Diensten aus der EU ist im Code vorbereitet. Die Buchungs-API ist mit einem Zugangsschlüssel je Betrieb geschützt.

LiveKit AgentsLiveKit CloudLiveKit Turn DetectorDeepgram FluxOpenAI GPT-4.1Cartesia SonicPythonpytestSIPREST-API

Betrieb und Tests

Der Agent ist mit LiveKit Agents in Python gebaut und läuft in LiveKit Cloud. Ein warmer Prozess baut die Sprachdienste schon vor dem ersten Anruf auf, damit Konfigurationsfehler beim Start auffallen und nicht erst im Gespräch.

Vorgänger war ein Gateway in Java mit Amazon Nova Sonic. Ein selbst betriebener LiveKit-Server mit Diensten aus der EU wurde erprobt und bleibt als umschaltbare Variante erhalten.

Zehn Testdateien (pytest) prüfen unter anderem die Zuordnung nach Trunk, den Buchungsablauf, die Umrechnung von Wochentagen, den Prompt und die Werkzeugergebnisse.

Mehrere Betriebe können denselben Agenten nutzen. Sie werden über die angerufene Nummer getrennt, jeder mit eigenem Schlüssel für die Buchungs-API und eigenem Team-Chat.

← Zurück zur Übersicht: Telefonagent mit Terminbuchung