Telefonie mit KI: Fünf Tage, 68 Commits und eine Nacht mit 40 Sekunden
Wie Jarvis telefonieren lernte – und warum „der Assistent soll anrufen können“ kein Wochenend-Feature ist.
Technik einfach erklärt: „Kann das nicht ChatGPT?“
- ChatGPT liefert Text. Ein Telefonat ist ein Live-Audiostrom in beide Richtungen. Kommt die Antwort erst nach drei Sekunden, ist das Gespräch kaputt – deshalb braucht es Echtzeit-Sprache statt „Frage – Antwort“.
- Jemand muss die Leitung haben. Eine echte Rufnummer kommt von einem Anbieter. Bei Relyper hängt deine Leitung an einem eigenen Telefonserver (Asterisk, Open Source) – oder du nutzt eine Voice-API.
- Der Schlüssel darf nie ins Netz. Für jeden Anruf gibt es ein kurzlebiges Token, damit der echte API-Schlüssel nie bei Nutzern landet.
- Und dann das Drumherum: Wer darf telefonieren, welche Firma hat welche Leitung, was kostet die Minute, wer bezahlt – lauter Dinge, die ein Chatbot nicht kennt.
Am Anfang klang es simpel: Der Assistent soll anrufen und angerufen werden können. Dann fängt man an – und kommt vom Hölzchen aufs Stöckchen. Man öffnet eine Tür, und dahinter warten zehn weitere. Jede davon brauchte einen eigenen Fix.
Von außen sieht man davon nichts: Am Ende ist es ein Telefonat, das einfach funktioniert. Genau deshalb erzähle ich hier, wie viel Arbeit darin steckt.
Ein KI-Assistent, der telefoniert – das klingt nach einem einzigen API-Aufruf. In Wirklichkeit waren es 51 Commits im Hauptprojekt, 17 weitere im Telefonserver-Repo, rund 5.000 Zeilen Telefonie-Code, ein eigener Telefonserver und eine Nacht, in der jeder Anruf nach genau 40 Sekunden abbrach.
Zwischen dem 2. und 6. Oktober 2026 hat Jarvis, der KI-Assistent der Relyper AI Factory, telefonieren gelernt. Das hier ist die ganze Geschichte, auch mit allem, was schiefging.
Was Jarvis jetzt kann
- Anrufen: „Ruf beim Arzt an und frag nach einem Termin.“ Jarvis wählt, wartet auf das „Hallo?“, sagt im ersten Satz, dass er eine KI ist, erledigt den Auftrag und liefert danach eine Zusammenfassung.
- Angerufen werden: Jarvis nimmt ab, nimmt Nachrichten auf, stellt Favoriten durch, legt bei gesperrten Nummern auf und beachtet Ruhezeiten.
- Bots: Bots einer Firma (eines „Tenants“) können telefonieren und SMS schicken – nur mit Freigabe einer verantwortlichen Person.
- Eigene Leitungen: Jede Firma bringt ihre eigenen Leitungen und Nummern mit, bis zu 10 pro Tenant, mit Ausweichleitung bei Störungen.
- Abrechnung: Jede Minute läuft in Relyper-Coins, wahlweise vom persönlichen oder vom Firmen-Wallet.
Der Aufbau: Ein Anruf, fünf Stationen
Einfach erklärt: Ein Anruf wandert wie eine Staffel durch mehrere Systeme. Der Telefonanbieter bringt ihn ins Telefonnetz, ein Telefonserver (Asterisk) nimmt ihn an, unsere API steuert alles, und ein Sprachmodell hört zu und antwortet. Das Besondere: Es gibt kein „Sprache → Text → KI → Sprache“. Das Modell versteht und spricht Audio direkt. Dadurch reagiert es schnell, und man kann es sogar unterbrechen.
Die API ist die Schaltzentrale: Sie steuert Asterisk, leitet den Ton zum Sprachmodell und holt sich vor jedem Anruf Token und Budget bei Relyper.
| Schicht | Technik | Aufgabe |
|---|---|---|
| Telefonanbieter | SIP-Trunk (z. B. sipgate, easybell, fonial) oder Voice-API (Twilio, SignalWire, Telnyx) | Nummern, Verbindung ins Telefonnetz |
| Telefonserver | Asterisk 22 im Docker-Container (Open Source, kostenlos) | Registrierung beim Anbieter, Kanäle, Ansagen |
| Steuerung | Asterisk REST Interface (ARI) und WebSocket für den Ton | Anrufe starten, annehmen, auflegen |
| AI Factory API | Node/TypeScript | Regeln, Limits, Freigaben, Abrechnung, Protokoll |
| Sprachmodell | OpenAI gpt-realtime, Stimme marin |
Zuhören, Sprechen, Aktionen auslösen (Durchstellen, Auflegen) |
| Relyper | KI-Proxy, kurzlebige Tokens, Coin-Wallets | Schlüsselwahl, Budgetprüfung, Abrechnung |
Drei Details, die zeigen, wie viel unter der Haube steckt:
- Leitungen ohne Neustart: Die API baut aus den Leitungsdaten jeder Firma die Telefon-Konfiguration und lädt sie im laufenden Betrieb. Das ist nötig, weil Asterisks dynamische Konfiguration keine Registrierungen beim Anbieter kann.
- Kein KI-Schlüssel in der AI Factory: Für jeden Anruf holt sie bei Relyper ein Einmal-Token (120 Sekunden gültig). Relyper wählt den passenden Schlüssel, prüft Mitgliedschaft und Guthaben – ist das Wallet leer, gibt es kein Token und damit keinen Anruf.
- Ausweichleitung: Fällt eine Leitung aus, wählt Jarvis automatisch über die nächste neu.
Der erste Plan scheitert
Für die Telefonie gab es drei Anläufe:
| Ansatz | Ergebnis | Warum |
|---|---|---|
| sipgate Click-to-Call plus SIP-Stream-Bridge (2.10.) | verworfen | Die Bridge konnte keine Anrufe selbst starten; Click-to-Call lässt zuerst das eigene Telefon klingeln |
| jambonz (Voice-Gateway) | verworfen | Self-Hosting ist kostenpflichtig |
| Asterisk 22 plus beliebiger SIP-Trunk (3.10.) | gewählt | Open Source, läuft im Container, jeder Anbieter möglich |
| Voice-API (Twilio, SignalWire, Telnyx) | zusätzlich | Kein eigener Server nötig, kann auch SMS |
„SIP ist ein Standard“ stimmt nur auf dem Papier. Jeder Anbieter will die Absendernummer anders: sipgate als P-Preferred-Identity nur mit Ziffern, easybell als P-Asserted-Identity, fonial mit +49… im From-Feld. Deshalb gibt es im Code eigene Anbieterprofile. Einen Preisvergleich der Anbieter findest du in der Telefonie-Anleitung.
Das Sprachmodell
- Gewählt: OpenAI
gpt-realtime, Stimmemarin. Weil das Modell direkt mit Audio arbeitet, entfällt der Umweg über Text. - Pro Nummer einstellbar: Modell und Stimme, der Name des Assistenten (z. B. „Aivra“), das Verhalten in freien Worten und das Wissen aus Text oder Webseiten.
- Eigener Telefonie-Schlüssel: Die Anrufe laufen über einen separaten Key, damit die Kosten getrennt von den Chat-Kosten sichtbar sind.
- Wann ist der Anrufer fertig? Standard ist die semantische Erkennung: Ein Modell beurteilt, ob ein Gedanke abgeschlossen ist, deshalb lösen Hintergrundgeräusche und Piepstöne selten eine Antwort aus. Die Alternative reagiert nur auf Lautstärke – schneller, aber jedes Geräusch zählt dann als Sprache.
Grüne Tests, rauschende Leitung
Nach drei Tagen war die Software fertig und getestet. Die echten Probleme kamen erst beim ersten echten Anruf.
| Datum | Problem | Ursache | Lösung |
|---|---|---|---|
| 4.10. | Zwei Einstellungen kollidierten | Gleicher Variablenname für zwei Zwecke | Kein KI-Schlüssel mehr in der AI Factory, stattdessen Einmal-Tokens |
| 5.10. | Lautes Rauschen bei der Ansage | Abspielen über ARI störte; Git hatte die Audiodateien als Text behandelt | Ansage über den Dialplan, Audio als Rohformat, Binärdateien in .gitattributes |
| 5.10. | Neue Ansagen kamen nie an | Docker behielt alte Dateien im Volume | Dateien werden bei jedem Start neu kopiert, Build ohne Cache |
| 5.10. | API fand Asterisk nicht | Zwei verschiedene Docker-Netzwerke | Asterisk ins Projektnetz, Zugriff über den Containernamen |
| 5.10. | Scanner fluteten das Log | Das Internet probiert offene SIP-Ports durch | Nur Anbieter-Adressen dürfen zugreifen |
| 5.10. | sipgate lehnte Anrufe ab | sipgate ignoriert From und PAI | Absender als P-Preferred-Identity, nur Ziffern |
| 6.10., 2 Uhr | Anrufe brachen nach ca. 40 Sekunden ab | Ein riesiger Audio-Frame, siehe unten | Höchstens 10 Frames pro Nachricht |
| 6.10., 3 Uhr | Sprachmodell brach mitten im Gespräch weg | Lange Sitzungen, abgelaufene Tokens | Bis zu 2 Reconnects mit dem bisherigen Gesprächsverlauf |
| 6.10., 10 Uhr | Gespräche wurden grundlos beendet | Harmlose „error“-Meldungen des Modells beendeten die Verbindung | Fehler nur noch protokollieren; nur ein echter Verbindungsabbruch zählt |
| 6.10. | Jarvis antwortete auf Hintergrundgeräusche | Erkennung nur nach Lautstärke | Semantische Erkennung plus Prompt-Regel „Nebengespräche ignorieren“ |
| 6.10. | Verabschiedung wurde abgeschnitten | Modell legte auf, während es noch sprach | 6 Sekunden Nachlaufzeit |
Die 40-Sekunden-Nacht
Alles funktionierte, aber jedes Gespräch starb nach etwa 40 Sekunden. Die Ursache war kein Netzwerk und kein Modell: Wenn Asterisk den Ton kurz anhält und wieder freigibt, ging der gesamte angestaute Audio-Rückstau als ein einziger riesiger WebSocket-Frame raus – und Asterisk schloss daraufhin die Verbindung.
// Asterisk schließt die Verbindung, wenn ein WebSocket-Frame zu groß wird
const MAX_FRAMES_PER_MESSAGE = 10;
Gefunden habe ich das nur, weil ich vorher Diagnose-Daten eingebaut hatte: Close-Code, gesendete Bytes, Warteschlange, Zähler fürs Anhalten. Ohne sie hätte ich noch lange geraten.
Ein einziger zu großer Datenblock – und jedes Gespräch war nach 40 Sekunden tot.
„Loud noise on the line“
Die Ansage „Der Assistent ist gerade nicht erreichbar“ klang wie ein Radiosender zwischen zwei Frequenzen. Dahinter steckten zwei Ursachen gleichzeitig: Git hatte die Audiodateien durch die Zeilenende-Umwandlung beschädigt, und das Abspielen über ARI rauschte zusätzlich.
Die Datei, die nicht aktualisiert werden wollte
Neues Image gebaut, trotzdem die alte Ansage gehört. Docker hielt die alten Dateien im Volume fest. Es folgten sechs Commits für ein einziges Problem: erst jede Datei einzeln statt ganzer Ordner kopieren, dazu eine Build-Prüfung, die bei veraltetem Stand abbricht. Dann die Dateien ganz aus den Docker-Volumes herausgezogen, damit das Startskript sie bei jedem Start frisch an ihren Platz kopiert – plus ein Sicherheitsnetz, falls doch einmal eine alte Vorlage durchrutscht. Und als die Ansage endlich ankam, war sie zu leise – also noch einmal lauter.
Sechs Anläufe für eine Ansage – und am Ende war sie einfach zu leise.
Das Internet klopft
Kaum war Port 5060 offen, kamen Scanner, die Passwörter für SIP-Konten erraten wollten. Ein öffentlicher Telefonserver wird sofort angegriffen, deshalb war die Zugriffsliste von Anfang an Pflicht.
Die zweite Nacht: Der Satz, der nicht ankam
Einen Tag später wieder Stille, diesmal mitten in einem Absatz. Im Transkript stand der Satz komplett, am Telefon hörte man nur die erste Hälfte. Das Modell hatte also fertig gesprochen – der Ton blieb auf dem Weg zu Asterisk hängen.
Die Ursache war ausgerechnet der Fix der ersten Nacht. Das Sprachmodell erzeugt Sprache schneller, als sie gesprochen wird. Ich schickte den Rückstau jetzt zwar in kleinen Stücken, aber so schnell wie möglich. Asterisk meldet dann „Puffer voll, warte“ (MEDIA_XOFF), und wenn das „weiter“ (MEDIA_XON) auf dem Weg verloren geht, wartet die Warteschlange für immer. Kein Fehler, keine Meldung – nur Stille.
Zwei Dinge dagegen: Der Ton geht jetzt im Echtzeit-Takt raus, höchstens gut eine Sekunde voraus, damit der Puffer gar nicht erst voll wird. Und ein Watchdog: Kommt nach dem Anhalten anderthalb Sekunden lang kein „weiter“, senden wir trotzdem. Lieber ein kurzer Knackser als ein stummer Assistent.
Wenn das Modell die Verbindung verliert
Reißt die Verbindung zum Sprachmodell wirklich ab, war das Gespräch früher einfach zu Ende. Jetzt verbindet sich die KI neu, bekommt den bisherigen Gesprächsverlauf mit und sagt dem Anrufer, dass die Leitung kurz unterbrochen war – und macht genau dort weiter. Erst wenn das zweimal scheitert, hört der Anrufer eine Ansage und die Leitung wird aufgelegt. Niemals eine tote Leitung.
Dabei lernte ich, dass „error“ nicht „kaputt“ heißt: Das Modell meldet regelmäßig harmlose Fehler, etwa wenn die Begrüßung und eine automatische Antwort zusammenfallen. Eine Version lang habe ich jeden dieser Fehler als Abbruch behandelt und die Verbindung neu aufgebaut. Das Ergebnis: Aivra sagte „Hallo“ und verstummte. Seitdem gilt: Nur ein echter Verbindungsabbruch löst den Neuaufbau aus, Fehler werden protokolliert.
Die Notiz, die es nicht gab
Legt der Anrufer auf, bevor die KI zusammenfassen konnte, stand im Monitor nur „The caller hung up“. Dass gerade ein Termin vereinbart wurde, war weg – obwohl das komplette Transkript vorlag. Jetzt gibt es bei jedem Gespräch oben die Zusammenfassung und darunter das Transkript. Und wenn die KI nicht mehr dazu kam, schreibt ein Textmodell die Notiz nachträglich aus dem Transkript: wer, warum, jede Frage samt Antwort, jeder Termin mit Datum und Uhrzeit.
Der Schlüssel, der nie zahlte
Firmen hinterlegen bei Relyper einen eigenen OpenAI-Schlüssel fürs Telefonieren und kreuzen an, welche Modelle er bezahlen darf. Eine Firma hatte gpt-realtime-2.1 angekreuzt – die AI Factory fragte aber fest nach gpt-realtime. Der Vergleich ist exakt, der Schlüssel wurde übersprungen, und jeder Anruf lief still auf Relypers Schlüssel.
Zwei Fehler auf einmal: Das Modell darf nicht in der Software festgeschrieben sein, und ein Rückfall darf nie still passieren. Jetzt kommt das Modell aus der Liste, die Relyper für den zahlenden Schlüssel meldet – wählbar pro Leitung und pro Nummer, aber nie außerhalb dieser Liste. Passt ein Modell nicht zum Schlüssel, gibt es einen klaren Fehler statt einer stillen Umleitung. Welcher Schlüssel bezahlt hat, steht seitdem bei jedem Anruf im Monitor: Firmen-Schlüssel oder Relyper-Schlüssel.
Und noch ein Nebeneffekt des Modellwechsels: Deutsch mit amerikanischem Akzent. Dem Modell musste erst gesagt werden, dass es Hochdeutsch wie eine Muttersprachlerin sprechen soll, und die Transkription bekam die Sprache mit – vorher hielt sie einen deutschen Satz schon mal für Niederländisch.
Damit es sich wie ein Gespräch anfühlt
Technisch läuft der Anruf, dann kommt der Feinschliff. Ein harter Schnitt mitten im Satz wirkt kaputt, deshalb gibt es 30 Sekunden vor dem weichen Zeitlimit (5 Minuten) einen sanften Hinweis, und die KI führt das Gespräch selbst zum Ende. Die harte Grenze liegt bei 10 Minuten. Und die Verabschiedung wird nicht mehr abgeschnitten, weil die Leitung erst nach einer kurzen Nachlaufzeit aufgelegt wird.
Wie wir testen
| Ebene | Was | Ergebnis |
|---|---|---|
| Unit-Tests | Fake-Sprachmodell, echte WebSockets, Fake-Asterisk; Regeln, Limits, Failover, Abrechnung | 58 Tests grün |
| End-to-End | Echter Asterisk plus zweiter Asterisk als Fake-Anbieter, zwei Firmen mit eigenen Konten | 16 von 16 Prüfungen grün |
| Firmen-Wallet | Echte Datenbank, parallele Auszahlungen | 13 Prüfungen grün |
| Echte Anrufe | Leitungstest, Testanruf, KI-Gespräche über sipgate | Fanden Rauschen, 40-Sekunden-Abbruch, Token-Abbruch, Absender-Ablehnung, den stummen Halbsatz, den falschen Schlüssel |
Im Produkt stecken außerdem eigene Testwerkzeuge: der Leitungstest ohne KI (die Leitung ruft an, spielt eine Ansage und dann ein Echo – man hört sich selbst, damit sind Registrierung, ausgehender Anruf und Ton in beide Richtungen auf einmal geprüft), ein Testanruf, der bewusst mit „Hier ist Relyper“ beginnt, damit der Angerufene nicht sofort auflegt, und ein KI-Testanruf mit Auswahl von Modell und Leitung. Jedes beendete Gespräch speichert seinen Abbruchgrund.
Coins und Kosten
Jede angefangene Minute kostet standardmäßig 5 Cent in Relyper-Coins, und vor dem Anruf muss der Zahler mindestens eine Minute decken. Pro Firma lässt sich wählen, wer zahlt: die Person, die den Anruf auslöst, oder das Firmen-Wallet. Abgebucht wird nach dem Anruf, und zwar nie doppelt. Leitungstests, Testanrufe und Ansagen bei nicht erreichbarem Modell sind kostenlos. Gegen Kostenexplosionen gibt es Limits: 5 KI-Anrufe pro Stunde, die Zeitlimits von oben und nur erlaubte Vorwahlen (Standard +49).
Das Ergebnis
Am 6. Oktober führt Jarvis stabile Gespräche bis 10 Minuten, überlebt Aussetzer des Sprachmodells, ignoriert Hintergrundgeräusche und verabschiedet sich, ohne abgeschnitten zu werden. Bei persönlichen Anrufen speichert der Monitor nur Zeit, Nummern, Person und Dauer – keine Transkripte. Der KI-Hinweis kommt immer im ersten Satz.
Was ich gelernt habe:
- Grüne Tests heißen nicht, dass das Telefon gut klingt. 16 von 16 Prüfungen bestanden, aber Rauschen, Frame-Größen und Anbieter-Eigenheiten zeigt nur ein echter Anruf.
- Audio ist binär. Git, Docker-Volumes und Build-Caches behandeln Dateien nicht so, wie man denkt.
- Jeder Anbieter ist anders. Standard auf dem Papier, Sonderfall in der Praxis.
- Fehler sind nicht gleich Abbruch. Viele „error“-Meldungen des Modells sind harmlos.
- Ein öffentlicher SIP-Port wird sofort angegriffen. Zugriffsliste von Anfang an.
- Gespräche brauchen weiche Grenzen. Ein Hinweis vor dem Ende wirkt besser als ein harter Schnitt.
- Diagnose einbauen, bevor man sie braucht. Erst Close-Code, Bytes und Warteschlange im Protokoll haben den 40-Sekunden-Fehler eingegrenzt – und der Grund für jedes Gesprächsende steht seitdem direkt im Monitor, nicht nur im Server-Log.
- Der Fix von gestern ist der Bug von morgen. Kleine Frames statt eines großen: richtig. Alle sofort statt im Takt: der nächste Fehler.
- Nie still zurückfallen. Ein Schlüssel, der nicht passt, muss einen Fehler erzeugen – nicht leise auf einen anderen umleiten.
- Nichts, was gesagt wurde, darf verloren gehen. Das Transkript ist da; wer auflegt, hat trotzdem eine Notiz verdient.
Was als Nächstes kommt
easybell und fonial mit echtem Konto testen, echte Konten bei Twilio, SignalWire und Telnyx, ein End-to-End-Lauf für mehrere Leitungen und WhatsApp Business. Und Jarvis hat inzwischen ein Gesicht bekommen: Aivra.
