← Blog

Chat agents

Chat agents bij accountants: de 60-secondes-SLA in Zwolle

Het is 17:42 op een dinsdag in Zwolle. Een accountantskantoor van 27 man heeft achttien minuten tot het SBR-loket sluit. De chat-agent heeft 60 seconden om de lastige berichten te parkeren.

Jacob Molkenboer· Oprichter · A Brand New Company· 4 jun 2026· 9 min
Messing oproepbord met groen vlaggetje, papieren briefje, leren onderlegger en bel op ivoren bureau.

Het is 17:42 op een dinsdag in maart in Zwolle. Een RA-controller — noem haar M. — heeft achttien minuten voordat het SBR-loket bij KvK om 18:00 zijn deponeervenster sluit. Op haar scherm: 47 jaarrekening-vragen die de chat-agent het afgelopen uur heeft geflagd, elk getagd met een waarschijnlijke NV COS 4410 samenstellings-uitzondering. Ze werkt de queue af op 22 seconden per item, tekent elf jaarrekeningen, stuurt er drie terug naar de dossierhouder voor herclassificatie en parkeert de rest tot morgen. Om 17:59:40 gaat de laatste deponering door. Ze klapt de laptop dicht en gaat naar huis.

Voor dat ritme hebben we gebouwd. Hier is wat de agent doet, en wat het kostte om hem in een veertien jaar oude stack te hangen zonder iets te breken.

Het kantoor en de stack

Zevenentwintig mensen. Zo'n 1.400 mkb-klanten in de boeken — vooral retail, horeca, kleine bouw. Twee RA-controllers, vier AA-accountants, elf dossierhouders, de rest in salaris en BTW. Eén IT-coördinator die tegelijk office manager is. Geen DevOps. Geen data team.

De dossierkant draait op CaseWare Cloud, dat het kantoor in 2012 aanschafte en sindsdien op zeven verschillende manieren heeft aangepast. CaseWare bevat de werkdossiers, de proefbalans en de cliëntacceptatie. Vrijwel niets anders staat daar.

Het echte klant-dossier-archief — elke getekende jaarrekening, elk assurance-rapport, elke concept-deponeerset sinds 2009 — staat in een zelfgebouwde SQL Server 2017-instance op een Hyper-V host in de serverruimte. Het schema heeft 184 tabellen. Er is één dbo.Documents-tabel met 2,4M rijen. Het is geen schoonheid, maar het werkt, en de partner die het bouwde werkt nog steeds bij het kantoor. De chat-agent moet uit beide kunnen lezen.

Hoe de queue er echt uitziet

De chat leeft op het klantportaal van het kantoor. Klanten droppen de hele dag jaarrekening-vragen: "klopt deze afschrijvingstabel?", "waarom staat mijn DGA-lening nu in box 1?", "kunnen jullie de deponeerset vóór vrijdag inschieten?". We meten gemiddeld 1.520 berichten per week over het laatste volledige kwartaal. De piekweek zat op 2.180, in de aanloop naar de 31 mei-deponeerdeadline voor middelgrote bv's.

De meeste zijn routine. Een lookup in de proefbalans, een check op dossierstatus, een "wanneer is de RC-rekening getoetst"-vraag. Die beantwoordt de agent door CaseWare's REST API te bevragen voor het werkdossier en dat te joinen tegen het SQL Server-archief op KvK-nummer. Mediaan round trip: 1,8 seconden.

De interessante gevallen zijn de NV COS 4410-cases — de samenstellings-uitzonderingen. NV COS 4410 is de Nederlandse standaard voor samenstellingsopdrachten. Vermoedt de agent dat een klantvraag wijst op een discontinuïteit, een stelselwijziging of een materiële schattingswijziging die de dossierhouder in de conceptfase heeft gemist, dan mag hij niet antwoorden. Hij moet het bericht parkeren, een flag opgooien en het routeren naar een registeraccountant.

De 60-secondes-SLA

De afspraak met het kantoor: elk bericht met een waarschijnlijke 4410-uitzondering staat binnen 60 seconden in de queue van de RA-controller, met het relevante stuk uit het dossier eronder.

Zestig seconden is geen technische grens. Het is een gedragsgrens. De RA-controllers hebben op deponeerdagen een sprint tussen 17:00 en 18:00. Ververst de queue elk uur, dan missen ze dingen. Elke vijf minuten, en ze missen om 17:55 het moment waarop de SBR-adapter onder druk gaat haperen. Binnen zestig seconden, en ze vertrouwen 'm. Dat vertrouwen bepaalt of ze de queue überhaupt afwerken.

Zestig seconden halen voor een model-call met twee database-joins, een CaseWare API-hop en een redeneerstap is niet gratis. We moesten op drie dingen letten: de classifier, het lezen uit het archief, en wat te doen als het model "misschien" zegt.

Een 4410-uitzondering classificeren

We begonnen niet met een model. We begonnen met een checklist die de senior RA van het kantoor op de achterkant van een print van de standaard had geschreven. Zeventien regels. Sommige keyword-triviaal ("het woord 'discontinuïteit' in het bericht"). De meeste context-afhankelijk ("de omzet van de klant is YoY met meer dan 30% gedaald en de dossierhouder heeft de going-concern-toelichting de laatste 90 dagen niet bijgewerkt").

De agent draait de checklist eerst, als deterministische Python. Zo'n 38% van de berichten valt op zichzelf al door een van die regels heen. Die gaan rechtstreeks de controller-queue in, zonder model-call, binnen vier seconden. De classifier ziet ze nooit.

De resterende 62% gaat naar een Claude Sonnet-call met het bericht, de dossier-headers van de afgelopen zes maanden en de zeventien regels in de system prompt. De output is een forced JSON-object, getypeerd zodat de call site het kan valideren voor er een routing-beslissing valt:

from typing import Literal, Optional, TypedDict


class ClassifierOutput(TypedDict):
    is_4410_exception: bool
    rule_hit: Optional[str]                        # which of the 17, or None
    confidence: Literal["low", "medium", "high"]
    excerpt_to_show_ra: str                        # max 400 chars from the dossier
    fallback_reply_to_client: str                  # what the agent would have said

Bij een high confidence-hit wordt het bericht geparkeerd, krijgt de controller een notificatie en ziet de klant een one-liner: "We laten dit even nakijken door een RA-collega. Je krijgt vandaag nog antwoord."

Bij low of medium antwoordt de agent de klant alsnog, maar zet de controller-queue in cc met de fallback_reply_to_client voor review achteraf. Ongeveer 6% daarvan krijgt in de weekreview een "dit had geparkeerd moeten worden"-correctie, en de regel die had moeten vuren wordt aan de deterministische checklist toegevoegd. De checklist staat nu op 31 regels en groeit met ongeveer één per week.

Kerninzicht

De moat zit in de weekreview van het medium-confidence-pad. De classifier verbetert niet doordat het model slimmer wordt, maar doordat de deterministische ruleset alles absorbeert wat het model fout deed.

14 jaar dossier-archief uitlezen in 200ms

De dbo.Documents-tabel met 2,4M rijen was de tweede bottleneck. Het originele schema had een clustered index op InsertedAt en niets op KvK-nummer. Een lookup per klant kostte 1,6 seconden op een koude cache, wat de SLA opblies voordat het model überhaupt liep.

We hebben de tabel niet gemigreerd. Dan was de partner die hem bouwde vertrokken, en zijn goodwill is meer waard dan de seek time. We hebben een covering nonclustered index toegevoegd op (KvK_Nummer, DocumentType) INCLUDE (DocumentId, SignedAt, Title). Lookups gingen naar 18ms. De oorspronkelijke queries vanuit CaseWare's eigen integratie draaien nog ongewijzigd.

We hebben ook een kleine read-replica toegevoegd — feitelijk een tweede SQL Server 2017-instance op een tweede Hyper-V host met snapshot-replicatie elke 60 seconden. De agent leest van de replica. Loopt de replica meer dan 90 seconden achter, dan faalt de agent dicht en parkeert het bericht voor een controller met de notitie dat het archief stale is. In de vier maanden sinds go-live is dat tweemaal gebeurd. Beide keren door een Windows Update-reboot die we buiten kantooruren hadden moeten plannen.

SBR en het 17:55-probleem

De Standard Business Reporting-laag bij KvK heeft een eigenaardigheid die iedereen kent die ooit om 17:58 een jaarrekening heeft gedeponeerd: tussen ruwweg 17:50 en 18:00 geeft het deponeer-endpoint soms een 502 op de eerste POST en accepteert het op de retry. Het is niet gedocumenteerd. Het is gewoon zo.

De agent dient niet in. Dat doet de dossierhouder. Maar de agent krijgt tijdens deponeerweek twintig keer per dag de vraag: "is mijn jaarrekening al gedeponeerd?". Antwoordt de agent om 17:54 op basis van het SBR-poll-endpoint en is dat antwoord om 17:56 verouderd, dan denkt de klant dat hij ingediend is terwijl dat niet zo is, en spendeert de controller woensdagochtend aan het uitleggen van een boete aan een gepanikeerde DGA.

Dus stopt de agent op deponeerdagen om precies 17:45 met het beantwoorden van deponeerstatus-vragen. De klant ziet: "Tussen 17:45 en 18:15 controleren we deponeerstatussen handmatig. Geen zorgen — een collega bevestigt vóór 18:30 of je jaarrekening binnen is." Het is een feature flag, geen modelbeslissing. Het model mag dat niet overrulen. De system prompt weet niet eens dat de flag bestaat.

Wat het kantoor heeft uitgezet

Drie dingen die we bouwden en op verzoek van het kantoor weer uitzetten, alle drie terecht.

Het eerste was een auto-reply voor cliëntacceptatie-vragen. Het kantoor besloot, terecht, dat alles wat acceptatie raakt langs een partner moet en niet langs een chat. We lieten de classificatie staan (zodat partners een snellere queue krijgen) maar haalden de auto-reply eruit. De partner ziet maandagochtend nu een getriageerde queue van acceptatie-signalen in plaats van een stapel ongesorteerde mail.

Het tweede was een CaseWare write-pad. De agent zou dossier-velden direct in het werkdossier markeren als "controle gewenst". De compliance officer wees erop dat elke write naar een werkdossier een audit-trail-event is en dat de agent geen AA-nummer heeft. We hebben hem laten schrijven naar een aparte annotations-tabel die de dossierhouder als zijbalk in CaseWare leest. Zelfde eindstand, geen audit-probleem.

Het derde was een door Claude gestuurde SBR-adapter die de deponeer-XBRL on the fly zou genereren. Wij waren enthousiast. De RA-controllers niet. De XBRL moet byte-identiek zijn aan wat het kantoor tekent, en een model dat "bijna altijd" klopt is het verkeerde gereedschap voor een deponering waar de bestuurder wettelijk aansprakelijk voor is. We hebben de bestaande template-gedreven adapter laten staan.

De cijfers, vier maanden later

Berichten die de agent zelfstandig afhandelt zonder controller: 1.182 van de 1.520 per week, ongeveer 78%.

Berichten geparkeerd in de RA-queue: 264 per week, ongeveer 17%. De resterende 5% gaat naar de dossierhouder, niet de controller — meestal omdat de vraag administratief is en niet vaktechnisch.

Berichten waar het model ernaast zat en de weekreview het corrigeerde: 91 over vier maanden, gemiddeld vijf à zes per week en dalend naarmate de deterministische ruleset groeide.

Mediane tijd van "klant drukt op verzenden" tot "geparkeerd in controller-queue met dossierfragment eronder": 41 seconden. P95: 58 seconden. P99: 71 seconden, allemaal op koude replica's na de dagelijkse snapshot-rotatie. Binnen de SLA, met één bekende failure mode.

Uren die de twee RA-controllers per week terugkrijgen, door henzelf gemeten en niet door ons: ongeveer negen. Die uren gebruiken ze om meer samenstellingen te doen, niet om eerder weg te gaan. Dat is de keuze van het kantoor.

Wat geverifieerde agents hiermee te maken hebben

Twee items uit het nieuws van deze maand zijn een regel waard.

Anthropic kondigde op 19 juni aan dat een aantal Claude API-capabilities vanaf 8 juli organisatie-ID-verificatie vereist. Voor een kantoor dat een agent in een gereguleerde context draait — en "gereguleerd" is voor een accountantskantoor zacht uitgedrukt — is dat een feature, geen drempel. De compliance officer was vrijdag vrolijker dan donderdag.

Cloudflare gaat tijdelijke, scoped accounts voor AI-agents uitrollen. Dat past op iets wat wij nu nog matig oplossen: het uitgeven van een per-agent SQL-login op de read-replica met een handmatige rotatie van 24 uur. Het model van Cloudflare is schoner, en we stappen daar bij het volgende kantoor waarschijnlijk op over. Het patroon klopt: kortlevende credentials gescoped op één job.

Het kleinste dat je morgenochtend kunt doen

Run je een accountantskantoor — of een back-office met aan het eind van elke dag een venster van 60 minuten stress — doe dan deze audit voordat je tooling koopt. Log één week lang elk bericht dat je team beantwoordt, met de timestamp van binnenkomst en de timestamp van het antwoord. Sorteer de rijen. Kijk naar de berichten waarvan het antwoord in de laatste vijftien minuten van dat venster landde. Dat zijn de berichten die nooit zover hadden moeten komen. Bouw daar als eerste voor.

Toen we de agent voor het Zwolse kantoor bouwden, was de classifier niet het stuk dat het langst duurde. Het langst duurde het besef dat "onder de 60 seconden" en "correct of geparkeerd" dezelfde SLA zijn, en dat het verkeerd is om het model in een gereguleerde uitkomst te laten gokken. Wil je zien hoe dat in bedrading vertaalt, op onze pagina over chat agents staat het architectuurdiagram.

Kern

Voor gereguleerde triage zijn 'onder de 60 seconden' en 'correct of geparkeerd' dezelfde SLA — elk onzeker antwoord gaat naar een mens, nooit naar een gok.

FAQ

Waarom NV COS 4410-uitzonderingen parkeren in plaats van door de agent laten beantwoorden?

Omdat een samenstellings-uitzondering een vaktechnisch oordeel is, geen lookup. De agent heeft geen AA- of RA-nummer en de bestuurder van het kantoor is wettelijk aansprakelijk voor de deponering. Parkeren is de enige juiste zet.

Waarom niet het SQL Server 2017-archief migreren naar iets moderns?

Omdat de partner die het bouwde nog bij het kantoor werkt en het schema dragend is voor zeven CaseWare-customisaties. Een covering index en een snapshot-replica van 60 seconden brachten ons binnen de SLA zonder een werkend systeem aan te raken.

Wat gebeurt er als het model een 4410-uitzondering verkeerd inschat?

Medium- en low-confidence-antwoorden worden in cc gezet bij de controller-queue, met de fallback-reply erbij. De weekreview vangt misclassificaties op en de regel die had moeten vuren komt in de deterministische checklist, die nu op 31 regels staat.

Waarom stopt de agent om 17:45 met het beantwoorden van deponeerstatus-vragen?

Omdat het SBR-endpoint tussen 17:50 en 18:00 instabiel wordt en een verouderd 'ja'-antwoord de volgende ochtend een KvK-boete oplevert. Een feature flag, geen modelbeslissing, bevriest dat pad tijdens de deponeer-sprint.

chat agentsai agentscase studyintegrationsworkflowoperations

Iets bouwen?

Start een project