Een beller zegt dat hij gebeld heeft en dat het niet werkte. Je dashboard zegt dat het gesprek eindigde met een fout. In die twee zinnen zit het hele probleem: ergens tussen de telefoon van de beller en jouw agent kunnen zeven dingen misgaan, en één woord in een dashboard kan niet vertellen welke. Het antwoord staat bijna altijd in de SIP-dialoog, één laag onder het niveau waar de meeste voice-AI-platformen je laten kijken.
Vier lagen, en slechts één ervan is de AI
Wie een voice-agent debugt grijpt eerst naar de prompt, want dat is het deel dat hij zelf geschreven heeft. Maar een telefoongesprek is een stapel, en het model zit daar bovenin. Onder de agent zit een orchestratielaag die bepaalt welke assistent opneemt en die de sessie vasthoudt. Daaronder zit SIP, het signaleringsprotocol dat het gesprek opzet, uitonderhandelt welke audio beide kanten spreken, en het weer afbreekt. En daaronder, over een compleet eigen route, gaat de media: de RTP-pakketten die de stem dragen.
Die laatste scheiding is het nuttigste dat je je eigen kunt maken. Signalering en media reizen apart. Een gesprek kan op SIP-niveau perfect verbonden zijn terwijl er geen enkele audio loopt, en dat is precies waarom "het gesprek kwam op maar de agent zei nooit iets" een mediaprobleem is en geen promptprobleem. Negentig procent van de verwarring bij het debuggen van voice AI komt doordat de ene stapel wordt behandeld als de andere.
Repareer de laag waar het symptoom woont
Hoe een gezond gesprek er in SIP uitziet
Voordat je een kapotte dialoog kunt herkennen moet je weten hoe een intacte leest. Een inkomend gesprek is een kort en uitermate voorspelbaar gesprek tussen de carrier en jouw platform. De carrier biedt het gesprek aan met een INVITE, met daarin een SDP-blok dat opsomt welke codecs hij kan spreken. Jouw kant bevestigt, laat rinkelen, neemt op met 200 OK en zijn eigen SDP, en beide kanten beginnen RTP te sturen. Hangt iemand op, dan sluit een BYE het af met een reden.
>> INVITE sip:+31570238200@trunk SIP/2.0
From: <sip:+31612345678@carrier>;tag=8f2b
Call-ID: 4c1d9e77-3a2f-4b10-9c8e-11e2a6d0f5aa
SDP: audio 41002 RTP/AVP 8 0 101 (PCMA, PCMU, telephone-event)
<< SIP/2.0 100 Trying
<< SIP/2.0 180 Ringing
<< SIP/2.0 200 OK
SDP: audio 24518 RTP/AVP 8 101 (PCMA agreed)
[rtp] inbound stream established ssrc=0x6b21f0
[rtp] outbound stream established ssrc=0x11c4ae
>> BYE sip:+31570238200@trunk SIP/2.0
Reason: Q.850;cause=16;text="normal clearing"
call ended · 47.2s · two-way audio · caller hung upVier dingen in dat spoor zijn het aanwijzen waard. De Call-ID is de greep die elk pakket, elke logregel en elke opname van dít ene gesprek aan elkaar knoopt, en het is het eerste dat je opvraagt als een klant een probleem meldt. De SDP-regels laten een geslaagde codec-onderhandeling zien: de carrier bood PCMA, PCMU en telephone-event aan, en jouw kant koos PCMA. De twee RTP-regels bevestigen audio in beide richtingen, elk met zijn eigen synchronisatiebron. En de BYE draagt een Q.850-oorzaak, waarmee het telefonienetwerk je in een standaardnummer vertelt waarom het gesprek eindigde.
De responscodes die een storing verklaren
Overleeft een gesprek de opzet niet, dan is de SIP-responscode de diagnose. De meeste voice-platformen persen die allemaal samen tot "mislukt", en gooien daarmee precies de informatie weg waaruit je had kunnen opmaken van wie het probleem is. Dit zijn de codes die je op echte trunks daadwerkelijk tegenkomt.
| Code | Betekent | Van wie is het |
|---|---|---|
| 403 Forbidden | De trunk weigert het verzoek meteen, meestal een IP dat niet op de toegangslijst staat, of inloggegevens die niet kloppen. | Configuratie |
| 404 Not Found | Het nummer bestaat niet op die trunk. Vaak een routeringsregel die nooit is aangemaakt, of een nummer dat is weggeporteerd. | Carrier / routering |
| 407 Proxy Authentication Required | Registratie of digest-authenticatie komt niet rond. Normaal als eerste uitdaging; een probleem als het zich herhaalt. | Configuratie |
| 408 Request Timeout | Niemand reageerde op de signalering. Vaak een firewall die SIP stil laat vallen, niet een bezette lijn. | Netwerk |
| 480 Temporarily Unavailable | De juiste plek bereikt, maar geen eindpunt beschikbaar. Op een AI-trunk betekent dit vaak dat geen worker de sessie oppakte. | Platform |
| 486 Busy Here | Een echte in-gesprektoon, of een plafond op gelijktijdige gesprekken. Check je eigen limieten voor je de carrier de schuld geeft. | Platform / capaciteit |
| 487 Request Terminated | Het gesprek werd geannuleerd voordat het werd opgenomen: de beller hing op tijdens het rinkelen. Geen storing. | Niemand |
| 488 Not Acceptable Here | Codec- of SDP-mismatch. Beide kanten wilden praten en werden het niet eens over hoe. Stil, direct, en nooit de schuld van het model. | Configuratie |
| 503 Service Unavailable | De andere kant leeft maar weigert werk: congestie, een storing bij de carrier, of een component verderop die nee zegt. | Carrier / platform |
De 488 verdient een eigen alinea, want het is de storing die het meest op magie lijkt. Hier hetzelfde gesprek, aangeboden met een codec die de trunk niet mocht accepteren:
>> INVITE sip:+31570238200@trunk SIP/2.0
SDP: audio 41002 RTP/AVP 9 101 (G.722, telephone-event)
<< SIP/2.0 100 Trying
<< SIP/2.0 488 Not Acceptable Here
Warning: 304 "Media type not available"
call never connected · 0.4s · no RTP · no transcriptVierhonderd milliseconden, geen audio, geen transcript, niets wat het model verkeerd gedaan kan hebben. Vanuit een dashboard dat alleen eindredenen rapporteert is dit niet te onderscheiden van een dozijn andere storingen. Vanuit de SIP-dialoog is het een reparatie van vijf minuten in de codeclijst van de trunk.
Eén code verdient vermelding juist omdát hij nooit bij een storing opduikt: OPTIONS. Het is helemaal geen fout, het is een keepalive: een klein periodiek verzoek dat als enige taak heeft de andere kant te vragen of hij er nog is. Zet je OPTIONS-pings aan op een trunk, met een interval in de orde van dertig seconden, dan verandert "leeft de trunk nog" van een vraag die je tijdens een storing beantwoordt in een grafiek waar je vóór een storing naar kunt kijken. Het houdt bovendien NAT-bindingen warm, wat stil een categorie eenrichtingsaudio-storingen voorkomt die hieronder wordt beschreven. Het is de goedkoopste monitoring in de telefonie en hij staat bijna overal standaard uit.
Q.850-oorzaakcodes die je uit je hoofd wilt kennen
Waar SIP het verzoek beschrijft, beschrijft Q.850 wat het telefonienetwerk ervan vond. Oorzaakcodes komen binnen in de Reason-header op een BYE of een CANCEL, en ze overleven het oversteken van gateways. Daardoor dragen ze vaak de waarheid, ook als de SIP-code ergens onderweg is herschreven.
| Oorzaak | Standaardbetekenis | Wat het in de praktijk meestal is |
|---|---|---|
| 1 | Niet-toegekend nummer | Het gedraaide nummer bestaat niet. Bij uitbelcampagnes is dit een datakwaliteitsprobleem, geen platformprobleem. |
| 16 | Normaal beëindigd | Een normale beëindiging van het gesprek. Zie je dit bij een gesprek waarvan de klant zegt dat het mislukte, dan zat de storing in de audio, niet in het gesprek. |
| 17 | Gebruiker in gesprek | Echt bezet, of een toestel dat een tweede gesprek weigert. |
| 19 | Geen antwoord van gebruiker | Het is overgegaan. Controleer je beltijd voordat je aanneemt dat het nummer dood is. |
| 21 | Gesprek geweigerd | Iets zei actief nee: een blokkeerlijst, een spamfilter, of beleid van de carrier op de bestemming. |
| 34 | Geen circuit beschikbaar | Capaciteit, verderop in de keten. Hier is opnieuw proberen zinvol; hard falen niet. |
| 38 | Netwerk buiten dienst | Een echte storing verderop. Dit is de code waarbij je eerst de statuspagina van de carrier opent. |
| 41 | Tijdelijke storing | De vaagste nuttige code. Bijna altijd één keer opnieuw proberen waard. |
| 102 | Herstel na verlopen timer | Iets antwoordde niet op tijd en een timer gaf op. Wijst op latency of een vastgelopen tak, niet op een weigering. |
| 127 | Interworking, niet gespecificeerd | Een gateway heeft iets vertaald en de oorspronkelijke reden verloren. Behandel als 'geen informatie beschikbaar'. |
Eenrichtingsaudio: de klassieker die nooit het model is
De meest voorkomende serieuze klacht bij elke nieuwe voice-uitrol is dat de ene kant de andere niet hoort. De beller hoort de agent prima en de agent doet alsof de beller niets zei, of precies omgekeerd. Het presenteert zich als een AI-storing en het is bijna nooit een AI-storing.
Omdat media over een eigen route gaat, werkt audio alleen als RTP beide eindpunten in beide richtingen kan bereiken. Signalering kan over de ene route wél aankomen terwijl de mediaroute geblokkeerd is, en niets in de SIP-dialoog zal klagen. De gebruikelijke daders zijn voorspelbaar: een firewall die de SIP-poort toestaat maar het RTP-bereik niet, netwerkadrestranslatie die een adres binnen de SDP herschrijft zodat de andere kant pakketten het niets in stuurt, of verwachtingen rond symmetrische RTP waar één kant zich niet aan houdt.
De diagnose is mechanisch, niet slim. Kijk naar de pakkettellers per richting afzonderlijk. Komt inkomende RTP wel binnen en is uitgaand nul, dan heb je een routerings- of filterprobleem op de weg naar buiten, geen transcriptieprobleem. Zijn beide tellers gezond en doet de agent nog steeds alsof hij stilte hoorde, dan pas wordt het een spraakherkenningsvraag.
Dit is de laag waar een doorverkoper niet komt
Als de toetsdruk niet aankomt
Een beller wordt gevraagd 1 te toetsen, toetst 1, en er gebeurt niets. DTMF, de tonen die een toetsenblok maakt, kan op drie verschillende manieren reizen, en een mismatch daartussen is geruisloos. De toon kan als eigen RTP-payloadtype meereizen zoals beschreven in RFC 4733 en zijn voorganger RFC 2833, en dat is wat de telephone-event in de SDP hierboven aankondigt. Hij kan als gewone audio worden meegestuurd, gemengd in de spraakstroom, wat minder tussenstappen overleeft dan mensen verwachten. Of hij kan buiten de mediastroom om worden gestuurd als een SIP INFO-bericht.
Luistert jouw kant naar RTP-events terwijl de carrier tonen in de audio meestuurt, dan zit de toetsdruk fysiek in het geluid en is hij volledig onzichtbaar voor je applicatie. Stel eerst vast welke van de drie daadwerkelijk in gebruik is voordat je iets in de agent aanraakt, en onderhandel bij voorkeur telephone-event in de SDP, zodat de toon aankomt als een losse gebeurtenis en niet als een geluid dat je moet detecteren.
Waarom je eindreden geen diagnose is
Goede platformen geven je per gesprek een deterministische eindreden. Op VoiceDock sluit elk gesprek af met één uit een vaste verzameling: de beller hing op, de assistent hing op, het gesprek is doorverbonden, de maximale duur is bereikt, er is voicemail gedetecteerd, niemand nam op, het krediet was op, of er trad een fout op. Die verzameling is oprecht nuttig voor rapportage, want je kunt uitkomsten tellen zonder vrije tekst te ontleden.
Wat een eindreden niet kan, is een storing verklaren. "Fout" is een categorie, geen oorzaak. De waarde van het bezitten van de laag eronder is dat er, als de categorie niet genoeg is, een volgende vraag te stellen valt: welke SIP-code, welke Q.850-oorzaak, in welke richting ontbrak de RTP, welke Call-ID. Een platform dat stopt bij de eindreden heeft die volgende vraag per ontwerp onbeantwoordbaar gemaakt.
De eindreden vertelt je wat er met het gesprek gebeurde. De SIP-dialoog vertelt je waarom. Je hebt een leverancier nodig die je beide kan overhandigen.
Een triagevolgorde die wél convergeert
Telefonie slecht debuggen betekent vijf dingen tegelijk openzetten. Het goed doen betekent vragen stellen in een volgorde die de zoekruimte elke keer halveert. Dit is de volgorde die wij gebruiken.
- 01
Haal de Call-ID op voor je iets anders doet
Al het andere is gokwerk zonder. Een tijdstip en een bellernummer volstaan als de klant niets anders heeft, maar de Call-ID maakt van een verhaal een registratie. - 02
Stel vast of het gesprek überhaupt tot stand kwam
Een 200 OK splitst het probleem netjes. Geen 200 OK betekent dat de storing in de opzet zit en de responscode hem benoemt. Wel een 200 OK betekent dat de opzet werkte en je doorschuift naar media. - 03
Controleer RTP per richting afzonderlijk
Twee tellers, niet één. Stilte in slechts één richting is een netwerk- of NAT-probleem, en het is de meest waarschijnlijke oorzaak van "de agent negeerde mij". - 04
Lees de afsluitende oorzaak, niet alleen de status
Een Q.850-oorzaak 16 bij een gesprek waarvan de klant zegt dat het mislukte is een sterk signaal: het gesprek was in orde en de ervaring niet. Dat wijst naar audiokwaliteit, latency of de agent, en weg van telefonie. - 05
Open nu pas het transcript en de prompt
Kwam de opzet rond, liep de audio beide kanten op en sloot het gesprek normaal af, dan en alleen dan is het een model- of instructieprobleem, en heb je vier lagen ruis uitgesloten voordat je daar tijd in stopt.
Niets hiervan is exotische kennis. Het is gewone telefonie-engineering, en het is precies wat verdwijnt als een voice-platform het telefoonnetwerk behandelt als een implementatiedetail dat je niet mag zien. Wij publiceren het omdat de vraag niet is of gesprekken op een echt netwerk soms mislukken. Dat doen ze. De vraag is of de mensen met wie je bouwt je kunnen vertellen waarom.
Bronnen Responscodes en dialooggedrag zoals vastgelegd in RFC 3261 (SIP), DTMF-transport in RFC 4733, en oorzaakwaarden uit ITU-T Q.850. De triagevolgorde en de praktijklezingen komen uit onze eigen ervaring met voice-verkeer op productie-trunks.