Wie aus einem Chatbot ein Gesprächspartner wurde: Architektur, Ideen und Umsetzung des Sprachgesprächs mit KAI, vom Mikrofon bis Gemini Live und zurück.
Sprechen statt tippen. Nachfragen, ins Wort fallen, Rückbezüge wie „und bei Sturm?“. KAI verhält sich wie ein Mensch am Telefon und überbrückt Wartezeit hörbar.
Jede fachliche Aussage stammt aus der KAI-Recherche über freigegebene Quellen. Dieselbe Pipeline, derselbe Kundenkontext und dieselbe Abnahme wie im Textchat. Das Sprachmodell erfindet nichts.
Der Chat schreibt mit: Fragen, entstehende Antworten, Quellen. Nach dem Auflegen bleibt ein normaler, gespeicherter Chatverlauf zum Nachlesen und Weiterarbeiten.
So lange dauert eine Recherche. Schnell: einige Sekunden. Vertieft: oft bis zu einer Minute. Schon drei Sekunden Stille wirken am Telefon wie ein Verbindungsabbruch.
Die Live API dokumentiert behavior: NON_BLOCKING. Das Modell spricht weiter, während ein Werkzeug arbeitet. Genau das, was man braucht.
Die FunctionDeclaration in Vertex kennt das Feld nicht und ignoriert es. Toolcalls blockieren: Das Modell schweigt, bis die Antwort da ist. Die Google-Dokumentation widerspricht sich hier.
Mit „Weiter“ oder „Abspielen“ läuft eine fachliche Frage im Modus Schnell durch alle beteiligten Komponenten.
Gemini erkennt den Barge-in und meldet interrupted. Der Browser stoppt alle geplanten Audioquellen sofort und verwirft nachlaufendes Audio. Echo-Unterdrückung verhindert, dass das Modell sich selbst hört.
Fragt der Nutzer während der Recherche etwas Neues, bekommt das Modell nur noch das neue Ergebnis. Die alte Recherche läuft für den Chat zu Ende. Keine veralteten Antworten im Ohr.
Ruft das Modell KAI ohne neue Nutzereingabe ein zweites Mal auf, startet keine zweite Recherche. KAI beantwortet genau diesen Call mit dem laufenden Ergebnis, sobald es da ist.
Sendet Gemini toolCallCancellation, erscheint das Ergebnis nur im Chat. Das Modell bekommt nichts mehr, das Gespräch bleibt konsistent.
Die Antwortgenerierung läuft im Backend entkoppelt weiter und wird gespeichert. Der Chat lädt neu und holt offene Antworten über den vorhandenen Resume-Mechanismus.
Scheitert eine Recherche, sagt das Modell nur „Die Bedingungen konnten gerade nicht abgefragt werden.“ Interna bleiben im Log, damit nichts davon vorgelesen wird. Verbindungsabbrüche enden mit klarer Meldung.
| Schritt | Textchat | Voice | Warum |
|---|---|---|---|
| Frage umformulieren (Rewriter) | ja | entfällt | Das Live-Modell stellt bereits eine eigenständige Frage. |
| Folgefragen-Vorschläge | ja | entfällt | Im Gespräch fragt man einfach nach. |
| Quellenfilter (Schnell) | vor der Antwort | nach der Antwort | Antwort sofort ans Modell, gefilterte Quellen kommen als zweites Ergebnis nach. |
| Hinweis „Antworte möglichst kurz“ | nein | als Kontext | Wird vorgelesen; der Hinweis wird nicht als Teil der Frage gespeichert. |
| Speicherung, Quellen, Kundenkontext | ja | ja | Gleiche fachliche Qualität und Nachvollziehbarkeit. |
Browser können beim WebSocket keine Header setzen. Das Keycloak-Token reist als Subprotocol bearer.<jwt>. Der Server bestätigt nur kai.voice.v1, nie das Token.
Token-Validierung wie bei REST, bevor die Verbindung angenommen wird. Ein Gespräch ist nur im eigenen Chat möglich, sonst Close 1008.
Das KIRA-Token, System-Prompts und die Gesprächslogik liegen im Backend. Der Browser spricht nie direkt mit KIRA oder Google.
Transkripte werden weder geloggt noch im Tracing erfasst. Audio wird nicht gespeichert. Ein Test sichert das ab.
Ohne aktiven Kundenkontext gelangen keine Vertragsdaten aus früheren Chatnachrichten in den Prompt des Live-Modells.
Feste Meldungen an Nutzer und Modell. Die Startnachricht ist vor Validierungs-Logs geschützt (hide_input_in_errors).
OpenTelemetry → Jaeger. Logs enthalten Ablaufschritte und IDs, aber keine Inhalte. Matomo zählt „Gespräch gestartet“ und „beendet“.
Drei Ideen tragen KAI Voice: Gesprächsführung und Wissen getrennt, sofort reden und parallel suchen, und ein Chat, der mitschreibt.