← Blog

Voice agents

Voice agents in logistiek: Transwide en Oracle 11g playbook

Het planningsteam in Antwerpen verdronk in 2.480 'waar is mijn truck'-calls per week. Het TMS was 14 jaar oud. Zo kwam de voice agent toch live.

Jacob Molkenboer· Oprichter · A Brand New Company· 18 jun 2026· 11 min
Vintage zwarte bakelieten telefoonhoorn op een mosgroen leren vloeiblad, gekrulde snoer over ivoorkleurig papier.

Dinsdag, 06:42, het bureau van de planner in Antwerpen. Drie vaste lijnen knipperen. Eén is een Slowaakse chauffeur die voor de terminal in Liefkenshoek staat en wil weten welke gate. Eén is een Franse verlader die vraagt waarom een pallet van 13 ton twee dagen in Zeebrugge bleef staan. De derde is de klant van de klant, die gisteren ook al belde, ook om 06:42.

Onze klant is een logistiek dienstverlener met 31 mensen in de haven van Antwerpen. Ze rijden zo'n 110 trucks per dag door de Benelux, Duitsland en Noord-Frankrijk, met een vaste douanecorridor van en naar het VK sinds Brexit. Geen grote naam. Goed in hun werk. Geen eigen softwareteam.

Hun dispatch verwerkte 2.480 inkomende calls per week. Onze steekproef van vier weken liet zien dat 71 procent statuscalls waren: waar is mijn truck, wat is mijn ETA, is de douanestop al vrij. De resterende 29 procent waren de calls die een planner echt moet aannemen: nieuwe orders, uitzonderingen, claims, een chauffeur die echt in de problemen zit.

De gemiddelde behandeltijd was 2 minuten 40. Reken het uit en het planningsteam verloor zo'n 78 uur per week aan opzoekwerk dat het al een keer had gedaan. Twee fulltime planners aan aandacht, weg aan vragen waarvan de antwoorden al in twee verschillende systemen stonden.

Dat was de opdracht van de operations lead: bouw een voice agent die die 71 procent overneemt en de andere 29 procent snel teruggeeft aan mensen, zonder een TMS te slopen dat geen enkele developer nog wilde aanraken.

De stack die we erbij kregen

Het TMS was Transwide. Niet de Transwide van vorig jaar. De build uit 2012, nooit geüpgraded, met een eigen EDI-laag die een van de oprichters zelf had geschreven in het jaar dat Belgische truckers de E40 platlegden.

Eronder een Oracle 11g database met de eigenlijke rittenplanning. Een zelfgebouwde PL/SQL-job duwde elke twintig minuten de ritstatus door naar Transwide. Chauffeursscans kwamen binnen per sms via een Belgische carrier waarvan niemand nog een contractprintout had.

Oracle 11g viel in 2015 uit Premier Support en in 2020 uit Extended Support. De instance draaide nog. Niemand had de init.ora sinds 2017 aangeraakt. De DBA was met pensioen.

Herken je je eigen stack hierin, dan ben je niet bijzonder. De vraag is of de voice agent erbovenop de fragiliteit van het verouderde systeem moet erven, of eromheen kan routen. De onze routede eromheen.

Waarom een voice agent, geen chatwidget

Het voor de hand liggende antwoord is dat chauffeurs en verladers belden, niet typten. Het echte antwoord: 38 procent van de inkomende calls kwam van chauffeurs achter het stuur, vaak met de handen aan dat stuur en een Duitse snelweg voor zich. Een chatwidget verliest het altijd van een telefoon in de cabine. Aan de verladerskant zit de statuscall-gewoonte er al decennia in. Mensen die transport boeken pakken de telefoon. We konden het kanaal vervangen, niet het spiergeheugen.

We kozen een voice stack die we konden snappen: ElevenLabs voor synthese (Nederlandse, Franse en Duitse stemmen), Whisper-large-v3 voor transcriptie, getuned op een intern corpus van zes uur afgekapt chauffeursnederlands, en onze eigen dialog state machine. Geen end-to-end voice model. De kosten waren bij dit volume onhoudbaar in medio 2025, en de latency op Benelux-carriers klopte niet.

De data-plumbing die niemand wilde aanraken

Je kunt geen statusvraag beantwoorden als je de status niet kunt zien. Dus voor we één regel dialoog schreven, bouwden we twee leespaden.

Het eerste was een materialized view van 60 seconden over Oracle 11g, ontsloten als een klein REST-servicetje op een aparte VM. De view joinde RIT, STOP, T1_DOC en CHAUFFEUR_SCAN tot één platte rij, met de publieke orderreferentie als sleutel.

CREATE MATERIALIZED VIEW mv_rit_status
  REFRESH FAST ON COMMIT
AS
SELECT r.ref_extern         AS order_ref,
       r.status             AS rit_status,
       s.eta_klant          AS eta_planned,
       s.werkelijk_aankomst AS eta_actual,
       t.t1_nummer          AS t1_doc,
       t.t1_aangemaakt      AS t1_created_at,
       c.laatste_scan       AS last_scan_at,
       c.laatste_locatie    AS last_loc
  FROM rit r
  JOIN stop s        ON s.rit_id = r.id AND s.volgorde = 1
  LEFT JOIN t1_doc t ON t.rit_id = r.id
  LEFT JOIN chauffeur_scan c
         ON c.chauffeur_id = r.chauffeur_id
        AND c.actief = 'J';

Het tweede was een nette, rate-limited pull tegen de Transwide HTTP API voor alles wat Oracle niet bezat (verlader-EDI-events, geplande douanevensters, transbordbevestigingen). De Transwide-API is prima als je hem respecteert. We zaten op 2 calls per seconde per integratietoken en een SQLite-cache van 24 uur voor langzaam veranderende velden.

De voice agent praat nooit rechtstreeks met Oracle. Hij belt onze REST-laag, die SLA's, logging en circuit-breakers heeft die de stack uit 2012 niet kent. Heeft Oracle een moment, en Oracle 11g heeft momenten, dan degradeert de agent naar 'Ik kijk het even na met planning, mag ik je over twaalf minuten terugbellen?' in plaats van de call te laten vallen.

Een minder voor de hand liggende regel: laat je voice agent nooit losse SQL-queries afvuren op de productiedatabase, hoe goed de LLM-naar-SQL-demo's er ook uitzien. Eén verkeerde join in een 14 jaar oud schema lockt een tabel waar de planning-UI van afhangt, en de planner die je net hebt opgezadeld is degene die jouw project bij het volgende MT-overleg moet verdedigen. De agent leest materialized views. Altijd.

De T1-escalatieregel

Van die 2.480 calls per week was de duurste klasse, gemeten in verloren geld in plaats van minuten, douaneproblemen. Een T1-transitdocument is het EU-papier dat goederen onder douanetoezicht laat bewegen zonder bij elke grens rechten te betalen. Komt een truck bij het douanekantoor in Vrasene aan (het standaard vrijgavepunt op de E34 van en naar het VK) met een T1 die langer dan 72 uur openstaat, dan stijgt de kans op een extra inspectie scherp. Een inspectie kost de klant twee tot vier uur chauffeurstijd en een sleuf in de dag van de planner.

De regel die we implementeerden, in één alinea: elke beller die vraagt naar een order met een open T1-document ouder dan 72 uur, waarvan de geplande route Vrasene binnen 90 minuten kruist, gaat direct van de voice agent af en valt in een hot planner-queue. Geen voicemail. Een live transfer met de volledige context al voorgeladen op het scherm van de planner.

def should_escalate(call_context, order):
    if not order.t1_doc:
        return False
    if (now() - order.t1_doc.created_at) < timedelta(hours=72):
        return False
    if not crosses_vrasene_within(order, minutes=90):
        return False
    return True

# in the dialog state machine
if should_escalate(ctx, order):
    transfer_to(queue="planning_hot", context=ctx)
    return

De 90 minuten zijn niet willekeurig. Het is de tijd die een chauffeur doet over het stuk vanaf de uitgang van de Liefkenshoektunnel tot het vrijgavepunt Vrasene bij gemiddeld havengebiedverkeer. Krijgt de planner de call voor dat venster sluit, dan kan hij de douanesleuf herboeken, een gecorrigeerde T1 naar het douaneportaal sturen, of, in twee van de vijf gevallen, de truck naar een ander vrijgavepunt sturen. Voorbij Vrasene klappen de opties dicht.

Takeaway

Het punt van een voice agent in logistiek is niet om 100 procent van de calls te beantwoorden. Het is om meedogenloos te zijn over de 8 procent die hij niet mag beantwoorden, en die met volledige context over te dragen voor de truck het point of no return passeert.

Hoe de maandag van het planningsteam eruitzag na vier weken

Acht weken na go-live zag het voortschrijdend gemiddelde over vier weken er zo uit:

  • 71 procent van de statuscalls volledig afgehandeld door de agent, zonder menselijke transfer.
  • 9 procent op verzoek van de beller doorverbonden ('Ik wil iemand spreken').
  • 8 procent geëscaleerd via een regel. T1 plus nabijheid Vrasene was de grootste klasse, met kleinere triggers voor Duitse Maut-overtredingen en een Frans SIVEP-venster voor visimport.
  • 12 procent die de agent niet aankon: nieuwe orders, claims, klachten, calls in het Pools (we leverden Nederlands, Frans, Duits en Engels).

Het callvolume voor het planningsteam zakte van 2.480 naar 740. De behandeltijd op de calls die ze wel pakten liep op, naar 4 minuten 10, omdat de overgebleven calls de calls waren die het nemen waard waren. Twee planners verschoven van de telefoon naar de douane- en exception-balie, fulltime. Niemand werd ontslagen. De chauffeurs merkten het als eersten; eentje stuurde het kantoor een doos Luikse wafels.

De carrier was het lastige stuk

Niet het model was de bottleneck. Whisper-large-v3 transcribeerde chauffeursnederlands goed genoeg op een bureautoestel in een stil kantoor. De bottleneck was de audio die het model daadwerkelijk bereikte. Een chauffeur op de speaker in een rijdende Volvo op 130 km/u op de A2, in roaming op een Duitse MVNO, klinkt niets als de schone telefoonaudio in een publieke benchmark.

In de eerste week echt verkeer verstond de agent ongeveer de helft van de orderreferenties verkeerd. We hadden bijna de hele transcriptielaag opnieuw gebouwd. In plaats daarvan voegden we één bevestigingsbeurt toe na elke orderreferentie: 'Ik heb order 4-4-1-7-2, klopt dat?'. Misreads zakten van 51 procent naar onder de 3 procent. De prijs: één extra seconde per call, en weer een klein deukje in het 'natuurlijke' gevoel dat we sowieso al hadden opgegeven.

Het tweede carrierprobleem was lelijker. Twee dagen na go-live begon de agent calls uit één SIM-range te droppen op de 17e seconde. De TTS-provider had heronderhandeld naar een codec die de carrier stilletjes downgradede, en na zeventien seconden klapte de audio-framebuffer in. We hebben de codec aan onze kant vastgezet en een heartbeat-test toegevoegd tegen vier Belgische carriers die elke vijftien minuten draait. De dashboards van die test hangen nu aan de muur van de plannersruimte, want planners geven om codecs meer dan wij.

Wat we niet meer zo zouden doen

Drie dingen, op volgorde van spijt.

Eén: we hebben twee weken besteed aan het tunen van prompts om de agent 'natuurlijk' te laten klinken. De chauffeurs wilden niet natuurlijk. Ze wilden voorspelbaar. Ze wilden dat de agent het ordernummer terugzei, de ETA noemde, het volgende checkpoint noemde, en ze laat gaan. We knipten de helft van de conversationele steigers weg en de tevredenheidsscore ging omhoog.

Twee: we bouwden onze eigen escalatiequeue-UI voor we hadden gekeken wat de planners al gebruikten. Die zaten in het planning board van Transwide. We hebben onze queue herbouwd als een rij in dat board, kleurgecodeerd per escalatieregel. Adoptie ging van 'gedwongen' naar 'ze vragen nu zelf om nieuwe escalatieklassen'.

Drie: we hebben de eerste maand te weinig in observability gestoken. Voice agents falen op manieren die chat agents niet kennen: een lock in de dialog state, een hiccup bij de TTS-provider, een carrier die midden in een call een codec heronderhandelt. We loggen nu elke beurt met audio, transcript, dialog state en downstream API-timings. Een mislukte call is een fragment van 90 seconden waar een planner naar kan luisteren, niet een rij in een logtabel.

Het kleinste dat je deze week kunt doen

Ga twee uur naast je dispatchteam zitten op een normale dinsdag. Verdeel de inkomende calls in drie bakjes: status, uitzondering, nieuwe business. Zit het statusbakje boven de helft, dan heb je een voice-agent-probleem, geen bezettingsprobleem. De volgende vraag, welke 8 procent nooit naar de agent mag, bepaalt of je project live gaat of in een slidedeck blijft hangen.

Toen we de voice agent voor de Antwerpse klant bouwden, kwamen we er telkens op uit dat het 14 jaar oude Transwide-schema en de Oracle 11g-instance eronder elk waren gepatcht door verschillende mensen over een decennium, en dat niets was vastgelegd. Uiteindelijk hebben we voor we aan de dialoog begonnen één pagina glossarium geschreven met veldnamen en hun betekenis, en dat glossarium werd het contract tussen de voice agent en het planningsteam. Sta je voor vergelijkbaar werk op een verouderde stack, dan zijn onze notities over het live krijgen van AI-agents tegen systemen die ouder zijn dan het team dat ze draait geschreven uit dit soort weken.

Kern

Een voice agent in logistiek gaat niet om elke call beantwoorden. Het gaat om meedogenloos zijn over welke calls moeten escaleren voor de volgende grens.

FAQ

Hoe voorkom je dat een voice agent een ETA hallucineert?

Veranker elke ETA in een benoemd databaseveld met een timestamp. Ontbreekt het veld of is het ouder dan een drempel, dan verbindt de agent door naar planning in plaats van er één te verzinnen. Laat het model nooit een getal genereren.

Kan een voice agent praten met een 14 jaar oud TMS?

Ja, maar niet rechtstreeks. Bouw een kleine leeslaag over een materialized view of een cache en laat de agent dáár mee praten. Laat een door een LLM gestuurde agent nooit ad-hoc queries afvuren op een verouderde productiedatabase.

Hoe reken je de ROI van een logistieke voice agent uit?

Neem het wekelijkse aantal inkomende calls, vermenigvuldig met de gemiddelde behandeltijd, vermenigvuldig met de loaded cost van een dispatcher. Is 60 tot 80 procent statusopzoekwerk, dan is dat het bedrag dat je terugwint, minus de runkosten van de agent.

Met welke talen moet een Benelux-voice-agent live gaan?

Nederlands, Frans, Duits en Engels dekken de chauffeur- en verladerspopulatie van de meeste Belgische operators. Pools is de volgende. Veel chauffeurs in Noordwest-Europa spreken het als eerste taal.

Wat is de grootste valkuil?

Niet de LLM. De carrier. Audiokwaliteit en codecnegotiatie op Benelux-mobielnetwerken variëren per toestel en per 4G/5G-fallback. Test op echte chauffeurstoestellen, niet op een bureautoestel.

voice agentsautomationlegacy sitesintegrationscase studyoperations

Iets bouwen?

Start een project