Chat agents
Intake-agent voor advocatenkantoor: beroepsgeheim eerst
Een Tilburgs kantoor van 27 mensen verwerkt 1.920 intake-vragen per week via Kleos en SharePoint. Dit is het playbook voor een agent die ze triëert zonder één bevoorrecht token aan te raken.

De intake-balie op maandag, 09:14
De senior-paralegal van het kantoor opent haar wachtrij om 09:14. Er liggen 312 intake-vragen te wachten uit het weekend, binnengekomen via het webformulier, het algemene emailadres en de transcripties van voicemails buiten kantoortijd. De meeste zijn routine. Elf noemen een naam die al opduikt in een lopende conflict-search. Drie beschrijven situaties die lezen als bevoorrechte mededelingen van iemand die nog geen cliënt is. Ze heeft ongeveer veertig minuten voor de eerste partner-stand-up.
Dat was de situatie die we aantroffen bij een Tilburgse praktijk met 27 mensen. Familierecht, arbeidsrecht en ondernemingsrecht onder één dak. Ongeveer 1.920 intake-vragen per week verdeeld over de drie desks. Een 13 jaar oud Kleos-dossiersysteem met cliënt- en zaakgegevens, en een SharePoint on-prem share met de historische correspondentie. De opdracht was direct: halveer de tijd voor intake-triage, zonder dat ook maar één bevoorrecht token op een pad komt dat kan schrijven naar het cliënt-portaal.
Dit is het playbook dat we hebben opgeleverd. Het is opinionated, het is klein, en de randvoorwaarden hebben het meeste ontwerpwerk voor ons gedaan.
Vier randvoorwaarden die alles bepaalden
Voor de eerste regel code schreven we vier randvoorwaarden op een whiteboard. De partners stonden niet toe dat we er ook maar één van inruilden.
- Beroepsgeheim is absoluut. Artikel 11a Advocatenwet behandelt bevoorrechte informatie als iets wat de advocaat niet mag delen, punt. De eigen richtlijnen van de orde over cloud en AI herhalen die regel en scherpen 'm aan voor gehoste diensten. De NOvA-pagina's over innovatie en ICT zijn de actuele referentie.
- Geen autonome writes. Niets wat de agent beslist bereikt een echt dossier, een echte cliënt of het portaal zonder dat een partner op goedkeuren klikt.
- Kleos blijft onaangeraakt. Geen schema-migratie, geen plugin, geen upgrade-window. De 13 jaar oude installatie is load-bearing en niemand wil degene zijn die haar sloopte in de week voor de vakantie.
- Het model ziet nooit een volledig dossier. Alleen het minimale stukje dat nodig is voor de triage-beslissing die voorligt. Geen PDF-inhoud, geen email-threads, geen scan-van-paspoort.
Die vier regels bepaalden uiteindelijk de deployment-target, de prompt-scaffolding, het queue-ontwerp en het audit-trail. We lazen ze opnieuw elke keer dat er later een verleidelijke shortcut langskwam.
Kleos en SharePoint ontsluiten zonder de schema's aan te raken
Kleos biedt een read-only ODBC-kanaal waarvan veel kantoren niet weten dat het bestaat. SharePoint on-prem 2019 heeft een prima REST API, zodra je stopt met ertegen te vechten. We bouwden een dunne read-only adapter voor elk van de twee, achter één intern endpoint dat de agent kon aanroepen. De agent ziet de connection strings nooit.
@router.get("/intake/context")
def intake_context(query: str, requester_email: str):
# 1. Conflict check against Kleos relations.
hits = kleos_ro.search_relations(query, limit=5)
# 2. Pull only matter metadata, never the body.
matters = [kleos_ro.matter_card(h.matter_id) for h in hits]
# 3. SharePoint: titles and last-modified only, no bytes.
docs = sp_ro.search_titles(query, top=10)
return {
"conflict_hits": hits,
"matter_cards": matters,
"doc_titles": docs,
"requester_in_kleos": kleos_ro.is_known(requester_email),
}
De agent krijgt nooit de inhoud van een dossier. Hij krijgt matter cards (naam, status, lead-partner, geopend-op) en documenttitels. Daarmee dek je ongeveer 80% van de triage-beslissingen: welke desk, welke partner, is dit een conflict, is de afzender al cliënt. De 20% die documentinhoud nodig heeft, gaat direct naar een mens; de taak van de agent is dat herkennen en stoppen.
De triage-stap
Elke binnenkomende intake-vraag loopt door een classifier in drie stappen voordat een mens 'm ziet. De classifier zelf is een klein instruction-tuned model dat draait op de eigen hardware van het kantoor, in een serverruimte twee deuren verderop van de partners. We hebben bewust geen bevoorrechte content naar een gehost endpoint gestuurd. Voor een Nederlands advocatenkantoor is de afweging scherper dan voor een gemiddeld bedrijf. Het is geen voorkeur, het is het verschil tussen een verdedigbaar beleid en een tuchtklacht.
De drie stappen:
- Classificeer de desk. Familie, arbeid, ondernemingsrecht, of "vraagt om een mens." Het model krijgt de boodschap plus de status van de afzender (bekende cliënt, oud-cliënt, onbekend) en geeft één label terug plus een confidence-score.
- Draai de conflict-probe. De agent haalt namen, KvK-nummers en adressen eruit, en roept dan het read-only Kleos-endpoint aan. Elke hit boven een drempelwaarde parkeert de vraag in een "conflict review"-baan en stopt verdere routering.
- Markeer de beroepsgeheim-gevallen. Als de boodschap leest als een bevoorrechte mededeling van iemand die nog geen cliënt is (dat gebeurt vaker dan mensen denken op intake-formulieren), krijgt 'ie een harde vlag en een routing naar alleen partners.
De output is een gestructureerd object dat de wachtrij begrijpt. Geen vrije tekst, geen concept-antwoord, geen "dit zou ik terugzeggen."
{
"intake_id": "iv-2026-06-14-0231",
"desk": "employment",
"desk_confidence": 0.93,
"conflict_hits": [],
"beroepsgeheim_flag": true,
"requester_status": "unknown",
"suggested_partner": "MdV",
"rationale": "Sender describes an ongoing internal investigation at a named employer; no prior matter on file."
}
Het rationale-veld is het enige stuk gegenereerde tekst in de hele pipeline. De partners gebruiken het zoals ze de samenvatting van een junior associate zouden gebruiken, en ze overrulen het zonder aarzeling. Elke override wordt gelogd.
De beroepsgeheim-poort
Dit was het onderdeel dat de partners samen met ons in één ruimte wilden ontwerpen. De regel waar we op uitkwamen is de simpelste die houdt: elk record met beroepsgeheim_flag: true mag het on-prem netwerk niet verlaten, mag in geen enkele digest-mail samengevat worden, en mag niet getoond worden aan iemand anders dan een benoemde partner of de aangewezen paralegal op die desk.
Technisch betekende dat drie dingen:
- Een aparte database-tabel voor gevlagde records, op een apart volume, met row-level access control gekoppeld aan AD-groepen.
- Een redactie-stap op elk downstream surface (dashboards, search, zelfs error logs), zodat een gevlagd record letterlijk niet kan renderen buiten zijn toegestane doelgroep.
- Een dagelijkse reconciliatie-job die elk systeem loopt waar de agent aan raakt, en controleert dat geen enkele gevlagde ID is gelekt naar een onbevoegde tabel of log.
Als gevlagde records dezelfde opslag delen met normale records en je vertrouwt op filtering in de applicatielaag, dan lekt de eerste developer die een snelle admin-query schrijft ze. Fysieke scheiding is goedkoper dan de tuchtklacht.
De goedkeuringswachtrij voor partners
Elke triage-beslissing landt in een wachtrij, niet in een mailbox. De wachtrij is het enige surface waar een mens ooit interacteert met de output van de agent, en het is ook de enige plek waar iets goedgekeurd kan worden voor een downstream actie.
De interface heeft vier kolommen, en een record kan alleen van links naar rechts bewegen.
- Inbox. Verse triage-resultaten, gesorteerd op desk en confidence. Alles onder 0,75 confidence toont de onderbouwing standaard uitgeklapt.
- Conflict review. Alles wat de conflict-probe heeft gevlagd. Een partner moet 'm clearen voordat 'ie verder kan.
- Privileged. De beroepsgeheim-wachtrij. Alleen benoemde partners kunnen deze records openen, en het audit-trail legt elke open vast.
- Goedgekeurd voor cliënt-portaal. De uitgang. Records hier komen in aanmerking om een write naar het cliënt-portaal te triggeren: dossier aanmaken, intake-email, agendaplek.
Er is geen auto-approve shortcut voor records met hoge confidence. De taak van de agent eindigt bij "voorgestelde actie plus onderbouwing"; daar begint de taak van een mens. De partners vonden dit fijn omdat het paste bij hoe ze al junior associates trainen, en het gaf ze een verdedigbaar antwoord op de toezichtsvraag "wie heeft dit besloten."
Het schrijfpad blijft mensenwerk
Het cliënt-portaal zit achter één write-endpoint. De agent heeft er geen credentials voor. De wachtrij wel, maar pas nadat een partner op goedkeuren heeft geklikt. Elke write draagt de queue-record-ID mee, de handtekening van de goedkeurende partner en een timestamp, en verschijnt in Kleos als een normale opened-by-user actie, zodat het audit-trail eruitziet als elke andere actie in het kantoor.
def open_matter(approved_record):
assert approved_record.approved_by_partner is not None
assert (approved_record.beroepsgeheim_flag is False
or approved_record.approved_by_partner in PRIVILEGED_PARTNERS)
return kleos_write.create_matter(
client_email=approved_record.requester_email,
desk=approved_record.desk,
opened_by=approved_record.approved_by_partner,
source="intake-agent-v1",
notes=approved_record.partner_notes,
)
De agent roept deze functie nooit aan. De wachtrij doet dat, nadat de twee asserts slagen. We hebben besproken om de agent dit voor routine-zaken te laten doen, en de partners hebben dat idee binnen dertig seconden afgewezen. Het juiste antwoord was het antwoord waar zij zonder ons al op uitgekomen waren.
Hoe zes weken eruit zagen
Tegen het einde van week zes hadden de cijfers zich gezet in een vast patroon. De triage-tijd van het paralegal-team daalde van ongeveer 47 minuten per 100 vragen naar 19. De desk-routing-nauwkeurigheid van de agent bleef hangen op 94%, gemeten tegen partner-overrides. De conflict-probe ving in de eerste maand twee near-misses op die een menselijke lezer plausibel had kunnen missen (beide betroffen voormalige wederpartijen die onder andere bedrijfsnamen opereerden). Geen enkele record overschreed de beroepsgeheim-grens, geverifieerd door de dagelijkse reconciliatie-job en een kleine externe audit in week vier.
Twee dingen verrasten ons, en beide waren saai en nuttig. Eén: partners keurden dingen sneller goed dan we hadden verwacht, omdat het rationale-veld betekende dat ze een beslissing aan het reviewen waren in plaats van er een vanaf nul maken. Twee: de agent werd in de loop van de tijd beter zonder hertrainen, omdat partner-overrides werden gelogd en wekelijks als few-shot voorbeelden in de prompt werden teruggevoerd. Geen fine-tune, alleen betere in-context priors.
De reconciliatie-job verdiende zijn geld in week drie. Een developer (een van de onze, gênant genoeg) had een debug-logregel toegevoegd die het volledige triage-object inclusief het vlag-veld naar een roterend bestand schreef buiten het bevoorrechte volume. De job ving het de volgende ochtend op, opende een ticket, en de regel was voor de lunch weg. Dat is het soort vangst dat je van een saaie cron wilt, niet van een auditor.
De audit van vijf minuten die je morgen kunt doen
Als jouw operatie ook maar enigszins op deze vorm lijkt, is het kleinste dat je deze week kunt doen je eigen schrijfpaden in kaart brengen. Pak een notitieblok. Schrijf elk systeem op waar een agent (of welke automatisering dan ook, inclusief die ene Zapier waarvan je was vergeten dat 'ie bestaat) iets zou kunnen aanmaken, bewerken of versturen dat een cliënt te zien krijgt. Schrijf naast elk systeem de naam van die ene mens die op goedkeuren moet klikken voordat die schrijf-actie plaatsvindt. Als een vakje leeg is, daar begin je.
Toen we de intake-agent voor dit Tilburgse kantoor bouwden, was het zwaarste onderdeel niet het model of de Kleos-adapter. Het was consensus krijgen over de vier kolommen van de wachtrij, en daar kwamen we alleen door de eerste week mee te zitten bij echte intake-reviews in plaats van code te schrijven. Wil je dezelfde vorm voor een intake-flow binnen je eigen kantoor, dan is dat het type werk dat wij doen op het gebied van AI-agents.
Kern
Als je agent alleen metadata nodig heeft om te beslissen, geef hem alleen metadata. Dossier-inhoud en beroepsgeheim zijn een aparte, veel zwaardere toestemming.
FAQ
Kan de agent iets naar een cliënt sturen zonder dat er een mens tussen zit?
Nee. De agent produceert alleen een gestructureerd triage-object plus een onderbouwing. Elke schrijf-actie naar het cliënt-portaal, het dossiersysteem of email gaat via een benoemde partner die in de wachtrij op goedkeuren klikt.
Waarom een lokaal model in plaats van een gehost model?
Beroepsgeheim onder artikel 11a Advocatenwet behandelt bevoorrechte informatie als iets wat een advocaat niet mag delen. Intake-content naar een gehost endpoint sturen creëert een verdedigingsprobleem dat on-prem inference voorkomt.
Moest je Kleos upgraden of aanpassen?
Nee. We lezen via het bestaande read-only ODBC-kanaal en schrijven nooit terug via de agent. Alle writes gaan via het normale Kleos-schrijfpad van het kantoor, ondertekend door de goedkeurende partner.
Hoe wordt de beroepsgeheim-vlag eigenlijk bepaald?
De classifier zoekt naar disclosure-taal van niet-cliënten, gevoelige derde-partij-vermeldingen en een kleine set expliciete triggers die met de partners is afgestemd. Iets twijfelachtigs wordt standaard gevlagd, niet ongevlagd.
Wat voorkomt dat de agent een verkeerde routering hallucineert?
De agent stelt nooit een reply op en opent geen dossier. Hij stelt alleen een desk en een partner voor, met een confidence-score en een onderbouwing. Bij lage confidence wordt de onderbouwing automatisch uitgeklapt, zodat de partner de redenering ziet voor goedkeuring.