Voice agents
Voice-agent in de ouderenzorg: 1.180 belletjes per week
Een Goudse zorgcoöperatie met 31 medewerkers verdronk in 1.180 terugbelverzoeken van familie per week. We zetten een Nederlandse voice-agent voor hun Nedap Ons EPD. Dit is wat brak.

Dinsdag, 09:14. De teamcoördinator van een Goudse zorgcoöperatie met 31 medewerkers houdt een geprinte terugbellijst vast. Er staan 38 namen op, alleen al van maandag. De meeste zijn familieleden die naar hun vader of moeder vragen. Twaalf zijn urgent. Drie van die twaalf wachten al sinds zondag.
Dit was de situatie voordat we voor hen een Nederlandse voice-agent bouwden. Zes maanden later handelt de agent zo’n 1.180 terugbelverzoeken van familie per week af, routeert Wzd-relevante signalen binnen 60 seconden naar een senior verpleegkundige, en schrijft alles terug in een elf jaar oude Nedap Ons-installatie. De agent vergeet ook dingen op een strak tijdschema, en dat bleek het lastigste onderdeel van het project.
Dit stuk gaat over het deel dat je niet ziet in demo’s van voice-agents. Echt EPD, echte Wkkgz, echte escalatiepaden. De cijfers zijn op verzoek van de klant geanonimiseerd.
Het beginprobleem
De coöperatie runt vier kleinschalige zorgwoningen plus een dagopvanglocatie. Eenendertig medewerkers. Op elk moment ongeveer 78 bewoners, de meesten met een vorm van dementie. Het team is goed. Het telefoonsysteem minder.
Er gebeurden drie dingen tegelijk.
Familieleden belden op alle uren naar de centrale lijn, vooral tijdens de dienstwissel, voor een update over pa of ma. De dagdienst nam tijdens de medicatieronde op. De nachtdienst kreeg om 23:00 telefoontjes van bezorgde zonen uit Australië. Niemand legde iets consistent vast.
Het Nedap Ons EPD had elf jaar aan klinische geschiedenis erin. Nieuwe zorgnotities gingen erin. Familiegesprekken niet. Dus toen een zoon twee dagen later terugbelde en zei ‘ik heb vrijdag iemand gesproken over het slikken van mijn vader’, kon niemand de notitie vinden.
En dan de BOPZ-vlag, die feitelijk een Wzd-vlag is sinds de wet op 1 januari 2020 veranderde. Bepaalde signalen van familie (‘ze zei dat ze weg wilde’, ‘hij heeft haar weer geslagen’, ‘ze hebben vanochtend medicatie geweigerd’) moeten door een gekwalificeerde zorgverlener worden getrieerd en met tijdstempels worden vastgelegd. Voicemailboxen doen dat niet.
De coöperatie had twee opties. Twee fte’s aannemen om een terugbeldesk te bemensen. Of iets bouwen. Ze vroegen ons om optie twee te scopen.
Wat we bouwden, in één alinea
Een Nederlandstalige voice-agent neemt het centrale terugbelnummer op. Hij identificeert de beller, haalt het cliëntdossier op uit Nedap Ons via een dunne middleware, leest de meest recente zorgnotities terug die de familie mag horen, neemt nieuwe informatie op, schrijft die terug als een gestructureerde notitie, en escaleert bij elke Wzd-relevante zin per sms en push naar de senior verpleegkundige die dienst heeft. Gesprekken worden opgenomen; transcripten blijven zeven jaar bewaard conform Wkkgz; ruwe audio wordt na 90 dagen verwijderd.
Die alinea kostte vijf maanden om uit te rollen.
De elf jaar oude Nedap Ons
Nedap Ons is in Nederland het dominante EPD voor de VVT (Verpleging, Verzorging en Thuiszorg). Er is een gedocumenteerde API en er zijn meerdere integratiepartners. De installatie die wij erfden liep ongeveer drie jaar achter op het huidige API-contract. Twee van de endpoints die we nodig hadden waren afgeschaft en één was vervangen door een totaal andere resource-vorm.
De coöperatie ging voor ons project geen EPD-upgrade doen. Dat zou op zichzelf al een programma van zes cijfers zijn geweest. Dus bouwden we een dunne adapter die aan de Nedap-kant het oude contract spreekt en aan de kant van onze agent het nieuwe. Hij draait als een kleine Node-service binnen het netwerk van de coöperatie.
Een representatief leespad ziet er zo uit:
// adapter/getResident.ts
// Speaks legacy Nedap Ons on one side, our internal contract on the other.
import { onsClient } from "./onsClient";
import type { Resident } from "../types";
export async function getResident(bsn: string): Promise<Resident | null> {
const legacy = await onsClient.get(`/clienten/${bsn}`);
if (!legacy || legacy.status === "uitgeschreven") return null;
return {
id: legacy.clientId,
voornaam: legacy.voornaam,
achternaam: legacy.achternaam,
geboortedatum: legacy.geboorte,
locatie: legacy.locatie?.naam ?? "onbekend",
// Legacy returned a single array; newer releases split it.
contactpersonen: (legacy.contactpersonen ?? []).map((c) => ({
naam: `${c.voornaam} ${c.achternaam}`.trim(),
relatie: c.relatie,
telefoon: c.telefoon,
autorisatieniveau: c.machtiging ?? "basis",
})),
wzdStatus: legacy.bopz_status ?? "geen", // field still called bopz in storage
};
}
Die laatste regel is precies het soort ding waar je in trapt. De Wet zorg en dwang heeft per 1 januari 2020 BOPZ voor de ouderenzorg vervangen. De Nedap-installatie dateert van vóór die wijziging. Het veld heet in opslag nog steeds bopz_status. Onze agent gebruikt de huidige Wzd-terminologie in transcripten, maar leest en schrijft het oude veld. We hebben dat op drie plekken gedocumenteerd, zodat niemand in 2027 de alias weghaalt en daarmee de escalatielogica breekt.
De 60-secondenregel voor escalatie
De agent luistert tijdens familietelefoontjes naar een vastgestelde set intents. De meeste zijn routine: hoe slaapt ze, heeft de apotheek bezorgd, we komen zaterdag om drie uur langs. Daar volgt een kort feitelijk antwoord uit de zorgnotities die de familie mag horen, en een korte samenvatting wordt terug in Nedap Ons geschreven.
Een tweede set intents triggert een harde escalatie. Dat zijn signalen waarvan de Wzd verlangt dat een gekwalificeerde zorgverlener ze beoordeelt:
- De bewoner zou zorg, eten of medicatie weigeren.
- De bewoner zou fysiek vastgehouden worden of proberen weg te gaan.
- Een familielid meldt nieuwe agressie, valpartijen of een opvallende gedragsverandering.
- Een familielid dient een formele klacht in zoals bedoeld in de Wkkgz.
Zodra de agent een uiting in een van deze categorieën plaatst, gebeuren er binnen 60 seconden drie dingen:
- De agent zegt in het Nederlands dat er kort een verpleegkundige terugbelt en noemt een concreet tijdvenster.
- De gestructureerde notitie wordt met een Wzd-tag naar Nedap Ons geschreven.
- Er gaat een sms plus pushmelding naar de senior verpleegkundige die dienst heeft, met de bewoner, de intentklasse en een transcriptlink die 24 uur geldig is.
Die 60 seconden is geen marketingcijfer. Dat is het ontwerpplafond dat we met de manager zorg van de coöperatie hebben afgesproken. We meten het. De mediaan is 11 seconden. De P95 is 34 seconden. Het traagste pad is sms-aflevering via de carrier, en dat kunnen we niet tunen.
Een voice-agent in de zorg is geen chatbot met een microfoon. Het is een triagesysteem dat toevallig conversational is, en de triageregels staan in Nederlandse wetgeving.
Wkkgz, retentie en de enige schaalbare delete
Audio-retentie is het stukje waar niemand je voor waarschuwt. De coöperatie valt onder de Wet kwaliteit, klachten en geschillen zorg (Wkkgz), plus de WGBO voor de bewaartermijn van klinische dossiers. Verschillende artefacten kennen verschillende plafonds.
Onze splitsing:
- Ruwe audio: 90 dagen. Lang genoeg om een klacht af te handelen, kort genoeg om ons risico klein te houden.
- Transcript met gestructureerde notitie: 7 jaar, weggeschreven in Nedap Ons.
- Geaggregeerde metrics (belvolume, intent-tellingen, escalatielatentie): onbeperkt bewaard, zonder PII.
Negentig dagen is geen wettelijk plafond, dat is onze keuze. Wkkgz staat langer toe. Wij betoogden, en de coöperatie was het ermee eens, dat audio na een paar maanden weinig forensische waarde meer toevoegt bovenop het transcript, en elke extra maand is risico.
Daarmee komen we bij de deletes. We draaien Postgres voor de metadata, en de audio staat in object storage met een TTL. Postgres-deletes zijn de pijnlijke soort. Een stuk dat deze week rondging op Hacker News betoogde dat de enige schaalbare delete in Postgres DROP TABLE is. Dat klinkt flauw, totdat je een calls-tabel hebt die richting de negen cijfers aan rijen gaat en een dagelijkse retentie-job die zich daar doorheen moet vreten. Wij kozen vanaf dag één voor de partitioneringsroute: één tabel per ISO-week, in zijn geheel gedropt op dag 90. De audio-opslaglaag doet zijn eigen ding aan de kant van de bucket.
Als je iets bouwt met audio-retentie in de zorg, modelleer retentie vanaf dag één als een partitioneringsstrategie. Hem achteraf op een enkele dikke calls-tabel proppen, dat is hoe je eindigt met DELETE-jobs die nooit klaar zijn.
Wat brak
Zes dingen zaten niet in de oorspronkelijke scope.
Dialect. De agent moest Zuid-Hollands aankunnen, maar een kwart van de familieleden is eerste-generatie Surinaams, Marokkaans of Turks. Het eerste spraakmodel dat we gebruikten zakte onder de 80% accuratesse voor niet-standaardaccenten. We hebben van model gewisseld en een fallbackpad toegevoegd dat de beller vraagt om in kortere zinnen te herhalen als de confidence laag is. Niet elegant. Wel effectief.
Het ‘hij is er niet meer’-probleem. De zin ‘hij is er niet meer’ kan in het Nederlands betekenen dat de bewoner is overleden, naar een ander huis is verhuisd, of even uit is met familie. Onze eerste intent-classifier las dit als rouw en triggerde een condoleancereactie. Dat is de slechtst denkbare uitkomst als de bewoner eigenlijk met zijn dochter naar de supermarkt is. We vragen nu een tweede beurt context voordat we sterfte-gerelateerde intents classificeren. De agent vraagt door. Dat is prima.
Drift in autorisaties. Nedap Ons bewaart de autorisatie per contact (mag medische details horen, mag financiële details horen). Dat veld verandert in de loop van de tijd, want families ruziën. We cachten het 24 uur, dat is te lang. We zijn naar een cache van 5 minuten gegaan met write-through-invalidatie op de webhook van het EPD. Autorisatielookups gaan nu live naar het EPD voor elke gevoelige onthulling.
Voicemail. Onze agent nam elke oproep aan. Sommige bellers wilden voicemail. We hebben in de openingsprompt een expliciete optie toegevoegd: druk op 9 om een bericht voor het team achter te laten zonder met de assistent te spreken. Ongeveer 8% van de bellers maakt daar gebruik van. Dat zijn vooral oudere partners die niet met een machine willen praten, en dat is een redelijke voorkeur.
Nachtdienst-handoff. De bereikbaarheidsdienst staat in Nedap Ons in een vrij tekstveld, niet gestructureerd. Wij parseerden dat. In de eerste maand brak het twee keer toen iemand de naam met een komma typte. We hebben nu een kleine admin-UI die een gestructureerd bereikbaarheidsrecord wegschrijft, en het EPD-veld wordt vanuit daar synchroon gehouden.
De klachtenroute. De Wkkgz vereist een gedocumenteerde klachtenprocedure. Als een familielid tijdens een gesprek een klacht uit, moet de agent de formele route aanbieden. Wij probeerden dat in het gesprek af te handelen. Dat werkte niet. Mensen willen over klachten met een persoon spreken. De agent classificeert de intent nu, opent een klachtdossier in het zaaksysteem van de coöperatie, en de manager zorg belt nog diezelfde werkdag terug. De taak van de agent is om de klacht te herkennen en op te houden met proberen die op te lossen.
Wat er veranderde voor het team
Na zes maanden in productie, de cijfers van de coöperatie waar wij om geven:
- De mediane reactietijd op familiebellen, gemeten vanaf inkomende oproep tot inhoudelijk antwoord, daalde van 6u 41m (klapper-gedreven) naar 38 seconden.
- De escalatiequeue van de senior verpleegkundigen bevat 7 tot 12 items per dag, allemaal echt klinisch. Routinematige statusbelletjes bereiken hen niet meer.
- Het Wzd-register, dat vroeger aan het eind van de week werd gereconstrueerd uit post-its, schrijft zichzelf nu in realtime.
De coöperatie heeft de twee fte’s niet aangenomen.
De reactie van de medewerkers was gemengd en eerlijk. De teamcoördinator zei dat de klapper feitelijk een nuttig artefact was voor de overdracht tussen diensten, en dat hadden we niet door. We hebben daarom een dagelijkse printbare samenvatting toegevoegd. De nachtdienst is onverkort blij met de agent. De dagdienst had ongeveer tien weken nodig om hem te vertrouwen.
Wat je morgen kunt doen als je een zorgorganisatie runt
Je begint niet met de voice-agent. Je begint met drie dingen.
Breng twee weken lang je belintents in kaart. Print een streepjeslijst. Markeer elke inkomende oproep met een van acht tot twaalf categorieën. Binnen tien werkdagen weet je welk deel routine-status is, welk deel klinisch is, welk deel administratief. Zonder dit scope je de verkeerde agent.
Krijg je EPD-leverancier aan de telefoon en vraag precies op welke API-versie jouw installatie draait en hoe de deprecatiekalender eruitziet. Loop je meer dan twee minor versions achter, plan dan de adapter voordat je de agent plant.
Schrijf je retentiebeleid op, per artefactklasse. Audio, transcripten, gestructureerde notities, metrics. Het getal is niet het punt. Het feit dat je hebt besloten is het punt.
Toen we de voice-agent voor de Goudse coöperatie bouwden, liepen we ertegenaan dat het retentiebeleid onder de Wkkgz niet als één getal binnenkomt. Het komt als vier verschillende getallen, gekoppeld aan vier verschillende artefacten, en de schoonste manier om ze af te dwingen is op tabelniveau, niet op rijniveau. De langere versie van hoe we dit soort werk aanpakken staat op onze pagina over AI-agents.
Als het enige dat je vandaag doet de belintenttelling is, heb je de beslissing al makkelijker gemaakt. Print de lijst nu.
Kern
Een voice-agent in de ouderenzorg is een triagesysteem volgens Nederlandse wetgeving dat toevallig conversational is. De lastige stukken zijn de EPD-adapter en het retentiebeleid, niet de spraak.
FAQ
Vervangt de voice-agent zorgmedewerkers?
Nee. Hij trieert routinegesprekken met familie en escaleert klinische signalen binnen 60 seconden naar een senior verpleegkundige. De klinische beslissingen blijven bij mensen.
Wat als een familielid weigert met een machine te praten?
De openingsprompt biedt een druk-op-9-optie om een voicemail voor het team achter te laten. Ongeveer 8% van de bellers maakt daar gebruik van, vooral oudere partners.
Hoe ga je in een ouder EPD om met BOPZ versus Wzd-terminologie?
De Nedap-installatie gebruikt in opslag nog steeds het oude bopz_status-veld. Wij aliassen het in de adapter als wzdStatus en documenteren die alias op drie plekken, zodat niemand hem weghaalt.
Waarom audio na 90 dagen verwijderen als Wkkgz langer toestaat?
Audio voegt na een paar maanden weinig forensische waarde meer toe bovenop het transcript. Kortere retentie verkleint het risicovlak. Transcripten en gestructureerde notities blijven zeven jaar.
Kun je dit bovenop elk EPD bouwen, of alleen op Nedap Ons?
Het patroon past op elk EPD met een aanroepbare API. Het lastige is zelden de agent. Het is de adapter tussen het contract van vandaag en de versie die de klant feitelijk draait.