Chat agents
Chat agents in logistiek: draaiboek voor de overdracht
De chat agent van een expediteur beantwoordt 80% van de tracking-vragen prima. In die andere 20% zit het geld en het vertrouwen. Dit is het draaiboek dat wij gebruiken.

Het is 19:40 in Rotterdam. Bij een kleine expediteur staan elf gesprekken open in de chat-queue. Acht zijn tracking-pings die de agent in twee seconden beantwoordde. Eén is een klant die vraagt waarom een pallet aankwam met gescheurde krimpfolie. Eén is een Duitse verlader die wil weten of de door de bot beloofde dinsdaglevering 'een echte belofte of een robotbelofte' is. De laatste is een nummer dat de agent nog nooit heeft gezien, met de vraag of het bedrijf gevaarlijke stoffen naar Algerije vervoert.
De chat agent moet sommige hiervan beantwoorden en de rest opschalen. Het hele spel draait om uitvogelen welke welke is, en dat doen voordat de klant het twee keer hoeft te vragen.
Dit is het draaiboek dat wij bij ABN gebruiken voor mkb-logistiek: kleine expediteurs, 3PL's, last-mile-vervoerders en douaneagenten. De meeste waarde van een chat agent in deze hoek komt niet uit het beantwoorden van meer vragen. Hij zit in het op het juiste moment doorzetten van de juiste vragen naar een mens.
Het verkeerde frame: containment maximaliseren
De eerste reflex van elke ops-lead is sturen op 'containment rate', het aandeel gesprekken dat de bot zonder mens afsloot. Leveranciers zijn er dol op, want het is makkelijk te meten en makkelijk op te pompen.
In de logistiek is het de verkeerde knop. Een bot die een chat over een beschadigde pallet 'succesvol' afsluit heeft net een juridisch risico geopend voor jouw klant. Een bot die een dinsdaglevering bevestigt aan een klant wiens zending nog in Antwerpen staat, heeft een vertragingsprobleem omgezet in een vertrouwensprobleem. Een bot die zelfverzekerd zegt dat je Klasse 3 ADR-goederen doet terwijl dat niet zo is, heeft net iets beloofd dat je niet kunt leveren.
De juiste knop is lastiger te meten: overdrachtskwaliteit. Heeft de bot de momenten doorgezet die om een mens vroegen, met genoeg context dat die mens er binnen dertig seconden in zit?
Vijf triggers die altijd opschalen
Deze staan niet ter discussie in elke logistieke implementatie die we hebben opgeleverd. De chat agent probeert ze nooit zelf af te sluiten, vraagt nooit 'kan ik je nog ergens mee helpen?' en biedt nooit een omweg aan. Hij draagt de chat over aan een mens en houdt zijn mond.
Geld in het spel
Elke zin met een offerte-aanvraag, een terugbetaling, een creditnota, een betwiste factuur of een schadeclaim. Bots zijn slecht in de grens tussen 'het spijt me' en 'wij aanvaarden aansprakelijkheid'. De juridische kosten van één verkeerd woord zijn groter dan een jaar besparing met de bot.
Een gereguleerde lading
Gevaarlijke stoffen (ADR, IMDG), farma cold chain, levende dieren, wapens, alles wat onder exportcontrole valt. De bot hoeft de regels niet te kennen. Hij moet de kernwoorden herkennen en een stap terug doen.
Een nieuwe klant die naar voorwaarden vraagt
Als de chat komt van een contact dat het systeem nog nooit heeft gefactureerd en het gesprek gaat over prijzen, kredietvoorwaarden of contracttaal: opschalen. Onboarding van nieuwe klanten hoort bij sales, niet bij een chat agent.
Klantsentiment onder een drempel
Elk klantbericht krijgt een snelle sentiment-pass. Twee negatieve berichten op rij, of één bericht met sterke frustratiesignalen ('onacceptabel', 'klacht', 'advocaat'), gaat direct naar een mens.
Herhaalde bot-fout
Als de bot dezelfde klant al twee keer heeft beantwoord en de klant nog steeds hetzelfde vraagt, is de bot het probleem. Draag over vóór de derde 'nee, ik bedoel...'.
Drie triggers op basis van vertrouwen, niet onderwerp
Die vijf hierboven zijn content-regels. Ze vuren op wat de klant zei. De volgende drie vuren op wat de bot wil zeggen.
Retrieval onder een drempelwaarde
We meten in de RAG-laag zowel een antwoord als een vertrouwensscore op basis van similarity van de opgehaalde chunks. Onder 0,62 cosine similarity op de top-chunk (jouw getal zal afwijken, dus kalibreer 'm op een gelabelde set) geeft de bot geen antwoord. Hij draagt over. De klant ziet nooit 'ik weet het niet zeker, maar...', wat hen aanleert om alles wat daarna komt te wantrouwen.
Tool-call faalt
Als de bot een zending opzoekt in het TMS en die lookup geeft een fout of verouderde data terug: opschalen. Niets verzinnen. Niet 'momentje' zeggen en het nog eens proberen. De dispatcher kan de vervoerder in vijf seconden bellen; de bot niet.
Hallucinatie-zelfcheck
Voordat we een antwoord versturen met een datum, een prijs of een regelgevende uitspraak, draaien we een goedkope tweede pass die het model vraagt: 'is dit gegrond in de opgehaalde context, ja of nee?', met een korte gestructureerde prompt. Een 'nee' gaat naar een mens. Dit vangt het zeldzame geval waarin het model zelfverzekerd een leverdatum uit het niets verzint.
De overdracht zelf: onder dertig seconden of mislukt
Een overdracht is niet 'ik verbind je door met een collega'. Dat is uitstel. Een echte overdracht heeft drie delen:
- Een mens krijgt een melding in een kanaal dat hij ook echt in de gaten houdt, meestal een Slack-kanaal, soms een rinkelende telefoon, bijna nooit een mail.
- Die mens pakt op met volledige context: klantnaam, accounthistorie, de samenvatting van de bot tot nu toe en de specifieke reden voor de opschaling.
- De klant ziet één bericht: 'Marieke van dispatch pakt dit nu op.' Geen vijf alinea's verontschuldiging.
Routing-code, vereenvoudigd uit een recente implementatie:
type HandoffReason =
| "money"
| "regulated_cargo"
| "new_account_terms"
| "negative_sentiment"
| "repeat_failure"
| "low_confidence"
| "tool_error"
| "ungrounded";
interface HandoffDecision {
escalate: boolean;
reason?: HandoffReason;
summary: string;
}
async function decide(
msg: CustomerMessage,
ctx: ConversationContext,
draft: AgentDraft,
): Promise<HandoffDecision> {
if (containsClaimLanguage(msg.text)) {
return { escalate: true, reason: "money", summary: summarise(ctx) };
}
if (matchesRegulatedCargo(msg.text)) {
return { escalate: true, reason: "regulated_cargo", summary: summarise(ctx) };
}
if (ctx.account.isNew && mentionsTerms(msg.text)) {
return { escalate: true, reason: "new_account_terms", summary: summarise(ctx) };
}
if (ctx.recentSentiment.consecutiveNegative >= 2) {
return { escalate: true, reason: "negative_sentiment", summary: summarise(ctx) };
}
if (ctx.recentBotAnswers.unresolvedRepeats >= 2) {
return { escalate: true, reason: "repeat_failure", summary: summarise(ctx) };
}
if (draft.retrievalConfidence < 0.62) {
return { escalate: true, reason: "low_confidence", summary: summarise(ctx) };
}
if (draft.toolErrors.length > 0) {
return { escalate: true, reason: "tool_error", summary: summarise(ctx) };
}
if (draft.containsFactualClaim && !(await isGrounded(draft, ctx.retrieved))) {
return { escalate: true, reason: "ungrounded", summary: summarise(ctx) };
}
return { escalate: false, summary: "" };
}
De volgorde doet ertoe. Goedkope content-regels eerst, dure model-passes als laatste. De grounding-check kost een model-call; die doen we alleen als al het andere is geslaagd.
Wat de dispatcher ziet
Hier gaat het bij de meeste implementaties mis. De bot schaalt op, maar de mens krijgt een Slack-pingetje met 'nieuwe chat' en moet door twintig beurten scrollen om te snappen wat er speelt. Tegen die tijd heeft de klant vier minuten gewacht en dezelfde vraag opnieuw gesteld.
De dispatcher-view die wij opleveren heeft vier blokken, in deze volgorde:
- Waarom dit op jouw bordje ligt. Eén zin. 'Schadeclaim, krimpfolie gescheurd, pallet 4 van 6.' Of 'ADR-vraag van een nieuwe verlader.' Dat is de hele kop.
- Wie. Klantnaam, bedrijf, accountstatus (bestaand, nieuw, opgeschort), de laatste drie zendingen met status, en eventueel openstaand saldo.
- Wat de bot al heeft gezegd. Een bullet-samenvatting van de beurten van de bot, niet het ruwe transcript. Maximaal vijf regels. Het ruwe transcript zit één klik verderop.
- Voorgestelde vervolgactie. Voorgevulde concept-reactie die de dispatcher kan bewerken en versturen, of weggooien. Nooit automatisch verstuurd; dit is de laatste nuttige bijdrage van de bot.
Het getal om in de gaten te houden is niet containment, maar time-to-human op de chats die een mens nodig hadden. 60% containment met overdrachten onder de 30 seconden wint van 85% containment met rommelige opschalingen, elk kwartaal opnieuw.
Wat we de eerste drie keer fout deden
Drie fouten om te benoemen, want elk team maakt ze.
We probeerden sentiment te scoren met een generieke classifier. Out-of-the-box sentiment-modellen die op productreviews zijn getraind, zijn waardeloos op vrachtchats. 'De pallet is naar de klote' en 'wacht, waar is hij' scoren allebei neutraal. We hebben uiteindelijk een kleine classifier gefinetuned op een paar duizend gelabelde vrachtberichten. Dat kostte een middag en het werkte.
We lieten de bot zich verontschuldigen. Vroege versies van de agent eindigden elke opschaling met drie zinnen 'het spijt me oprecht voor het ongemak'. Klanten haatten het. Nu zegt de bot één korte zin en gaat aan de kant.
We lieten context-windows ongelimiteerd groeien. Bij één klant raakte de chat-geschiedenis per eindklant op twaalfduizend beurten in een jaar. Dat allemaal in elke prompt laden was duur en maakte de bot slechter, niet beter. We vatten nu alles ouder dan de huidige zendingscyclus samen en laden die samenvatting plus de laatste veertig beurten. Het Mattermost-team liep recent tegen een vergelijkbare muur op met een tienduizend-berichten-cap in hun UI; chatgeschiedenis is een budget, geen gratis resource.
Multimodale overdrachten: de foto van beschadigde lading
De overdrachtstrigger met de hoogste waarde die we vorig jaar opleverden was beeldgebaseerd. Een klant stuurt een foto van beschadigde goederen. De bot probeert geen schuldvraag te beantwoorden. Wel haalt hij eruit: aantal pallets in beeld, zichtbaar schadebeeld (drukschade, scheur, nat, contaminatie) en of het SSCC-label leesbaar is. Die extractie gaat naar de overdrachtskaart van de dispatcher, zodat de mens al half-geïnformeerd oppakt.
Laat de bot nooit schade kwantificeren of schuld toewijzen op een schadefoto. Haal waarneembare feiten eruit, draag over, klaar. 'Het lijkt op lichte schade' is een zin die verzekeraars zevencijferige bedragen heeft gekost.
Eén audit die je vandaag kunt draaien
Trek de laatste honderd chats die je team afhandelde en label elke met de juiste uitkomst: had dit bot-only moeten zijn, bot-dan-mens, of mens-only vanaf bericht één. Vergelijk dat met wat je huidige systeem werkelijk deed. Het gat tussen die twee kolommen is je roadmap. We deden deze audit vorige maand voor een 3PL in Tilburg en zagen dat hun agent 14% van de gesprekken opschaalde die bij de bot hadden moeten blijven, en stilletjes 9% afsloot die binnen twee beurten naar een mens had gemoeten. Die 9% is het gevaarlijke getal. De 14% is op te lossen met prompt-tuning. De 9% gaat het bedrijf uiteindelijk een claim of een klant kosten.
Toen we begin dit jaar de chat agent bouwden voor een Nederlandse expediteur, liepen we vooral aan tegen de edge case rond gereguleerde lading: verladers die met omhalen vroegen naar goederen die ze niet zwart op wit wilden noemen. We hebben dat opgelost door elke onduidelijkheid in de ladingbeschrijving als automatische overdracht te behandelen, niet als retrieval-probleem. Wie een chat-laag voor een logistiek bedrijf ontwerpt of herbouwt: ons werk rond AI-agents begint met precies dit soort trigger-map, voordat er één regel prompt is geschreven.
Het kleinste wat je vandaag kunt doen: open je laatste vijftig chat-transcripten en streep elke zin aan waarin een mens had moeten overnemen. Tel ze. Dat getal is de ondergrens van wat je overdrachtslogica moet vangen.
Kern
Containment rate is een ijdelheidsmetric voor chat agents in logistiek. Time-to-human op de chats die een mens nodig hadden, is de echte maat.
FAQ
Wat is containment rate en waarom is het de verkeerde knop voor chat agents in logistiek?
Containment rate is het aandeel chats dat de bot zonder mens afsluit. In de logistiek beloont dat de bot voor het afsluiten van chats die hij had moeten opschalen, zoals schadeclaims, gereguleerde lading en prijsvragen van nieuwe accounts. Stuur in plaats daarvan op overdrachtskwaliteit.
Wanneer moet een logistieke chat agent altijd overdragen aan een mens?
Bij geld (claims, terugbetalingen, creditnota's), gereguleerde lading, nieuwe accounts die naar voorwaarden vragen, twee negatieve berichten op rij, herhaalde bot-fouten, lage retrieval-confidence, fouten bij tool-calls en niet-onderbouwde feitelijke uitspraken.
Welke confidence-drempel moeten we hanteren om van RAG naar een mens op te schalen?
Begin rond 0,62 cosine similarity op de top-chunk en kalibreer dat op een gelabelde set echte chats uit jouw operatie. Het exacte getal is minder belangrijk dan dat je het meet en ernaar handelt.
Moet een chat agent schade beoordelen op basis van een klantfoto?
Nee. Haal waarneembare feiten eruit (aantal pallets, zichtbaar schadebeeld, leesbaarheid van het label) en draag over aan een mens. De bot schade laten kwantificeren of schuld laten toewijzen creëert juridisch risico.
Hoe snel moet een mens overnemen nadat een chat agent opschaalt?
Onder de dertig seconden. Daarna stelt de klant dezelfde vraag opnieuw en voelt de overdracht als uitstel. De dispatcher-kaart moet de reden, klanthistorie en een bot-samenvatting bevatten zodat de context er meteen is.