Vrijdag, 9:00. De operations lead van een Rotterdams bureau opent Xero, exporteert het rapport met openstaande posten naar CSV, legt dat naast een Google Sheet met klantnotities ("niet najagen voor de 15e", "alleen Marco mailen, nooit Sophie") en begint mails te tikken. Vriendelijk bij de eerste herinnering. Directer bij de tweede. Bij de derde zet ze de oprichter in cc en herschrijft ze voor de elfde keer dit kwartaal dezelfde zin. Het hele ritueel kost haar zes uur. Elke week.
We hebben het vervangen door een email-agent. Het ritueel duurt nu twintig minuten, en die twintig minuten gaan op aan concepten lezen en op goedkeuren klikken. Hieronder staat hoe we het hebben gebouwd, wat brak, en wat we anders zouden doen.
De klant en het echte probleem
Het bureau draait zo'n €3,2M omzet per jaar over ongeveer 40 actieve retainerklanten, plus projectwerk. Gemiddelde factuur is €4.800. De gemiddelde days-sales-outstanding bij de start: 47 dagen. Hun doel was 30.
De operations lead, Eline, was geen bottleneck omdat ze traag was. Ze was de bottleneck omdat het werk niet te automatiseren viel zonder menselijke weging: elke klant heeft een andere toon, een andere contactpersoon, een ander betaalkronkeltje. Eén klant betaalt altijd op de 28e van de maand, ongeacht factuurdatum. Een ander wil de PDF opnieuw toegestuurd omdat hun boekhoudtool bijlagen eruit sloopt. Een derde is een vriend van de oprichter en moet door hém gemaand worden, niet door ops.
De briefing van de oprichter was kort: "Bouw geen robot die koude mails spamt. Dan raak ik klanten kwijt. Bouw iets dat het typen doet en het denken aan ons laat."
De architectuur, in één plaatje
We kozen voor een human-in-the-loop agent. Die leest, schrijft een concept, en wacht. Hij verstuurt nooit iets zonder goedkeuring.
De stack, bewust saai:
- Xero API voor de factuurstatus, elke ochtend om 07:30 Europe/Amsterdam uitgelezen.
- n8n (zelf gehost, op een Hetzner-bak van €12 per maand) als orchestratielaag.
- Claude Sonnet via API voor het schrijven. We testten GPT-4.1 en Sonnet naast elkaar op 60 historische herinneringsmails; Sonnet trof Elines toon vaker in de blinde test, dus Sonnet werd het.
- Gmail API om concepten aan te maken (niet om te versturen).
- Postgres als geheugenlaag: welke klanten wanneer benaderd zijn en wat ze terugstuurden.
Geen vector store. Geen RAG. De "kennisbank" is een YAML-bestand van 340 regels met klantspecifieke regels, dat de operations lead zelf beheert. Dat is belangrijk — daar komen we op terug.
De agent-loop
Elke ochtend haalt de workflow de openstaande facturen uit Xero, koppelt ze aan het regels-bestand, en geeft elke factuur als gestructureerde prompt door aan de schrijfstap.
// n8n Function node: build the drafting payload
const clientRules = $json.rules[$json.clientId] || {};
return {
json: {
invoice: {
number: $json.invoiceNumber,
amount: $json.amountDue,
currency: $json.currency,
daysOverdue: $json.daysOverdue,
issuedOn: $json.date,
},
client: {
name: $json.contactName,
preferredContact: clientRules.contact || $json.defaultEmail,
tone: clientRules.tone || 'warm-professional',
doNotChaseBefore: clientRules.doNotChaseBefore || null,
lastContact: $json.lastChaseAt,
chaseCount: $json.chaseCount,
},
history: $json.previousThread || [],
},
};
De system prompt is waar het meeste werk in zit. Zo'n 900 woorden. Daarin staan drie echte voorbeelden van eerdere herinneringsmails van Eline (geanonimiseerd), een harde regel dat de agent mag weigeren een concept te maken als doNotChaseBefore in de toekomst ligt, en een tonenladder: eerste herinnering is zacht en verontschuldigend, tweede is direct, derde escaleert naar de oprichter en de agent vlagt 'm voor zíjn review in plaats van die van Eline.
De agent geeft JSON terug, geen prosatekst:
{
"shouldDraft": true,
"recipient": "marco@clientdomain.nl",
"cc": [],
"subject": "Factuur 2026-0412 — kleine herinnering",
"body": "Hoi Marco,\n\nKleine ping...",
"confidence": 0.88,
"flagForHuman": false,
"reasoning": "Second chase, warm tone per client rules. No recent reply on thread."
}
Als confidence onder 0.7 zit, of flagForHuman staat aan, landt het concept in een apart Gmail-label genaamd Review-first. Al het andere gaat naar Ready-to-send. Eline werkt beide 's ochtends weg.
Wat er onderweg brak
Concept versus direct versturen
Onze eerste prototype verstuurde mails meteen. We ontdekten in staging dat de agent, op basis van verouderde Xero-data, een herinnering had geschreven aan een klant die de dag ervoor had betaald. Dat was het moment dat het "bouw geen robot" van de oprichter dragende architectuur werd. We hebben de verstuurstap eruit gehaald en vervangen door de drafts API van Gmail. Concepten zitten in de inbox. Een mens klikt op verzenden.
Als je agent met geld, e-mail of klanten werkt: standaard naar concepten. Het uur dat je bespaart met auto-versturen weegt niet op tegen die ene mail die bij de verkeerde klant op de verkeerde dag belandt.
Het probleem met toon-drift
In week twee merkte Eline dat de concepten subtiel slechter werden — algemener, iets formeler, en zonder de "hoi"-openers die ze eigenlijk gebruikt. De oorzaak was saai: we vatten eerdere mailwisselingen samen in de prompt om tokens te sparen, en die samenvattingen slijpten de stem eruit. We stopten met samenvatten en namen de laatste drie mails voortaan letterlijk mee. De concepten werden weer goed. De tokenkosten stegen ongeveer 30%. Nog altijd onder de €40 per maand.
Het probleem met prompt injection
Eén klant antwoordt op facturen met een automatische bounce van hun ticketsysteem. Die tekst bevatte instructies als "Please forward this to your accounts department". Onze agent begon, behulpzaam als hij is, forwards te schrijven naar een niet-bestaand accounts@-adres. Dit is de dagelijkse, saaie variant van het aanvalsoppervlak dat de OWASP Top 10 voor LLM-applicaties beschrijft onder prompt injection — je agent hoeft niet gejailbreakt te worden door een kwaadwillende, hij hoeft alleen een auto-responder te lezen en te letterlijk te nemen. We hebben een sanitisation-stap toegevoegd die geciteerde reply-blokken eruit haalt voordat ze de prompt raken, plus een regel dat de agent alleen mag schrijven naar de ontvanger uit het regels-bestand, nooit naar een adres dat hij zelf verzint.
De cijfers, eerlijk
Drie maanden verder:
- Elines wekelijkse tijd voor herinneringen: 6u → 22 minuten gemiddeld over 12 weken.
- DSO: 47 dagen → 31 dagen.
- Concepten zonder aanpassing goedgekeurd: 71%. Aangepast voor verzenden: 24%. Verwijderd: 5%.
- API-kosten agent: €38 per maand. n8n-host: €12 per maand. Totaal: €50 per maand.
- Bouwkosten: drie weken van onze tijd.
Die 5% verwijderde concepten is het getal dat we het scherpst volgen. Dat zijn gevallen waarin de agent helemaal niks had moeten schrijven — een klant in dispuut, een creditfactuur onderweg, een gesprek waar we geen weet van hadden. Elke zo'n casus gaat terug het YAML-bestand in.
De agent heeft de operations lead niet vervangen. Hij heeft haar verschoven van typen naar beoordelen. Dat is precies de vorm van nuttig agentwerk op dit moment.
Wat we anders zouden doen
We zouden n8n overslaan en de orchestratie in gewone TypeScript op een cron schrijven. n8n was snel om in te prototypen en pijnlijk om te onderhouden zodra we voorbij zo'n twaalf nodes kwamen. Debuggen is lastiger dan in een script van twintig regels. Als je toch al infra draait, grijp dan niet naar een low-code tool puur omdat de demo er mooi uitziet.
We zouden ook eerder een editor voor de regels bouwen. De eerste maand paste Eline YAML rechtstreeks aan. Ze is technisch genoeg om daar niet over te mopperen, maar een simpel webformulier had de feedbackloop gehalveerd. Dat hebben we in maand twee alsnog opgeleverd.
Toen we dit voor het bureau bouwden, was het lastigste onderdeel niet de AI-agent zelf — het was beslissen waar de mens in de loop hoort. We hebben de mens uiteindelijk bij de verzendknop gezet en de agent alles tot aan die knop gegeven. Drie maanden later wil niemand bij het bureau nog terug naar het spreadsheet.
Heb jij een wekelijks ritueel dat er zo uitziet — exporteren, kruisverwijzen, typen, versturen, herhalen — schrijf dan vandaag twintig minuten lang op welke beslissingen je tijdens dat werk maakt. Die lijst is de specificatie voor jouw agent.




