Hoe je autonome AI-agenten een open vraagbereik geeft over bedrijfsdata, zonder de controle over rechten, herkomst, kosten en risico op te geven — en hoe je dat zo bouwt dat het blijft werken wanneer de modellen erachter onherkenbaar veel capabeler zijn geworden.
Video 3 van de reeks · 2:41 — wat dit document uitwerkt, in beeld: hoe één vraag door de AI-poort reist, met bij elke stap dezelfde controle.
Dit is de technische uitwerking: hoe je AI-agenten een open vraagbereik geeft over je bedrijfsdata zonder de controle over rechten, herkomst, kosten en risico op te geven. Het is geschreven met een gereguleerde organisatie voor ogen — meerdere entiteiten, een auditor, een toezichthouder.
Blijf je hier? Dan hoef je niets van dit document vooraf te weten. De managementsamenvatting hieronder geeft de vier stellingen; daarna wordt elke laag apart uitgewerkt.
Organisaties willen AI-agenten die vragen over hun eigen data beantwoorden. De gangbare implementaties kiezen tussen twee kwaden: ofwel beperk je wat gevraagd mag worden (een vaste catalogus tools of rapporten — veilig maar dom), ofwel geef je het model vrije toegang (schema plus SQL-generatie — slim maar onbestuurbaar). Deze architectuur weigert die keuze.
De kern is een gateway: één doorgang tussen redeneerders en data, waar rechten, tenant-afbakening, volume, herkomst en kosten worden afgedwongen — niet door instructies aan het model, maar door code die draait ongeacht wat het model probeert. Daarboven staat een semantische laag die vastlegt welke entiteiten, velden, relaties en gecertificeerde metrieken bestaan, elk met een gevoeligheidsklasse. De agent stelt binnen die laag vrij zijn eigen bevragingen samen — ook vragen die niemand vooraf bedacht heeft — terwijl hij nooit een SQL-string aanraakt en zijn eigen afbakening niet kan uitbreiden.
De meeste mislukte AI-datatoegangprojecten mislukken niet in de bouw maar in de probleemstelling. "Bouw een chatbot op onze data" is een opdracht die het antwoord al verkeerd stuurt.
Hoe geef je een niet-deterministische redeneerder een open vraagbereik over data die meervoudig bestuurd is — per entiteit, per rol, per gevoeligheidsklasse, per rechtsgebied — zonder dat elke nieuwe vraag opnieuw een veiligheidsvraag wordt?
De laatste bijzin is de hele opgave. In een systeem met vaste rapporten is elk rapport één keer beoordeeld en daarna veilig. In een systeem met een open vraagbereik bestaat "de vraag" nog niet op het moment dat je hem moet goedkeuren. Je kan dus niet vragen beoordelen; je moet toegang beoordelen. Alles in deze architectuur volgt uit die verschuiving.
Je kan de vragen niet opsommen — de nuttige zijn per definitie de niet-voorziene. Je kan de data wél opsommen, en wie er wat van mag zien. Bevries daarom het bestuurbare en laat het onbestuurbare vrij.
Het model dat je vandaag kiest is over achttien maanden achterhaald, mogelijk van een andere leverancier, mogelijk lokaal draaiend om soevereiniteitsredenen. Alles wat governance is, moet daarbuiten staan — anders herbouw je het bij elke wissel.
Een traag antwoord is hinderlijk. Een overtuigend fout antwoord op een schadereserve, een marge of een blootstelling stuurt een verkeerde beslissing en wordt pas veel later ontdekt. Elk compromis valt daarom uit in het voordeel van controleerbaarheid.
In een gereguleerde omgeving is "waarom zei het systeem dit?" geen debugvraag maar een toezichtvraag, met termijnen en bewaarplichten. Bewijsvoering hoort in de architectuur, niet in de logging-backlog.
Dit is de analytische ruggengraat van het document. Elke controle in elk AI-systeem valt in één van drie klassen, en die klasse voorspelt hoe de controle zich gedraagt als het model beter wordt.
Wat: instructies in de systeemprompt. "Toon nooit gegevens van andere klanten." "Verzin geen cijfers." "Vraag om bevestiging vóór je iets wijzigt."
Waarom het faalt als grens: de werking hangt af van de bereidheid en het begrip van het model. Ze is niet af te dwingen, niet te bewijzen en niet uitputtend te testen — de ruimte van formuleringen die haar omzeilen is oneindig. Erger: een capabeler model vindt méér paden, niet minder, en tekst uit de data zelf (een klantnaam, een e-mailtekst, een schadedossier) kan met dezelfde autoriteit spreken als jouw instructie.
Legitiem gebruik: kwaliteit, toon, formaat, voorkeursvolgorde. Nooit: vertrouwelijkheid, afbakening, autorisatie, onomkeerbare handelingen.
Wat: beperken wat überhaupt geprobeerd kán worden. Een vaste catalogus van tien tools. Vooraf geschreven rapporten. Geen SQL-toegang.
Waarom het onvoldoende is: het werkt — maar het plafond ligt bij de verbeeldingskracht van de ontwerper op de dag dat hij de catalogus schreef. Naarmate modellen capabeler worden, wordt de restrictie de bindende beperking in plaats van het model. Je betaalt voor een redeneerder en gebruikt hem als menukaart.
Legitiem gebruik: kosten, prestaties, blast radius van handelingen. Ongeschikt als: primaire veiligheidsgrens, omdat elke uitbreiding opnieuw een veiligheidsbeoordeling vraagt.
Wat: controle die buiten het model draait en niet afhangt van zijn medewerking. Policy-evaluatie per veld. Afbakening die in de query geïnjecteerd wordt. Toelatingscontrole op volume. Read-only databaserollen. Verplichte herkomstvastlegging.
Waarom het standhoudt: de effectiviteit is onafhankelijk van wie of wat de aanvraag doet. Een kluisdeur vraagt niet hoe slim de persoon ervoor is. Dezelfde controle werkt identiek voor een zwak model, een superieur model, een gecompromitteerde integratie of een medewerker met gestolen inloggegevens — en dat is precies de eigenschap die je in een bedrijfsomgeving nodig hebt.
Kosten: ontwerpwerk vooraf. Je moet je datamodel semantisch beschrijven en classificeren vóórdat je AI erop loslaat. Dat is de investering die dit document verdedigt.
Drie gevestigde principes vormen de lakmoesproef voor elke toegangsarchitectuur. Dit ontwerp verhoudt zich er als volgt toe — inclusief de plek waar het bewust van de zuivere leer afwijkt.
Elke bevraging wordt op het moment zelf volledig geverifieerd: identiteit uit de sessie, policy per veld, afbakening opnieuw geïnjecteerd. De gateway is het policy enforcement point, de bestuurslaag het policy decision point. Verder dan klassiek Zero Trust: ook de redeneerder zelf is onvertrouwd — het ontwerp neemt aan dat het model gemanipuleerd kan zijn (injectie via data), vandaar geen tekstpad naar de opslag en afbakening buiten zijn bereik. "Intentie is geen toegangsprimitief" is never trust, always verify, toegepast op bedoelingen.
Het niet-vervalsbare zit erin: de afbakeningscontext bereikt de uitvoering buiten elk schema om, zodat de agent niet eens kán uitdrukken wat hem niet gegeven is; elke agent krijgt alleen het toolsubset van zijn rol; delegatie met vervaldatum is een klassieke capability-grant. Rondgereikte ondertekende tokens ontbreken bewust: binnen één servergrens met één reference monitor voegen ze niets toe. Zodra er servicegrenzen komen (de federatieve uitvoering, §3.3), materialiseren beslissingen wél als kortlevende ondertekende query-capabilities — zelfde model, gedistribueerde vorm.
Zuiver PoLP per operatie×veld is bij open bevraging het duizenden-beslissingen-probleem — en onbeheerbare rechtenlijsten verzanden in verouderde grants: privilege sprawl schendt least privilege harder dan een grovere maar onderhouden structuur. Hier ontstaat de minimale bevoegdheid per aanvraag als doorsnede: rol×klasse ∩ subjectreikwijdte ∩ resource-verfijning ∩ verplichtingen (maskering, alleen-geaggregeerd, geen export) ∩ doelbinding ∩ toolsubset ∩ aflopende delegaties. Het minimale-pad-gedrag (eerst namen, dan één nummer) is dynamisch least privilege — minimalisatie per vraag, wat statische rechten per definitie niet kunnen.
Rollen encoderen in dit ontwerp geen intenties maar functienoodzaak (need-to-know); ze zijn een administratieve compressie van grants. De handhaving verwijst nergens naar bedoelingen.
De vraag "werkt dit nog over drie jaar, als AI bovenmenselijk is geworden?" is beantwoordbaar, en het antwoord is niet "we hopen het".
Definitie. Een controle is capaciteitsonafhankelijk wanneer haar effectiviteit niet afhangt van het vermogen van de entiteit die ze beheerst.
Toegangscontrole op een database is capaciteitsonafhankelijk: ze kent geen verschil tussen een junior analist en een superintelligentie, ze kent alleen legitimatie. Een instructie in een prompt is dat niet: haar werking is volledig een functie van hoe het model haar interpreteert.
Een architectuur houdt stand bij stijgende modelcapaciteit als, en alleen als, groeiende capaciteit de waarde verhoogt zonder de veiligheid te verlagen. Dat vraagt twee dingen tegelijk:
Een beter model stelt betere vragen, kiest slimmere aggregaties, herkent scherper welke domeinkennis het nodig heeft en trekt betere conclusies uit weinig data. Al die winst valt binnen de vraagzijde — precies wat deze architectuur vrijlaat. Meer capaciteit betekent hier meteen meer waarde, zonder één regel code.
Policy-evaluatie, afbakeningsinjectie en toelatingscontrole draaien identiek, ongeacht wie vraagt. Ze worden niet zwakker doordat de aanvrager slimmer is. Meer capaciteit betekent hier géén extra risico — en dat is de enige reden waarom je een sterker model gerust kan inschakelen.
Een praktische investeringsgids die uit hetzelfde denken volgt. Als je vandaag budget verdeelt over een AI-programma, is dit de verdeling die over drie jaar nog verdedigbaar is:
| Depreciëert snel — houd dun en vervangbaar | Appreciëert — hier hoort de investering |
|---|---|
| Promptteksten en few-shot-voorbeelden | Ontologie en semantische laag — de vastgelegde betekenis van je entiteiten, velden en relaties |
| Modelkeuze, fine-tunes, leverancierspecifieke koppelingen | Gegevensclassificatie — wat is gevoelig, waarom, en onder welk regime |
| Toolimplementaties die om de eigenaardigheden van één model heen gebouwd zijn | Policy als data — wie mag wat, uitgedrukt zodat het evalueerbaar en testbaar is |
| Orkestratieframeworks van dit jaar | Gecertificeerde metriekdefinities — de ene, gezaghebbende berekening van marge, blootstelling, schaderatio |
| Retrieval-afstemming rond een specifiek embeddingmodel | Kennislaag en precedentenverzameling — hoe deze organisatie beslist, vastgelegd (§2.2) |
| Interface-details van de chatlaag | Bewijs- en evaluatieverzameling — traces, gouden vragen, regressiedekking |
Uitspraken die altijd gelden, ongeacht domein, model of implementatie. Wanneer een keuze in de bouw met een principe botst, is de keuze fout — niet het principe.
De scheiding die het systeem onderhoudbaar houdt. Elke laag heeft een eigen wijzigingsritme, een eigen eigenaar en een eigen kwaliteitsregime — en dat is geen esthetiek maar de reden dat een modelwissel de governance niet raakt.
Data zegt wat er gebeurd is. Kennis zegt wat het betekent. Een redeneerder die de eerste heeft en de tweede mist, produceert cijfers die kloppen en antwoorden die niet deugen.
| Tier | Inhoud | Laadmoment | Waarom deze laag bestaat |
|---|---|---|---|
| 0 · Register | Alle domeinen met trefwoorden, routes en een verwijzing naar hun kerndocument | Altijd, in elke aanroep (gecached) | De redeneerder weet wat er bestaat zonder iets ervan te kennen. Een paar duizend tokens vervangen honderdduizenden. |
| 1 · Kern | Doel van het domein, invarianten, veldbetekenis, statusverlopen, verboden | Voor de één tot drie gekozen domeinen | Voorkomt de meest voorkomende fout: correcte SQL op een verkeerd begrepen veld. Dit is waar "welke status telt als openstaand" thuishoort. |
| 2 · Regels | Bedrijfsregels, processtappen, randgevallen, uitzonderingen | Op aanvraag, per sectie | Onbegrensd in omvang zonder de contextkosten van elke vraag te verhogen. De redeneerder haalt op wat de vraag vereist. |
| 3 · Precedent | Uitgewerkte gevallen, eerdere beslissingen met motivering, interpretaties van toezichthouders, architectuurbesluiten | Op aanvraag, wanneer de vraag om oordeel vraagt | Institutioneel geheugen. Het verschil tussen een antwoord dat in het algemeen juist is en een antwoord dat consistent is met hoe deze organisatie beslist. |
Alle vier de tiers worden opgehaald via de gateway, niet via een bestandslezing naast de deur. Drie redenen, en de derde is de belangrijkste: kennisdocumenten kunnen zelf gevoelige informatie bevatten — een tier-3-precedent beschrijft een concreet dossier; toegang tot een domeinkerndocument verraadt dat het domein bestaat; en de vraag welke kennis geraadpleegd werd, is onderdeel van de verantwoording van het antwoord. Kennisophaling is dus rechtengecontroleerd en gelogd, net als elke andere aanvraag.
De bestuurslaag is het declaratieve geheugen van wat mag: alles wat hier staat is data — versiebeheerd, evalueerbaar, testbaar en te simuleren vóór inwerkingtreding. Ze wijzigt op het ritme van de organisatie (een nieuwe rol, een strengere regel, een tijdelijke delegatie), nooit op het ritme van de code. En ze doet zelf niets: de gateway (laag 3) dwingt af wat hier gedeclareerd is.
De vier blokken hierboven worden in deze volgorde uitgewerkt: het semantisch register (§2.3.A), de policy (§2.3.B), het handelingsregister (§2.3.C) en de routering (§2.3.D).
De samenhang in één zin: het register beschrijft, de policy verleent, het handelingsregister begrenst het doen, en de routering begrenst de denker. Wie iets aan het gedrag van het systeem wil veranderen, verandert hier data — en kan in de bewijslaag nalezen wat die verandering deed.
Het register is de afgesproken werkelijkheid: wat er bestaat voor de AI. Nadrukkelijk niet het fysieke schema, maar een bewuste, geclassificeerde doorsnede daarvan met betekenis eraan vast.
// Eén resource, declaratief. Domeinneutraal patroon;
// hier ingevuld voor een commerciële opportuniteit.
defineResource({
naam: "Opportuniteit", opslag: "leads", domein: "commercieel",
omschrijving: "Verkoopkans vóór promotie naar uitvoeringsproject.",
// VERPLICHT — geen resource zonder afbakeningspad. Lint faalt.
afbakening: { soort: "TENANT", pad: "tenants.some.tenantId" },
velden: {
id: { type: "id", klasse: "INTERN" },
naam: { type: "tekst", klasse: "INTERN", filterbaar: true },
status: { type: "enum", klasse: "INTERN", domeinwaarden: "LeadStatus" },
ontvangenOp: { type: "datum", klasse: "INTERN", filterbaar: true },
waarde: { type: "geld", klasse: "COMMERCIEEL", aggregeerbaar: true },
contactTel: { type: "tekst", klasse: "PERSOONSGEGEVEN",
maskering: "laatste4", grondslag: "gerechtvaardigd belang — contactopname" },
// Sleutels, tokens, ruwe documenten: staan hier NIET → bestaan niet voor de AI.
},
relaties: {
interacties: { naar: "Interactie", soort: "veel", telbaar: true },
conversaties: { naar: "Conversatie", soort: "veel", telbaar: true },
klant: { naar: "Organisatie", soort: "een" },
},
// Gezaghebbende berekeningen. De redeneerder mag ze gebruiken, niet herleiden.
metrieken: {
winratio: { klasse: "COMMERCIEEL", impl: canon.winratio,
definitie: "gewonnen / (gewonnen + verloren), excl. ingetrokken",
eigenaar: "Commercieel directeur", herzienOp: "2026-06-01" },
},
kwaliteit: { notitie: "Data vóór 2024 is gemigreerd; statussen zijn benaderd." },
limieten: { standaard: 50, max: 500 },
indexen: ["tenants.tenantId", "status", "ontvangenOp"],
})
Vijf tot zeven klassen volstaan voor vrijwel elke organisatie. Meer klassen geven schijnprecisie en onbeheersbare matrices; minder dwingt alles naar het strengste regime.
| Klasse | Aard | Standaardregime |
|---|---|---|
| Intern | Namen, referenties, statussen, datums | Alle geauthenticeerde interne rollen |
| Operationeel | Uitvoering, planning, voortgang, capaciteit | Rollen met uitvoerende verantwoordelijkheid |
| Commercieel | Prijzen, offertes, kansen, klantwaarde | Commerciële en leidinggevende rollen |
| Financieel | Bedragen, marges, kosten, blootstelling, reserves | Financiële rollen; afgebakend per juridische entiteit |
| Persoonsgegeven | Identificeerbare gegevens van natuurlijke personen | Beperkt, met maskering en doelbinding; grondslag vastgelegd per veld |
| Bijzonder | Gezondheid, biometrie, strafrechtelijk — AVG art. 9/10 | Alleen expliciete grondslag; vaak volledig uitgesloten voor AI-verwerking |
| Geheim | Sleutels, tokens, inloggegevens, ruwe documenten | Niemand. Staat niet in het register — bestaat niet |
genegeerd. Eén bewuste beslissing per migratie op een blootgestelde tabel; de rest van het schema blijft buiten schot. Whitelist = veiligheid, gratis en schemabreed; CI-check = volledigheid, gericht en goedkoop.De voor de hand liggende tegenwerping: een serieus datamodel telt duizenden kolommen — de reference implementation telt er ruim drieduizend over 174 tabellen — en die stuk voor stuk classificeren is onbegonnen werk. Terecht. Daarom werkt de classificatie met vier mechanismen die de last terugbrengen van duizenden regels naar tientallen beslissingen:
De veiligheid zit in de whitelist: niet-geregistreerd = onbereikbaar, schemabreed en gratis. De bouwstraatcontrole is enkel het drift-alarm daarbovenop en geldt uitsluitend voor kolommen van al blootgestelde tabellen (zie het kader in §2.3.A hierboven). Een eerste fase met vijf resources vraagt dus vijf besluiten, niet drieduizend.
Elke resource draagt één standaardklasse; alleen afwijkende velden krijgen een eigen regel. Een factuurtabel is standaard financieel, met het nummer als interne uitzondering en het ruwe documentveld als geheime. In de praktijk: één beslissing per tabel plus een handvol uitzonderingen — voor de reference implementation circa zestig tabelbesluiten in plaats van 3.500 veldregels.
De eerste vulling wordt gegenereerd — uit naamconventies, typen en de bestaande kennisdocumenten — en door een mens beoordeeld. Dit is ook hoe de industrie het doet: classificatietooling stelt automatisch voor, mensen bevestigen de twijfelgevallen. Een middag review in plaats van weken invoerwerk.
Organisaties met per-veld-documentatie — datadictionaries, AI-bewerkbaarheidstabellen, gegevenscatalogi — voegen één attribuut toe aan een bestaand ritueel, geen nieuw proces. De reference implementation onderhoudt zulke veldtabellen al voor zestig modules; de klasse is er één kolom bij.
Het register zegt wat er is. De policy zegt wie er wat mee mag. Bewust gescheiden: het register verandert met het datamodel, de policy met de organisatie — en ze hebben verschillende eigenaars en verschillende goedkeuringswegen.
Policy is data, geen code: evalueerbaar, testbaar, diffbaar, en te simuleren vóór inwerkingtreding. Standaard is weigeren. Beslissingen zijn niet binair maar drieledig.
rol COMMERCIEEL → lees:PERSOONSGEGEVEN → TOESTAAN, met doelbinding. Vanaf dat moment geldt dat voor élk veld van die klasse.
klasse + resource): nog steeds een handvol regels, geen veldwerk. Hetzelfde principe als beveiligingsclearances: wie SECRET mag lezen, mag alle SECRET-documenten lezen — niemand zet de clearance op elk document opnieuw.// Eén policyregel — de volledige vorm. Rechten worden verleend per (rol, actie,
// klasse), optioneel verfijnd per resource en per subjectbereik.
type PolicyRegel = {
rol: Rol // subject
actie: "lees" | "handel"
klasse: Gevoeligheidsklasse
resource?: ResourceNaam // verfijning: klasse+resource (leads wél, werknemers niet)
reikwijdte?: "eigen" | "team" | "organisatie" // subjectbereik binnen de geïnjecteerde afbakening;
// default "organisatie" — zet "eigen"/"team" waar
// portefeuilles persoonsgebonden zijn (§"Intentie")
effect: "TOESTAAN" | "WEIGEREN"
verplichtingen?: Verplichting[]
geldigTot?: Datum // delegatie/mandaat: aflopende verlening bij vervanging
verleendDoor?: GebruikerId // wie delegeerde — audit-spoor
}
type Beslissing = // uitkomst van policy-evaluatie per element
| { effect: "TOESTAAN" }
| { effect: "WEIGEREN"; reden: string; ontbrekendRecht: string }
| { effect: "TOESTAAN"; verplichtingen: Verplichting[] }
type Verplichting =
| { soort: "MASKEER"; patroon: "laatste4"|"domein"|"volledig" }
| { soort: "ALLEEN_GEAGGREGEERD"; minGroepsgrootte: number } // k-anonimiteit
| { soort: "MAX_RIJEN"; n: number }
| { soort: "GEEN_EXPORT" } // tonen mag, meenemen niet
| { soort: "MODEL_BEPERKING"; eisen: ModelEis } // zie hieronder
| { soort: "DOELBINDING"; toegestaneDoelen: string[]
defaultDoel?: string } // afgeleid/expliciet → trace (§"Doelbinding")
| { soort: "VIER_OGEN"; goedkeurderRol: string } // bij handelingen
Zonder verplichtingen wordt elk gevoelig veld een dichte deur en verschraalt het systeem tot triviale vragen. Met verplichtingen wordt het genuanceerd: een commerciële rol ziet bedragen geaggregeerd met een minimale groepsgrootte van vijf — zodat een groep van één de maskering niet omzeilt; een uitvoerende rol ziet contactgegevens gemaskeerd; een medewerker die een financiële vraag stelt krijgt geen leeg scherm maar de mededeling welk recht ontbreekt en bij wie het te halen is.
MODEL_BEPERKING is de meest onderschatte bouwsteen van deze architectuur. Omdat de policy weet welke klasse data een antwoord bevat, en de routeringslaag weet welke eigenschappen elke provider heeft, kan je uitdrukken: "persoonsgegevens mogen uitsluitend verwerkt worden door een provider met verwerkingslocatie in de EU, zonder training op invoer en met nulretentie; bijzondere categorieën uitsluitend door een model dat binnen ons eigen netwerk draait."
De verplichting DOELBINDING roept meteen de praktische vraag op: gebruikers zeggen zelden waarom ze iets nodig hebben. Het antwoord is dat het doel geen formulier is dat de gebruiker invult, maar een interpretatie die de agent maakt en vastlegt. Vier regels maken dat werkbaar én verdedigbaar:
Elke policyregel kan een defaultDoel dragen — voor een commerciële rol op contactgegevens is dat vanzelfsprekend contactopname, het standaarddoel van die functie. Routinevragen lopen daardoor frictieloos door; de trace markeert het doel als afgeleid of expliciet, zodat een auditor ziet wat interpretatie was en wat de gebruiker letterlijk zei.
De agent weigert nooit op een gegokt doel. Is de vraag eenduidig, dan leidt hij het doel af; is ze dat niet, dan stelt hij één korte wedervraag. Een weigering volgt uitsluitend wanneer het doel verklaard of evident verboden is. Een doelbindingsregime dat routinevragen onderbreekt wordt omzeild — en een omzeilde controle is erger dan geen.
Wie de eigenaar van een gevonden voorwerp zoekt, heeft geen dertig telefoonnummers nodig maar een namenlijst en daarna één nummer. Zodra het doel bekend is, kan de agent het minst gegevensintensieve antwoord voorstellen. Dataminimalisatie wordt zo geen blokkade maar een beter antwoord — iets dat noch botweg weigeren, noch alles dumpen ooit oplevert.
Ze blokkeert verklaard verboden doelen en legt elke claim vast — meer niet. Een gebruiker die liegt over zijn bedoeling houd je er niet mee tegen; wel is achteraf bewijsbaar wat werd geclaimd en wat werd verstrekt. De sloten heten whitelist, afbakening, verplichtingen en toelating; doelbinding is de verklaring-onder-logging daarbinnen.
eigen / team / organisatie. Een kleine organisatie kiest team-lezen (collega's vallen voor elkaar in); een strikte omgeving kiest eigen plus delegatie met vervaldatum: een leidinggevende verleent tijdelijk leesrecht op de portefeuille van de afwezige — expliciet, aflopend, gelogd. Dat is het mandaatmechanisme dat gereguleerde sectoren al kennen, uitgedrukt als policyregel.Het resourceregister beschrijft wat gelezen kan worden; het handelingsregister beschrijft wat gedaan kan worden: de volledige lijst van handelingen die een agent ooit mag voorstellen of uitvoeren, elk met een risicoprofiel. In een leesomgeving (autonomieladder t/m L2) blijft dit register leeg; het wordt ontworpen vóórdat de eerste handeling verleend wordt, nooit erna.
Een handeling is dus nooit "een bevraging met een schrijfvlag" (principe 9). Elke handeling staat vooraf gedeclareerd met haar risicoprofiel:
type Handeling = {
naam: string // bv. "herinnering.verstuur", "reserve.bijstel"
domein: string // koppelt aan kennislaag en resources
omkeerbaarheid: "OMKEERBAAR" // ongedaan te maken zonder spoor naar buiten
| "COMPENSEERBAAR" // herstelbaar met een tegenhandeling (creditnota)
| "ONOMKEERBAAR" // verzonden mail, externe melding, betaling
reikwijdte: { maxBedrag?: Geld; maxAantal?: number; perTijdvak?: Duur }
voorwaarden: Conditie[] // bv. "alleen op eigen portefeuille", "status = X"
minimumLadder: "L3" | "L4" | "L5" // laagste autonomieniveau waarop dit ooit mag
goedkeuring?: { rol: string; vierOgen?: boolean } // vereist bij L4
notificatie: Rol[] // wie het altijd te zien krijgt — de deur die lawaai maakt
terugdraaiplan?: string // verplicht bij L5: hoe de envelop-noodstop herstelt
}
Drie voorbeelden laten zien hoe het risicoprofiel de plaats op de ladder bepaalt — niet andersom:
| Handeling | Omkeerbaarheid | Typische verlening | Waarom |
|---|---|---|---|
| Interne taak aanmaken / afspraak verschuiven | Omkeerbaar | L5 — binnen envelop | Volledig intern herstelbaar; envelop begrenst aantal per dag; notificatie aan de betrokkene volstaat. |
| Betalingsherinnering versturen | Onomkeerbaar (extern zichtbaar) | L4 — na goedkeuring | Raakt een klantrelatie. Goedkeuring per stuk of per batch; reikwijdte begrenst het aantal per run. |
| Dossier-verantwoordelijke wijzigen / reserve bijstellen | Compenseerbaar, gevoelig | L4 met vier ogen | Precies de handeling uit het intentie-kader (§2.3.B): de dief moet door een deur die lawaai maakt — notificatie aan de oorspronkelijke verantwoordelijke is verplicht, niet optioneel. |
De gebruiker (rol FINANCIEEL) typt: "Stuur een betalingsherinnering naar iedereen die meer dan 30 dagen over vervaldatum zit."
De agent stelt via de gewone leeslaag vast om wie het gaat: 13 openstaande facturen, vervaldatum > 30 dagen verstreken. Dit deel is volledig open — geen register nodig, de vraag had ook heel anders kunnen luiden.
De agent vindt factuur.herinnering in het handelingsregister en toetst elke kandidaat aan de gedeclareerde voorwaarden. Eén factuur valt af: die klant kreeg vier dagen geleden al een herinnering, en de voorwaarde eist een cooldown van zeven dagen. Blijven over: 12 — binnen de reikwijdte (max. 15 per run). De agent meldt de uitgesloten klant expliciet, met reden.
Niets wordt verstuurd. De agent legt een voorstel voor: de lijst van 12, per klant het openstaande bedrag, dagen over vervaldatum en het gekozen mailtemplate. De gebruiker heeft rol FINANCIEEL — precies de goedkeurderrol uit het register — en keurt de batch met één klik goed (of haalt er klanten uit).
De uitvoering loopt via het bestaande mailpad van de applicatie — geen tweede schrijfroute. In de trace: de bevraging, de voorwaardentoets (incl. de uitgesloten klant), het voorstel, wie goedkeurde, en per mail het resultaat. De notificatie uit het register gaat naar de rol FINANCIEEL.
Merk op waar de intelligentie zat: in het vertalen van "iedereen die te ver over datum zit" naar de juiste selectie, het toepassen van de cooldown, en het opstellen van het voorstel. Het register bepaalde alleen de vangrails: wélke handeling bestaat, haar voorwaarden, en dat er een mens tussen zit. Had de gebruiker rol COMMERCIEEL gehad, dan was stap 3 geëindigd in een aanbeveling: "12 kandidaten gevonden — goedkeuring vereist rol FINANCIEEL."
De vierde component van de bestuurslaag is kort maar principieel: welk model wat mag doen is een bestuursbeslissing, geen implementatiekeuze. De mechaniek van modelrollen en adapters staat in §2.5.B; hier staat wat erover beslist wordt en door wie.
De routeringstabel is configuratie — per organisatie-eenheid, wijzigbaar zonder deploy, met versiehistoriek:
{
"routering": {
"LICHT": { "provider": "…", "model": "…", "maxTokens": 1024 },
"WERKER": { "provider": "…", "model": "…", "maxTokens": 4096 },
"FRONTIER": { "provider": "…", "model": "…", "maxTokens": 8192 },
"CRITICUS": { "provider": "…ander dan WERKER…" } // diversiteit is de waarde
},
"residentie": { // gekoppeld aan MODEL_BEPERKING (§2.3.B)
"PERSOONSGEGEVEN": { "verwerkingslocatie": "EU", "trainingOpInvoer": false, "retentieDagen": 0 },
"BIJZONDER": { "verwerkingslocatie": "ON_PREM" }
},
"escalatie": { "bijComplexiteit": {…}, "naGatewayFouten": 2, "maxEscalaties": 1 },
"budget": { "perGesprekEur": 0.50, "perDagEur": 25, "bijOverschrijding": "WEIGEREN" }
}
Vier beslissingen leven hier, elk met een eigenaar (§3.4): de rol-naar-model-toewijzing (AI-platformteam — dit is de knop waarmee een modelwissel een instelling is, principe 10); de residentie-eisen per gegevensklasse (privacy en security — de gateway dwingt ze af via de verplichting MODEL_BEPERKING: raakt een antwoord persoonsgegevens, dan vernauwt de toegestane providerverzameling automatisch); de escalatieregels (wanneer een zwaarder model gerechtvaardigd is — twee afgewezen bevragingen zijn goedkoper te escaleren dan vijf mislukte rondes); en de budgetten met hun overschrijdingsgedrag — weigeren, degraderen naar een goedkoper model, of doorlaten met melding; de keuze hoort bij de budgeteigenaar, niet bij de ontwikkelaar (§3.2).
De gateway is de enige doorgang tussen redeneerders en bronnen (principe 1) en het handhavingspunt van alles wat de bestuurslaag declareert. Zelf bevat ze géén beleid — ze voert het uit. Elke aanvraag, hoe klein ook, passeert hier; er bestaat geen tweede pad.
Drie onderdelen, in leesvolgorde:
Vier API-families (kennis, catalogus, bevraging, handeling) met zes aanroepen in de leesomgeving, en de negen-stappen-pijplijn die achter de bevragings-API draait — inclusief de mapping welke aanroep welke stappen doorloopt, en het dataflow-schema. §2.4.A
De declaratieve taal waarin de agent vraagt (geen SQL, geen tekstpad naar de opslag), wat bewust onuitdrukbaar is, en de drie vallen waar de compiler op getest moet zijn. §2.4.B
Elke weigering is een gestructureerd tegenvoorstel met uitvoerbare suggesties — het mechanisme dat de agent zelfcorrigerend maakt. §2.4.C
Zes vermogens in plaats van tientallen vragen. Dat is niet minder intelligentie maar een andere plaatsing ervan: een tool die een vraag is, is eindig; een tool die een vermogen is, is dat niet.
| API-familie | Aanroep | Doet | Levert | Wanneer |
|---|---|---|---|---|
| Kennis | kennis.register | Tier 0 — welke domeinen bestaan | Domeinregister, enkele duizenden tokens | Altijd, gecached |
| kennis.lees | Tier 1, 2 of 3 van een domein, of één sectie | Betekenis, regels of precedent | Zodra het domein bekend is | |
| Catalogus | catalogus.beschrijf | Registerdoorsnede voor genoemde resources | Velden, klassen, relaties, metrieken — geannoteerd met toegang | Vóór het samenstellen van een bevraging |
| Bevraging | bevraag.plan | Droogloop: valideren, autoriseren, ramen — zonder data | Toelaatbaarheid, geschat volume, waarschuwingen | Bij twijfel over omvang of rechten |
| bevraag.voer_uit | De bevraging lezend uitvoeren onder het volledige regime — dit is géén handeling | Rijen plus herkomstenvelop | De werkelijke datatoegang | |
| zoek | Hulpcall: vrije tekst → entiteitsidentificatie. Technisch een vooraf vastgelegde, begrensde bevraging | Maximaal tien kandidaten met referentie | Wanneer de vraag een entiteit bij naam noemt | |
| Handeling | handel.stel_voor · keur_goed · voer_uit · draai_terug | Bestaan niet in de leesomgeving (ladder t/m L2). Verschijnen pas wanneer L3+ verleend wordt, gestuurd door het handelingsregister (§2.3.C) | Vanaf autonomieniveau L3 | |
De negen stappen hieronder zijn de volledige pijplijn van de bevragings-API. De andere aanroepen zijn lichter en doorlopen een verkorte vorm — maar nooit nul: óók een kennisaanroep wordt geautoriseerd en vastgelegd (kennis is data, §2.2).
| Aanroep | Doorlopen stappen | Toelichting |
|---|---|---|
| kennis.register · kennis.lees | 1 · 2 · 9 | Binden (bestaat het domein/de sectie?), autoriseren (mag deze rol dit kennisdoc?), vastleggen. Geen raming — docs hebben een vaste, bekende omvang. |
| catalogus.beschrijf | 1 · 2 · 9 | De toegangsannotatie per veld in het antwoord ís stap 2, vooraf uitgevoerd voor de hele doorsnede. |
| bevraag.plan | 1 – 5 | Droogloop: stopt ná de toelating, vóór de uitvoering. Geen data, wel het oordeel en de raming. |
| bevraag.voer_uit | 1 – 9 | De volledige pijplijn. |
| zoek | 1 · 2 · 6 · 9 | Vaste, begrensde query (max. 10 kandidaten, alleen INTERN-velden) — raming en toelating zijn overbodig omdat de vorm vastligt. |
Elke bevraag.voer_uit doorloopt exact deze stappen. Geen uitzonderingen, geen interne route die er drie overslaat. De rood genummerde stappen zijn de handhavingspunten — klasse 3.
De redeneerder schrijft geen SQL. Hij schrijft een declaratieve specificatie die de gateway compileert. Dat verplaatst uitdrukkingskracht in plaats van haar in te perken: alles wat een bedrijfsvraag nodig heeft is uitdrukbaar, alles wat gevaarlijk is niet.
type Bevraging = {
van: ResourceNaam // uit het register
selecteer?: string[] // velden, ook via 1-op-1 paden
meet?: Meting[] // aggregaties over relaties of velden
waar?: Filter // boom: en/of/niet + veldpredicaten
groepeer?: string[]
sorteer?: { veld: string; richting: "op"|"af" }[]
limiet?: number // begrensd door registermaximum
doel?: string // doelbinding, verplicht bij persoonsgegevens
}
type Meting =
| { als: string; tel: RelatiePad; waar?: Filter } // telling over relatie
| { als: string; som: VeldPad; waar?: Filter } // mits aggregeerbaar
| { als: string; gem|min|max: VeldPad }
| { als: string; metriek: MetriekNaam } // GECERTIFICEERD
Alleen gedeclareerde relatiepaden, maximaal drie stappen diep. Geen kruisproducten, geen koppeling op velden die geen relatie zijn. Dit sluit zowel prestatieontsporingen als onbedoelde datacombinaties uit — dat laatste is een privacyrisico dat zelden benoemd wordt.
Er is geen veld waarin tekst de opslag bereikt. De compiler bouwt uit gevalideerde identifiers en geparametriseerde waarden. Injectie is geen risico dat beheerst wordt maar een constructie die niet bestaat — het antwoord op de vraag hoe je een API zo ontwerpt dat er niet ter plekke gevaarlijke query's ontstaan.
Velden die de basis vormen van een gecertificeerde metriek staan op aggregeerbaar: false. Een som erover wordt geweigerd met verwijzing naar de metriek. Zo kan de redeneerder geen eigen definitie van marge of blootstelling uitvinden.
Tenant-, entiteit- en rechtsgebiedsleutels zijn niet filterbaar en niet selecteerbaar. Ze bestaan uitsluitend als injectie. De redeneerder kan er niet naar vragen en er niet op filteren — en kan dus ook niet ontdekken wat hij niet mag zien.
Waar een naïeve implementatie stukloopt. Alle drie zijn echt en alle drie horen in de testverzameling van de compiler, niet in de oplettendheid van de gebruiker.
Tel je in dezelfde bevraging twee relaties met gewone koppelingen, dan vermenigvuldigen de rijen: een entiteit met tien interacties en vier berichten geeft veertig rijen en beide tellingen worden fout. Regel: elke telling of som over een relatie wordt een gecorreleerde subbevraging, nooit een koppeling in de hoofdbevraging.
"Sorteer op aantal interacties" dwingt volledige berekening vóór de limiet kan knippen. Op tweeduizend rijen prima, op twee miljoen niet. Regel: het register declareert bruikbare indexen; sorteren op een afgeleide is toegestaan tot een geraamde basiskardinaliteit, daarboven weigert de raming met de suggestie eerst te filteren.
De hoofdentiteit afbakenen volstaat niet. Telt de redeneerder over een relatie, dan moet ook die subbevraging afgebakend worden — anders tellen records buiten de afbakening mee. Een lek dat er als een gewoon getal uitziet, en daarom gevaarlijker dan een zichtbare fout. Regel: injectie loopt over het volledige relatiepad; verplichte test per resource dat een aanvraag van A geen record van B raakt.
Het onderdeel dat een star systeem van een lerend systeem scheidt. Een weigering is geen doodlopende weg maar een tegenvoorstel — en dat maakt de redeneerder zelfcorrigerend zonder dat iemand hem iets hoeft te leren.
{
"toegelaten": false,
"code": "VOLUME_OVERSCHREDEN",
"geschat": { "rijen": 2014, "tokens": 41200 },
"drempel": { "rijen": 500, "tokens": 8000 },
"suggesties": [
{ "soort": "LIMIET",
"uitleg": "Je vroeg naar 'de meeste' — sorteer af en neem de top 25.",
"patch": { "limiet": 25, "sorteer": [{…}] } },
{ "soort": "FILTER",
"uitleg": "Beperk tot lopend jaar (412 records).",
"patch": { "waar": { "ontvangenOp": {"jaar": 2026} } } },
{ "soort": "AGGREGEER",
"uitleg": "Of groepeer per status (7 rijen).",
"patch": { "groepeer": ["status"] } }
]
}
{
"toegelaten": false,
"code": "RECHT_ONTBREEKT",
"geweigerd": [
{ "element": "Polis.premieJaarlijks",
"klasse": "FINANCIEEL",
"ontbreekt": "lees:FINANCIEEL",
"rolAanvrager": "SCHADEBEHANDELAAR" }
],
"welToegestaan": ["Polis.nummer", "Polis.status",
"Polis.dekkingstype", "Polis.ingangsdatum"],
"boodschap": "Premiebedragen vallen onder FINANCIEEL. Aantallen, " +
"statussen en dekkingen zijn wel beschikbaar."
}
De aanvrager kan nu twee dingen: opnieuw vragen zonder het bedrag — aantallen zijn vaak al een bruikbaar antwoord — of de gebruiker uitleggen welk recht ontbreekt. Beide zijn beter dan een lege tabel of een cryptische fout.
De redeneerlaag is de vervangbare laag: hier leven de modellen en de agenten, en hier leeft bewust géén enkele veiligheidseigenschap. De laag kent geen opslag, geen rechten en geen afbakening — alles wat ze wil, vraagt ze door de gateway. Daardoor is een modelwissel een configuratiewijziging (principe 10) en groeit de waarde mee met elke generatie betere modellen, zonder dat het risico meegroeit (§1.3).
De vijf blokken uit de band worden elk in een eigen sectie uitgewerkt: orkestratie (§2.5.A — wie doet wat), provider-adapters (§2.5.B — hoe modellen inwisselbaar blijven), de agentlus (§2.5.C — hoe één agent werkt, ronde voor ronde), het antwoordcontract (§2.5.D — de vaste vorm van elk antwoord) en de autonomieladder (§2.5.E — de bestuurde as waarlangs deze laag meegroeit met de modellen; het antwoord op "werkt dit nog over drie jaar?").
Eén vraag wordt zelden door één agent beantwoord. De orkestratie verdeelt het werk over vier vaste rollen — en die rollen zijn declaraties in de configuratie, geen klassen in code: een rol toevoegen of bijstellen is configuratie plus een prompt.
| Rol | Opdracht | Mag deze aanroepen | Denkt met | Grenzen |
|---|---|---|---|---|
| Router | Classificeert de vraag (complexiteit), splitst in deelvragen, kiest de domeinen uit het kennisregister | kennis.register | LICHT | 1 ronde |
| Analist | Beantwoordt één deelvraag: kennis ophalen, catalogus lezen, bevragingen samenstellen, resultaat duiden | alle zes leescalls | WERKER | 8 rondes, 6 bevragingen |
| Synthese | Voegt de bevindingen van de analisten samen tot één antwoord in het antwoordcontract (§2.5.D) | — (ziet alleen bevindingen) | WERKER / FRONTIER | 1 ronde |
| Criticus | Hercontroleert het hoofdcijfer met een onafhankelijk samengestelde bevraging; meldt afwijkingen | bevraag.plan · voer_uit | CRITICUS | 2 rondes |
De router bepaalt de vorm van de graaf: bij een enkelvoudige vraag handelt één analist alles af, zonder synthese; bij een samengestelde vraag (één domein, meerdere metingen) komt de synthese erbij; bij een domeinoverstijgende vraag draaien meerdere analisten parallel — elk met uitsluitend de kennisdocumenten en het toolsubset van hun eigen domein — en weegt de synthese hun bevindingen. De criticus draait alleen wanneer het antwoord een cijfer draagt dat een beslissing kan sturen.
Geen enkele agent praat rechtstreeks met een leverancier. Alles loopt door één neutraal contract; per leverancier vertaalt een adapter dat contract naar diens eigen formaat — en nergens anders leeft leverancierspecifieke vorm.
// De enige interface die orkestratie en agenten kennen.
interface ModelProvider {
naam: string
eigenschappen: {
gestructureerdeAanroep: boolean // native function calling?
streaming: boolean
contextcache: boolean
contextvenster: number
// Bepalend voor MODEL_BEPERKING uit de policy:
verwerkingslocatie: "EU" | "VS" | "ON_PREM" | "ANDERE"
trainingOpInvoer: boolean
retentieDagen: number
certificeringen: string[] // ISO 27001, SOC 2, …
}
genereer(v: Verzoek): Promise<Antwoord>
}
Eén per leverancier, plus één OpenAI-compatibele adapter die de meeste zelf-gehoste en lokale servers in één keer dekt. Vertaling van het neutrale aanroepschema naar het formaat van de leverancier gebeurt binnen de adapter en nergens anders.
Ondersteunt een model geen gestructureerde aanroepen, dan valt de adapter terug op een JSON-modus met schemavalidatie en herkansing. De orkestratie merkt geen verschil; de eigenschappen-vlaggen sturen dat.
Providerstoring is een routeringsgebeurtenis, niet een storing van de dienst. Concentratierisico bij één leverancier is voor gereguleerde instellingen een expliciete toezichtzorg — hier is het een configuratieregel.
Agentcode noemt nooit een model. Ze vraagt om een rol; de routeringstabel in de bestuurslaag (§2.3.D) bepaalt wat die rol vandaag betekent — per organisatie-eenheid, zonder deploy wijzigbaar.
| Rol | Waarvoor | Doorslaggevende eigenschap | Aandeel verkeer |
|---|---|---|---|
| Licht | Classificeren, routeren, herformuleren | Latency en prijs | ± 40% |
| Werker | Bevragingen samenstellen, resultaten duiden, deelantwoorden | Betrouwbaarheid van gestructureerde aanroepen — hier het belangrijkst | ± 45% |
| Frontier | Synthese over domeinen, tegenstrijdigheden wegen, oordeelsvorming | Redeneerdiepte; kosten wegen minder want zeldzaam | ± 10% |
| Criticus | Onafhankelijke controle van het hoofdcijfer | Bij voorkeur een andere leverancier — diversiteit is hier de waarde | ± 5% |
De criticus is de vertaling van challenger model uit klassiek modelrisicobeheer: bij voorkeur een andere leverancier dan de werker, want diversiteit is hier de waarde. Verschil tussen werker en criticus is geen fout maar een signaal — en het wordt gelogd, niet weggepoetst.
Elke rol uit §2.5.A draait op dezelfde motor: een lus die het model laat denken, zijn gateway-aanroepen uitvoert, de resultaten teruggeeft en opnieuw laat denken — tot er een antwoord is of een grens bereikt wordt.
De synthese schrijft geen vrije tekst die daarna geparsed moet worden: ze wordt via een gedwongen structuur (tool-keuze) verplicht deze envelop in te vullen. Eén envelop, meerdere weergaven — en daardoor kán het cijfer in de export niet afwijken van het cijfer op het scherm.
type Antwoordenvelop = {
antwoord: string // markdown, kort, in de taal van de gebruiker
kernwaarde?: { label: string; waarde: number|string; eenheid?: string
toon?: "neutraal"|"positief"|"waarschuwing"|"kritiek" }
tabel?: { kolommen: Kolom[]; rijen: Rij[] } // getypeerd: geld/datum/tekst/getal
grafiek?: { soort: "staaf"|"lijn"|"donut"; … }
aannames: string[] // VERPLICHT — "Periode: 2026 (aangenomen)",
// kwaliteitsnotities uit het register
bronnen: Bron[] // per cijfer: bevragingshash, spec, rijaantal,
// afgekapt-vlag — het audit-spoor (§2.6)
vervolgvragen: string[] // max 3, klikbaar
}
Drie regels maken dit contract meer dan een formaat. Eén: de renderers zijn deterministisch — tekst, KPI-tegel, tabel, PDF en spreadsheet worden alle uit dezelfde envelop opgebouwd, en het model schrijft nooit zelf het bestand (een model dat een rapport hertikt, hertikt vroeg of laat een cijfer fout). Twee: aannames is verplicht en mag niet leeg zijn wanneer er iets aangenomen wérd — een stilzwijgende aanname in een stellig geformuleerd antwoord is precies wat een chat gevaarlijker maakt dan een dashboard. Drie: bronnen draagt de volledige herkomst, zodat "hoe kom ik hieraan?" één klik is en elk cijfer natelbaar blijft tot op de bronrij (principe 8).
Hoe een systeem meegroeit met capaciteit zonder herbouw. Dezelfde gateway, dezelfde policy-engine; wat verandert is welke handelingen verleend zijn — per rol, per domein, per omgeving.
Zonder deze laag is het systeem een orakel. Met deze laag is het een bedrijfsmiddel dat zich kan verantwoorden tegenover een auditor, een toezichthouder en een betrokkene die inzage vraagt.
Per gesprek een boom: elke ronde met modelrol, provider, prompt-hash, tokens, kosten, duur — en per gateway-aanroep de specificatie, de policy-beslissingen, de raming, het rijaantal en de bevragingshash. Bewaartermijn en redactie zijn zelf beleid: traces bevatten data, dus vallen ze onder hetzelfde regime.
Een trace opnieuw uitvoeren tegen een ander model of een nieuwere registerversie en de verschillen tonen. Dit maakt van een modelwissel een meting in plaats van een gok: draai de laatste duizend gesprekken opnieuw, vergelijk uitkomsten en kosten, beslis daarna. Het is ook het regressiemechanisme voor wijzigingen in de semantische laag.
Gouden vragen in de bouwstraat, in drie soorten: correctheid (klopt het cijfer tegen een onafhankelijk berekende waarheid), veiligheid (een aanvraag namens A raakt geen record van B; een beperkte rol krijgt geen beschermde klasse), zuinigheid (blijft het aantal rondes en de kost binnen de grens).
Voor een gereguleerde instelling is dit de sectie die bepaalt of het systeem in productie mag. De afbeelding is bewust op componenten, niet op beloften.
| Kader | Kernverplichting | Waar de architectuur dat draagt |
|---|---|---|
| EU AI-verordening | Risicoclassificatie; registratie van gebeurtenissen gedurende de levensduur; menselijk toezicht; transparantie naar gebruikers | De trace ís het gebeurtenissenlogboek — met invoer, beslissingen en uitkomst per stap. De autonomieladder maakt menselijk toezicht een verleningsbeslissing per handeling in plaats van een intentie. Classificatie van het gebruik volgt uit het handelingsregister: adviseren is een ander risicoprofiel dan beslissen. |
| AVG / GDPR | Doelbinding, minimale gegevensverwerking, rechtmatige grondslag, rechten van betrokkenen, geen louter geautomatiseerde besluiten met rechtsgevolg | Grondslag per veld in het register; doelbinding als verplichte parameter en toetsingsstap; minimalisatie afgedwongen door projectie en drempels; de trace beantwoordt een inzageverzoek; art. 22 wordt gedragen doordat besluitvormende handelingen op L4 of lager staan. |
| DORA | Beheersing van ICT-risico bij derden; concentratierisico; uitwijk en exitstrategie | Providerabstractie maakt van uitwijk een routeringsregel. Meerdere providers naast elkaar verlagen concentratierisico structureel; de exitstrategie is aantoonbaar omdat herspelen laat zien dat de dienst op een andere leverancier dezelfde uitkomsten geeft. |
| BCBS 239-beginselen | Nauwkeurigheid, volledigheid en herleidbaarheid van risicodata-aggregatie | Gecertificeerde metrieken met eigenaar en herzieningsdatum; herkomst tot op de bronrij; registerversie vastgelegd bij elk resultaat, zodat een cijfer van vorig kwartaal reproduceerbaar blijft. |
| Solvency II / EIOPA | Datakwaliteit voor rapportage; beheersing van modelrisico; verantwoordingsplicht bestuur | Kwaliteitsnotities per resource die automatisch in de aannames van een antwoord belanden; criticus-agent als challenger; evaluatieverzameling als doorlopende validatie; bestuur ziet één catalogus met eigenaars. |
| Datasoevereiniteit | Beperkingen op verwerkingslocatie per gegevenscategorie | MODEL_BEPERKING koppelt gegevensklasse aan providereigenschappen. Persoonsgegevens routeren automatisch naar EU-verwerking; bijzondere categorieën naar eigen infrastructuur — afgedwongen, niet afgesproken. |
Wie vraagt wat, wat kost het, en wat levert het op. Zonder deze cijfers wordt elk AI-programma na een jaar een discussie op basis van meningen.
De sturing zelf is beleid, geen code: budgetplafonds per gesprek, per gebruiker per dag en per eenheid per maand, met een instelbaar gedrag bij overschrijding — weigeren, degraderen naar een goedkoper model, of doorlaten met melding. Alle drie zijn verdedigbaar in verschillende contexten; de keuze hoort bij de eigenaar van het budget, niet bij de ontwikkelaar.
De toets op generaliseerbaarheid. Links een middelgrote multi-tenant ERP-omgeving, rechts een internationale verzekeraar. Dezelfde vijf lagen, dezelfde negen stappen, dezelfde ladder — andere invulling.
| Architectuurbegrip | ERP — reference implementation | Internationale verzekeraar |
|---|---|---|
| Afbakeningsas 1 | Tenant (werkmaatschappij binnen een groep) | Entiteit per land / branche, met verschillende toezichthouders |
| Afbakeningsas 2 | Juridische entiteit voor financiële gegevens | Rechtsgebied plus distributiekanaal (eigen net, makelaar, volmacht) |
| Kernresources | Opportuniteit, project, factuur, werkopdracht, planning | Polis, dekking, schadeclaim, premie, reserve, herverzekeringscessie, tussenpersoon |
| Gecertificeerde metrieken | Omzet, onderaannemerskost, marge, openstaand saldo | Schaderatio, gecombineerde ratio, IBNR-reserve, technisch resultaat, klantwaarde |
| Bijzondere klasse | Contactgegevens, personeelsdocumenten | Medische dossiers bij letselschade, strafrechtelijke gegevens bij fraudeonderzoek |
| Tier-3 precedent | Eerdere calculatiebesluiten, afwijkende afspraken per klant | Eerdere schaderegelingen in grensgevallen, acceptatiebeslissingen, interpretaties van polisvoorwaarden |
| Typische L2-vraag | "Welk project had de laagste marge en lag dat aan kosten of prijs?" | "Welke tussenpersonen verslechterden in schaderatio motor 2024, en zit dat in frequentie of in gemiddelde last?" |
| Typische L4-handeling | Een herinnering versturen; een planning verschuiven | Een reserve bijstellen binnen mandaat; een routinematige claim afhandelen onder drempel |
| Zwaarste eis | Geen kruisverkeer tussen tenants; natelbaarheid van elk financieel cijfer | Datasoevereiniteit per rechtsgebied; herleidbaarheid voor toezicht; geen louter geautomatiseerde besluiten richting verzekerden |
| Schaalverschil | Tientallen gebruikers, miljoenen rijen | Duizenden gebruikers, miljarden rijen, tientallen bronsystemen |
Architectuur zonder eigenaarschap verwatert binnen twee kwartalen. Dit is de verdeling die maakt dat de lagen onderhouden blijven.
| Artefact | Eigenaar | Goedkeuring | Ritme |
|---|---|---|---|
| Semantisch register — velden, relaties | Domein-data-eigenaar | Code-review + bouwstraatcontrole | Bij elke schemawijziging |
| Gevoeligheidsklassen en grondslagen | Privacy- en informatiebeveiliging | Vieroog, vastgelegd | Bij nieuwe velden; jaarlijkse herziening |
| Gecertificeerde metrieken | Functionele eigenaar (Finance, Actuariaat, Commercie) | Eigenaar + risicobeheer | Bij definitiewijziging; herzieningsdatum verplicht |
| Policy — rol × klasse × actie | Informatiebeveiliging | Vieroog + simulatie vóór inwerkingtreding | Bij organisatiewijziging |
| Kennistiers 1–3 | Domeinexperts | Vakinhoudelijke review | Doorlopend; tier 3 groeit per afgehandeld grensgeval |
| Modelroutering en budgetten | AI-platformteam | Eigenaar + inkoop bij nieuwe leverancier | Per kwartaal of bij marktverandering |
| Evaluatieverzameling | AI-platform samen met domeinexperts | Bouwstraat blokkeert bij regressie | Groeit met elke fout die gevonden wordt |
| Autonomieverleningen (L3+) | Business-eigenaar van het proces | Risicobeheer; onderbouwd met trace-bewijs | Per proces, met evaluatie na inwerkingtreding |
Deze architectuur is geen eigen uitvinding die de lezer op gezag moet aannemen. Ze is de vendor-neutrale beschrijving van het patroon waar de grote platformen en de semantische-laag-markt in 2025–2026 onafhankelijk van elkaar op geconvergeerd zijn. Dat is een sterkte: het patroon is gevalideerd; wat dit document toevoegt is de samenhang en het beslissingskader.
| Laag (dit document) | Microsoft | AWS / Google | Databricks / Snowflake | Onafhankelijke spelers |
|---|---|---|---|---|
| Kennislaag | Foundry-kennisbronnen, Copilot-grounding | Bedrock Knowledge Bases / Vertex AI Search | — | Retrieval-platformen; de tier-structuur met precedent is zeldzaam en meestal klantwerk |
| Bestuurslaag | Purview (classificatie, labels), Entra Agent ID | Bedrock Guardrails-policies / Vertex-governance | Unity Catalog / Horizon | Immuta, Collibra; OPA en Cedar voor policy-as-data |
| Gateway | AI Agent Landing Zone, Foundry Agent Service | Bedrock Agents + Guardrails / Agent Builder | Unity AI Gateway / Cortex Analyst semantic models | Cube, AtScale (semantische laag met compile-time-rechten); Kong, Portkey, LiteLLM (modelverkeer) |
| Redeneerlaag | Foundry-modelcatalogus, multi-model routing | Bedrock-modelkeuze / Vertex Model Garden | Model serving endpoints | Portkey, LiteLLM, OpenRouter — routing, failover, kostenmeting |
| Bewijslaag | Purview-audit, Foundry-tracing | CloudWatch/Bedrock-invocatielogs / Vertex-tracing | Lakehouse Monitoring | Langfuse, Arize, Braintrust — traces, evals, kostentoerekening |
Twee observaties die het beslissingskader vormen:
De gevestigde data-gateways en semantische lagen zijn gebouwd voor analytische platformen — warehouse en lakehouse. Voor een organisatie waarvan de data daar al ligt, is kopen de voor de hand liggende route en wordt dit document het evaluatiekader. Voor een operationeel systeem op een transactionele database — zoals de reference implementation — bestaat er geen passend product van de plank, en is een dunne eigen gateway op het bestaande autorisatiemodel de kortere en veiligere weg. Grote organisaties doen doorgaans beide: kopen voor het analytische landschap, bouwen voor de operationele kernen.
Geen enkel platform kan de data van de klant classificeren, de metrieken definiëren of de domeinkennis vastleggen. Een classificatietool herkent een telefoonnummer, maar niet dat een gefactureerde vordering niet als omzet telt. Het semantisch register, de gecertificeerde metrieken en de kennistiers zijn bij elke opzet klantwerk — dat is dus geen overhead die deze architectuur toevoegt, maar de kern die hoe dan ook gedaan moet worden. De architectuurkeuze bepaalt alleen of dat werk één keer gebeurt, op één plek, met één eigenaar — of verspreid en impliciet in elke integratie opnieuw.
De vijf lagen als infrastructuur: welke zones, welke servers, welk netwerk — en per vraagtype het pad dat een aanvraag over die servers aflegt. Klik op een onderdeel voor wat, hoe en waarom.
Klik op een onderdeel in het schema — of kies er hieronder een.
Dezelfde servers, vijf soorten aanvragen. Elke pijl is één stap; elke stap heeft een meetpunt in obs-01, en stap "log" is de wettelijke bewijslast. Rood is de enige route naar buiten; blauw verlaat de eigen muren nooit.
Een expliciete toets: als de redeneerder over drie jaar aanzienlijk capabeler is dan een menselijke expert, welke onderdelen van dit ontwerp houden stand en welke moeten mee-evolueren?
| Onderdeel | Uitkomst | Waarom |
|---|---|---|
| Afbakeningsinjectie | Ongewijzigd | Klasse 3. Werkt identiek ongeacht wie vraagt — dat is de definitie van capaciteitsonafhankelijk. |
| Policy-evaluatie | Ongewijzigd | Idem. Wordt niet zwakker doordat de aanvrager slimmer is. |
| Toelatingscontrole | Drempels stijgen | Het mechanisme blijft; een capabeler model verdient een ruimer venster omdat het beter met meer data omgaat. Een instelling, geen herbouw. |
| Bevragingstaal | Verrijkt | Sterkere modellen stellen complexere bevragingen samen. Vensterfuncties, cohortanalyse, tijdreeksen komen erbij — als uitbreiding van de taal, niet als omweg eromheen. |
| Aantal agentrollen | Neemt af | Router, analist en synthese bestaan omdat huidige modellen baat hebben bij contextscheiding. Een capabeler model doet dat zelf. De graafconfiguratie krimpt; de gateway eronder verandert niet. |
| Kennistiers | Waardevoller | Een sterkere redeneerder haalt méér uit precedent, niet minder — hij herkent scherper welk eerder geval van toepassing is. Tier 3 wordt belangrijker naarmate de redeneerder beter wordt. |
| Autonomieniveau | Stijgt bewust | Van L2 naar L4 en voor sommige processen L5. Een verleningsbeslissing per rol en domein, onderbouwd met trace-bewijs uit het niveau eronder. |
| Verificatie door mensen | Verschuift wezenlijk | Redenering nalezen verliest zijn waarde. Bewijsketens en steekproeven op uitkomsten nemen het over. Dit is de enige verandering die architectuur vooraf moet dragen — achteraf inbouwen kan niet. |
| Prompt als sturing | Verliest werking | Klasse 1 degradeert. Wie er veiligheid op bouwde, moet dan herbouwen. Wie hem alleen voor kwaliteit gebruikte, merkt er niets van. |
Wat deze architectuur expliciet afwijst, en waarom. Het eerste punt is een correctie op het eerste ontwerp — de fout is leerzaam genoeg om te tonen.
| Patroon | Waarom het aantrekkelijk lijkt | Waarom het faalt |
|---|---|---|
| Toolwildgroei — één tool per vraagsoort | Elke tool is afzonderlijk veilig en makkelijk te begrijpen | Het vraagbereik is begrensd door de verbeelding van de ontwerper; de catalogus groeit tot ze zelf niet meer in de context past; elke nieuwe vraag vraagt een release. Dit was de fout in de eerste versie van dit ontwerp. |
| Prompt als beleid | Snel, flexibel, geen infrastructuur nodig | Klasse 1: niet afdwingbaar, niet bewijsbaar, niet uitputtend testbaar — en degradeert precies wanneer de modellen beter worden. |
| Directe SQL-generatie op productie | Maximale flexibiliteit, snel te demonstreren | Afbakening niet afdwingbaar, definities worden herleid in plaats van gebruikt, onbegrensde resultaten, injectie-oppervlak, en niets is reproduceerbaar. |
| Vector-retrieval als standaardantwoord | Eén patroon voor alles; volwassen gereedschap | Uitstekend voor ongestructureerde tekst, ongeschikt voor precieze aggregatie over gestructureerde data. Benaderend zoeken levert benaderende cijfers — onaanvaardbaar voor financiële en actuariële vragen. Beide naast elkaar, elk voor waar het thuishoort. |
| Alles in de context stoppen | Grote contextvensters lijken het probleem op te lossen | Kosten schalen lineair met ruis, precisie daalt bij irrelevante inhoud, en de rechtenvraag verdwijnt niet — hij wordt alleen onzichtbaar. |
| Menselijk toezicht als vinkje | Voldoet ogenschijnlijk aan de eis | Een goedkeurder die tien voorstellen per minuut ziet, keurt goed. Toezicht werkt alleen met begrensd volume, echte weigermogelijkheid en zichtbaar bewijs — anders is het schijnzekerheid met een auditspoor. |
| Leverancierspecifieke koppeling | Het snelste pad naar een werkende demo | Formaten, aanroepconventies en eigenaardigheden lekken in de bedrijfslogica. Wisselen wordt een project in plaats van een instelling — en toezichthouders vragen inmiddels naar uitwijk. |
Wat na dit alles nog moeilijk blijft. Een referentiearchitectuur die alleen de opgeloste problemen benoemt, is een verkoopdocument.
Met een open bevragingstaal kan een redeneerder twee sommen combineren en het resultaat een naam geven die met de gezaghebbende definitie botst. Vier verdedigingslagen — gecertificeerde metrieken, niet-aggregeerbare basisvelden, zelflabeling van antwoorden als gezaghebbend of zelf samengesteld, en een criticus met een onafhankelijke bevraging — verkleinen het maar sluiten het niet uit. Daarom is natelbaarheid geen extra, maar de voorwaarde waaronder financiële antwoorden gepresenteerd mogen worden.
De bouwstraatcontrole voorkomt achterlopen, maar verlegt de last naar elk schemavoorstel. In een grote organisatie met tientallen domeinteams is dat federatief bestuur met alle bijbehorende afstemming. Het is bewust — het is de prijs van principe 3 — maar het moet begroot worden, niet weggewuifd.
Eén gezaghebbende metriek betekent dat iemands bestaande rapportage ongelijk krijgt. Dat is een bestuurlijk vraagstuk met eigenaars en belangen, en het is doorgaans het traagste onderdeel van het traject. Techniek kan het zichtbaar maken; beslissen moet de organisatie zelf.
Een perfect herleidbaar antwoord op een verkeerd gestelde vraag blijft misleidend, en een correct cijfer over een periode die niet representatief is, is nog steeds een verkeerd inzicht. Vandaar de verplichte aannames in elk antwoord en de kwaliteitsnotities per resource — maar de laatste beoordeling of de vraag de juiste was, blijft menselijk. Dat is geen tekortkoming van dit ontwerp; het is de grens van wat een systeem over zichzelf kan weten.
Vensterfuncties over onregelmatige tijdvensters, recursieve hiërarchieën, statistische procedures. Twee eerlijke uitwegen: de taal uitbreiden wanneer een patroon zich herhaalt, of een streng afgeschermde escape met eigen recht, menselijke bevestiging en verplichte herkomst. Doen alsof die vijf procent niet bestaat, leidt tot schaduwoplossingen buiten de gateway — en dat is erger dan een bestuurde uitzondering.
De volgorde is bewust: bestuur vóór intelligentie. De eerste twee fasen leveren geen zichtbare chat op — en zonder die twee bouw je een systeem waarvan je de veiligheid achteraf moet bewijzen, wat niet lukt.
| Fase | Wat | Inhoud | Klaar wanneer |
|---|---|---|---|
| 0 | Semantiek en policy | Register met classificatie en afbakeningspaden voor vijf kernresources; policy-engine met verplichtingen; bouwstraatcontrole op ongeclassificeerde velden | Veiligheidstests groen: geen kruisverkeer tussen afbakeningen; beperkte rol krijgt geen beschermde klasse |
| 1 | Gateway | Bevragingstaal, compiler met gecorreleerde subbevragingen, afbakening over relatiepaden, raming, toelating, lees-only rol, zes aanroepen. Nog geen AI. | Een niet-voorziene analytische vraag draait via de API vanuit een testscript |
| 2 | Redeneerlaag | Providerinterface met één adapter, agentlus, router/analist/synthese, modelrollen uit configuratie, volledige trace | Vragen die niemand vooraf bedacht heeft worden end-to-end beantwoord, met herkomst |
| 3 | Interface en oplevering | Gespreksinterface met zichtbare stappen, herkomst uitklapbaar, doorklik naar bronrijen, export | Bruikbaar zonder tussenkomst van een ontwikkelaar |
| 4 | Bestuur zichtbaar | Beheerschermen voor rechten, catalogus en gesprekken; tweede provider-adapter; herspelen; evaluatieverzameling; criticus | Modelwissel is een instelling met een meting; rechten zijn simuleerbaar vóór inwerkingtreding |
| 5 | Verbreding en autonomie | Register uitbreiden per domein; tier-3-precedent opbouwen; handelingsregister; L3 en daarna L4 voor geselecteerde processen | Autonomie wordt verleend op basis van bewijs uit de trace van het niveau eronder |
"Welke opportuniteiten hebben de meeste interacties en de meeste e-mailcommunicatie?" — een vraag waarvoor niets is voorbereid. Dit is de toets die de hele architectuur moet doorstaan.
Classificeert met het domeinregister in de gecachte systeemprompt: samengestelde vraag, één domein met een raakvlak. Eén analist, synthese, geen criticus — er is geen financieel cijfer in het spel.
Haalt tier 1 van het commerciële domein op. Leert de statusverlopen, en dat interacties polymorf zijn opgeslagen met een typeveld — waardoor hij straks niet per ongeluk interacties van andere entiteitsoorten meetelt. Dat is precies het soort domeinkennis dat het verschil maakt tussen een cijfer dat klopt en een cijfer dat plausibel oogt.
Vraagt het register voor Opportuniteit en ziet velden, klassen, toegangsannotaties en relaties. Merkt dat de relatie naar conversaties verwijst naar een resource die zélf berichten heeft, vraagt in dezelfde ronde ook die op, en kent daarmee het tweestapspad.
Stelt zijn eerste specificatie samen en laat hem droogdraaien. De gateway autoriseert alles, injecteert de afbakening, raamt 2.014 rijen ≈ 41k tokens en weigert met drie verfijnsuggesties. Geen data — wel richting.
Neemt de suggestie over en verfijnt zelf verder: alleen inkomende berichten, want communicatie van de klant is een betere maat voor betrokkenheid dan eigen verzonden post. Die afweging is precies het stuk dat je niet in een tool kan vastleggen — en de reden dat het vraagbereik open moet zijn.
{ "van": "Opportuniteit",
"selecteer": ["id", "naam", "status", "klant.naam"],
"meet": [
{ "als":"interacties", "tel":"interacties" },
{ "als":"inkomendeMail","tel":"conversaties.berichten",
"waar":{ "richting":"IN" } },
{ "als":"laatsteContact","max":"interacties.datum" } ],
"sorteer": [{"veld":"interacties","richting":"af"},
{"veld":"inkomendeMail","richting":"af"}],
"limiet": 25 }
De compiler maakt géén koppelingen maar gecorreleerde subbevragingen — anders bederft val 1 uit §2.4.B beide tellingen — en injecteert de afbakening die de agent niet gevraagd heeft en niet kan weglaten:
SELECT o.id, o.naam, o.status, k.naam AS klant_naam,
(SELECT count(*) FROM interacties i
WHERE i.opp_id = o.id AND i.entiteit_type = 'opportuniteit') AS interacties,
(SELECT count(*) FROM berichten b
JOIN conversaties c ON c.id = b.conversatie_id
WHERE c.opp_id = o.id AND b.richting = 'IN') AS inkomende_mail,
(SELECT max(i.datum) FROM interacties i WHERE i.opp_id = o.id) AS laatste_contact
FROM opportuniteiten o
LEFT JOIN organisaties k ON k.id = o.klant_id
-- afbakeningsinjectie: niet gevraagd, niet weg te laten
WHERE EXISTS (SELECT 1 FROM opp_tenants t
WHERE t.opp_id = o.id AND t.tenant_id = ANY($1))
ORDER BY interacties DESC, inkomende_mail DESC
LIMIT 25;
Duiding, de tabel van 25, de aannames ("betrokkenheid gemeten als inkomende berichten plus geregistreerde interacties; alle jaren"), de herkomst (één bevraging, hash, 25 van 2.014 na sortering) en twee vervolgvragen.
"Welke tussenpersonen verslechterden het sterkst in schaderatio op motorrijtuigen 2024, en zit die verslechtering in frequentie of in gemiddelde schadelast?"
Dezelfde vijf lagen, drie verschillen die de sectorspecifieke eisen dragen:
| Aspect | Uitwerking |
|---|---|
| Gezaghebbende metriek | Schaderatio wordt niet door de redeneerder samengesteld. Het is een gecertificeerde metriek met een eigenaar bij Actuariaat, met de vastgelegde behandeling van IBNR, schaderegelingskosten en herverzekeringsherstel. De basisvelden staan op niet-aggregeerbaar, dus een zelfbedachte variant wordt geweigerd met verwijzing naar de metriek. De ontleding naar frequentie en gemiddelde last zijn twee aanvullende gecertificeerde metrieken — precies de decompositie die de vraag stelt. |
| Afbakening | Twee assen tegelijk: de entiteit die het risico draagt (rechtsgebied en toezichthouder) en het distributiekanaal. Een gebruiker bij de Belgische entiteit ziet geen Franse portefeuille, ook niet in een totaal — en het aggregaat verraadt dat verschil niet, want de injectie zit in de subbevraging. |
| Modelbeperking | Het antwoord bevat geen persoonsgegevens — het gaat over tussenpersonen en portefeuilles — dus de volledige providerverzameling is toegestaan. Zou dezelfde analyse afdalen naar individuele schadedossiers met letselgegevens, dan vernauwt de policy de toegestane modellen automatisch tot on-premise verwerking, zonder dat iemand daaraan hoeft te denken. |
| Tier 3 | Bij de duiding van uitschieters raadpleegt de analist eerdere acceptatiebeslissingen en portefeuillesaneringen: is deze verslechtering al eens vastgesteld en welke maatregel volgde? Dat maakt het verschil tussen een correct cijfer en een bruikbaar advies. |
| Autonomie | Blijft op L2 — analyseren en rapporteren. Een portefeuillemaatregel voorstellen is L3 en vraagt een expliciete verlening; een commissie of mandaat effectief aanpassen is L4 met vieroogprincipe. De architectuur draagt alle drie; de organisatie beslist waar de grens vandaag ligt. |
How to give autonomous AI agents an open question range over company data without giving up control of permissions, provenance, cost and risk — and how to build it so that it keeps working when the models behind it have become unrecognisably more capable.
Video 3 in the series · 2:41 · Dutch spoken, English subtitles — what this document works out, on screen: how one question travels through the AI gate, with the same check at every step.
This is the technical treatment: how you give AI agents an open question range over your company data without giving up control over permissions, provenance, cost and risk. It is written with a regulated organisation in mind — several entities, an auditor, a regulator.
Staying here? Then you need to know nothing about this document in advance. The executive summary below gives the four propositions; after that each layer is worked out separately.
Organisations want AI agents that answer questions about their own data. The common implementations choose between two evils: either you restrict what may be asked (a fixed catalogue of tools or reports — safe but stupid), or you give the model free access (schema plus SQL generation — clever but ungovernable). This architecture refuses that choice.
The core is a gateway: one passage between reasoners and data, where permissions, tenant scoping, volume, provenance and cost are enforced — not by instructions to the model, but by code that runs regardless of what the model attempts. Above it sits a semantic layer that records which entities, fields, relations and certified metrics exist, each with a sensitivity class. Within that layer the agent freely composes its own queries — including questions nobody thought of in advance — while it never touches a SQL string and cannot widen its own scoping.
Most failed AI data-access projects fail not in the build but in the problem statement. "Build a chatbot on our data" is an assignment that steers the answer wrong from the outset.
How do you give a non-deterministic reasoner an open question range over data that is governed on several axes — per entity, per role, per sensitivity class, per jurisdiction — without every new question becoming a security question all over again?
The last clause is the whole task. In a system with fixed reports, each report is reviewed once and safe thereafter. In a system with an open question range, "the question" does not yet exist at the moment you have to approve it. So you cannot review questions; you have to review access. Everything in this architecture follows from that shift.
You cannot enumerate the questions — the useful ones are by definition the unforeseen ones. You can enumerate the data, and who may see what of it. So freeze what is governable and leave what is not governable free.
The model you choose today is obsolete in eighteen months, possibly from a different vendor, possibly running locally for sovereignty reasons. Everything that is governance has to sit outside it — otherwise you rebuild it at every swap.
A slow answer is a nuisance. A convincingly wrong answer on a claims reserve, a margin or an exposure drives a wrong decision and is only discovered much later. Every trade-off therefore falls in favour of verifiability.
In a regulated environment, "why did the system say this?" is not a debugging question but a supervision question, with deadlines and retention obligations. Evidence belongs in the architecture, not in the logging backlog.
This is the analytical backbone of the document. Every control in every AI system falls into one of three classes, and that class predicts how the control behaves as the model gets better.
What: instructions in the system prompt. "Never show data from other customers." "Do not invent figures." "Ask for confirmation before you change anything."
Why it fails as a boundary: its operation depends on the willingness and the understanding of the model. It cannot be enforced, cannot be proven and cannot be exhaustively tested — the space of formulations that circumvent it is infinite. Worse: a more capable model finds more paths, not fewer, and text from the data itself (a customer name, an email body, a claims file) can speak with the same authority as your instruction.
Legitimate use: quality, tone, format, preferred ordering. Never: confidentiality, scoping, authorisation, irreversible actions.
What: restricting what can be attempted at all. A fixed catalogue of ten tools. Pre-written reports. No SQL access.
Why it is insufficient: it works — but the ceiling sits at the imagination of the designer on the day he wrote the catalogue. As models become more capable, the restriction becomes the binding constraint instead of the model. You pay for a reasoner and use it as a menu card.
Legitimate use: cost, performance, blast radius of actions. Unsuitable as: the primary security boundary, because every extension calls for a fresh security review.
What: control that runs outside the model and does not depend on its cooperation. Policy evaluation per field. Scoping injected into the query. Admission control on volume. Read-only database roles. Mandatory provenance recording.
Why it holds up: its effectiveness is independent of who or what makes the request. A vault door does not ask how clever the person in front of it is. The same control works identically for a weak model, a superior model, a compromised integration or an employee with stolen credentials — and that is precisely the property you need in an enterprise environment.
Cost: design work up front. You have to describe and classify your data model semantically before you let AI loose on it. That is the investment this document defends.
Three established principles are the litmus test for any access architecture. This design relates to them as follows — including the place where it deliberately departs from the pure doctrine.
Every query is fully verified at the moment itself: identity from the session, policy per field, scoping injected afresh. The gateway is the policy enforcement point, the governance layer the policy decision point. Further than classical Zero Trust: the reasoner itself is untrusted too — the design assumes the model may have been manipulated (injection via data), hence no text path to storage and scoping beyond its reach. "Intent is not an access primitive" is never trust, always verify, applied to intentions.
The unforgeable part is there: the scoping context reaches execution outside any schema, so the agent cannot even express what has not been granted to it; each agent gets only the tool subset of its role; delegation with an expiry date is a classical capability grant. Signed tokens passed around are deliberately absent: within one server boundary with one reference monitor they add nothing. As soon as service boundaries appear (the federated deployment, §3.3), decisions do materialise as short-lived signed query capabilities — same model, distributed form.
Pure PoLP per operation×field is, with open querying, the thousands-of-decisions problem — and unmanageable permission lists bog down in stale grants: privilege sprawl violates least privilege harder than a coarser but maintained structure. Here the minimal authority per request arises as an intersection: role×class ∩ subject reach ∩ resource refinement ∩ obligations (masking, aggregate-only, no export) ∩ purpose binding ∩ tool subset ∩ expiring delegations. The minimal-path behaviour (names first, then one number) is dynamic least privilege — minimisation per question, which static permissions by definition cannot do.
In this design, roles encode not intentions but job necessity (need-to-know); they are an administrative compression of grants. The enforcement nowhere refers to intentions.
The question "will this still work in three years, once AI has become superhuman?" is answerable, and the answer is not "we hope so".
Definition. A control is capability-independent when its effectiveness does not depend on the ability of the entity it governs.
Access control on a database is capability-independent: it knows no difference between a junior analyst and a superintelligence, it knows only credentials. An instruction in a prompt is not: its operation is entirely a function of how the model interprets it.
An architecture holds up under rising model capability if, and only if, growing capability raises the value without lowering the safety. That calls for two things at once:
A better model asks better questions, chooses smarter aggregations, recognises more sharply which domain knowledge it needs and draws better conclusions from little data. All that gain falls within the question side — precisely what this architecture leaves free. More capability here means more value straight away, without a single line of code.
Policy evaluation, scoping injection and admission control run identically, no matter who asks. They do not become weaker because the requester is cleverer. More capability here means no extra risk — and that is the only reason you can safely bring in a stronger model.
A practical investment guide that follows from the same thinking. If you are allocating budget across an AI programme today, this is the allocation that is still defensible in three years:
| Depreciates fast — keep thin and replaceable | Appreciates — this is where the investment belongs |
|---|---|
| Prompt texts and few-shot examples | Ontology and semantic layer — the recorded meaning of your entities, fields and relations |
| Model choice, fine-tunes, vendor-specific integrations | Data classification — what is sensitive, why, and under which regime |
| Tool implementations built around the quirks of one model | Policy as data — who may do what, expressed so that it is evaluable and testable |
| This year's orchestration frameworks | Certified metric definitions — the one authoritative calculation of margin, exposure, loss ratio |
| Retrieval tuning around a specific embedding model | Knowledge layer and precedent collection — how this organisation decides, recorded (§2.2) |
| Interface details of the chat layer | Evidence and evaluation collection — traces, golden questions, regression coverage |
Statements that always hold, regardless of domain, model or implementation. When a choice in the build collides with a principle, the choice is wrong — not the principle.
The separation that keeps the system maintainable. Each layer has its own rhythm of change, its own owner and its own quality regime — and that is not aesthetics but the reason a model swap does not touch governance.
Data says what happened. Knowledge says what it means. A reasoner that has the first and lacks the second produces figures that are correct and answers that are no good.
| Tier | Content | When it loads | Why this layer exists |
|---|---|---|---|
| 0 · Register | All domains with keywords, routes and a reference to their core document | Always, in every call (cached) | The reasoner knows what exists without knowing any of it. A few thousand tokens replace hundreds of thousands. |
| 1 · Core | Purpose of the domain, invariants, field meaning, status flows, prohibitions | For the one to three domains selected | Prevents the most common error: correct SQL on a misunderstood field. This is where "which status counts as outstanding" belongs. |
| 2 · Rules | Business rules, process steps, edge cases, exceptions | On request, per section | Unbounded in size without raising the context cost of every question. The reasoner fetches what the question requires. |
| 3 · Precedent | Worked cases, earlier decisions with their reasoning, interpretations by regulators, architecture decisions | On request, when the question calls for judgement | Institutional memory. The difference between an answer that is right in general and an answer that is consistent with how this organisation decides. |
All four tiers are fetched through the gateway, not by a file read at the side door. Three reasons, and the third is the most important: knowledge documents can themselves contain sensitive information — a tier 3 precedent describes a concrete case; access to a domain core document reveals that the domain exists; and the question of which knowledge was consulted is part of the accountability for the answer. Knowledge retrieval is therefore permission-checked and logged, like every other request.
The governance layer is the declarative memory of what is allowed: everything set out here is data — version-controlled, evaluable, testable and open to simulation before it takes effect. It changes at the rhythm of the organisation (a new role, a stricter rule, a temporary delegation), never at the rhythm of the code. And it does nothing itself: the gateway (layer 3) enforces what is declared here.
The four blocks above are worked out in this order: the semantic register (§2.3.A), the policy (§2.3.B), the action register (§2.3.C) and the routing (§2.3.D).
The whole in one sentence: the register describes, the policy grants, the action register bounds the doing, and the routing bounds the thinker. Anyone who wants to change the behaviour of the system changes data here — and can read back in the evidence layer what that change did.
The register is the agreed reality: what exists as far as the AI is concerned. Emphatically not the physical schema, but a deliberate, classified cross-section of it with meaning attached.
// One resource, declarative. Domain-neutral pattern;
// filled in here for a commercial opportunity.
defineResource({
name: "Opportunity", storage: "leads", domain: "commercial",
description: "Sales opportunity before promotion to a delivery project.",
// MANDATORY — no resource without a scoping path. Lint fails.
scoping: { kind: "TENANT", path: "tenants.some.tenantId" },
fields: {
id: { type: "id", class: "INTERNAL" },
name: { type: "text", class: "INTERNAL", filterable: true },
status: { type: "enum", class: "INTERNAL", domainValues: "LeadStatus" },
receivedOn: { type: "date", class: "INTERNAL", filterable: true },
value: { type: "money", class: "COMMERCIAL", aggregatable: true },
contactTel: { type: "text", class: "PERSONAL_DATA",
masking: "last4", basis: "legitimate interest — making contact" },
// Keys, tokens, raw documents: NOT here → they do not exist for the AI.
},
relations: {
interactions: { to: "Interaction", kind: "many", countable: true },
conversations: { to: "Conversation", kind: "many", countable: true },
customer: { to: "Organisation", kind: "one" },
},
// Authoritative calculations. The reasoner may use them, not re-derive them.
metrics: {
winRatio: { class: "COMMERCIAL", impl: canon.winRatio,
definition: "won / (won + lost), excl. withdrawn",
owner: "Commercial director", reviewOn: "2026-06-01" },
},
quality: { note: "Data before 2024 was migrated; statuses are approximate." },
limits: { default: 50, max: 500 },
indexes: ["tenants.tenantId", "status", "receivedOn"],
})
Five to seven classes are enough for virtually any organisation. More classes give false precision and unmanageable matrices; fewer force everything into the strictest regime.
| Class | Nature | Default regime |
|---|---|---|
| Internal | Names, references, statuses, dates | All authenticated internal roles |
| Operational | Execution, planning, progress, capacity | Roles with operational responsibility |
| Commercial | Prices, quotes, opportunities, customer value | Commercial and managerial roles |
| Financial | Amounts, margins, costs, exposure, reserves | Financial roles; scoped per legal entity |
| Personal data | Identifiable data on natural persons | Restricted, with masking and purpose limitation; legal basis recorded per field |
| Special category | Health, biometrics, criminal matters — GDPR Art. 9/10 | Explicit legal basis only; often excluded from AI processing altogether |
| Secret | Keys, tokens, credentials, raw documents | Nobody. Not in the register — does not exist |
ignored. One deliberate decision per migration on an exposed table; the rest of the schema stays out of range. Whitelist = security, free and schema-wide; CI check = completeness, targeted and cheap.The obvious objection: a serious data model has thousands of columns — the reference implementation has well over three thousand across 174 tables — and classifying them one by one is a hopeless task. Fair enough. That is why classification works with four mechanisms that bring the burden down from thousands of rules to dozens of decisions:
The security sits in the whitelist: not registered = unreachable, schema-wide and free. The build-pipeline check is only the drift alarm on top of that and applies solely to columns of already exposed tables (see the box in §2.3.A above). A first phase with five resources therefore takes five decisions, not three thousand.
Every resource carries one default class; only deviating fields get a rule of their own. An invoice table is financial by default, with the number as an internal exception and the raw document field as a secret one. In practice: one decision per table plus a handful of exceptions — for the reference implementation some sixty table decisions instead of 3,500 field rules.
The initial fill is generated — from naming conventions, types and the existing knowledge documents — and reviewed by a human. This is how the industry does it too: classification tooling proposes automatically, people confirm the doubtful cases. An afternoon of review instead of weeks of data entry.
Organisations with per-field documentation — data dictionaries, AI editability tables, data catalogues — add one attribute to an existing ritual, not a new process. The reference implementation already maintains such field tables for sixty modules; the class is one more column.
The register says what exists. The policy says who may do what with it. Deliberately separated: the register changes with the data model, the policy with the organisation — and they have different owners and different approval routes.
Policy is data, not code: evaluable, testable, diffable, and able to be simulated before it takes effect. The default is to refuse. Decisions are not binary but threefold.
role COMMERCIAL → read:PERSONAL_DATA → ALLOW, with purpose limitation. From that moment on it holds for every field of that class.
class + resource): still a handful of rules, no fieldwork. The same principle as security clearances: whoever may read SECRET may read all SECRET documents — nobody sets the clearance on every document again.// One policy rule — the full form. Rights are granted per (role, action,
// class), optionally refined per resource and per subject range.
type PolicyRule = {
role: Role // subject
action: "read" | "act"
class: SensitivityClass
resource?: ResourceName // refinement: class+resource (leads yes, employees no)
scope?: "own" | "team" | "organisation" // subject range within the injected scoping;
// default "organisation" — set "own"/"team" where
// portfolios are person-bound (§"Intent")
effect: "ALLOW" | "REFUSE"
obligations?: Obligation[]
validUntil?: Date // delegation/mandate: expiring grant when standing in
grantedBy?: UserId // who delegated — audit trail
}
type Decision = // outcome of policy evaluation per element
| { effect: "ALLOW" }
| { effect: "REFUSE"; reason: string; missingRight: string }
| { effect: "ALLOW"; obligations: Obligation[] }
type Obligation =
| { kind: "MASK"; pattern: "last4"|"domain"|"full" }
| { kind: "AGGREGATED_ONLY"; minGroupSize: number } // k-anonymity
| { kind: "MAX_ROWS"; n: number }
| { kind: "NO_EXPORT" } // showing allowed, taking away not
| { kind: "MODEL_RESTRICTION"; requires: ModelRequirement } // see below
| { kind: "PURPOSE_LIMITATION"; allowedPurposes: string[]
defaultPurpose?: string } // derived/explicit → trace (§"Purpose limitation")
| { kind: "FOUR_EYES"; approverRole: string } // for actions
Without obligations every sensitive field becomes a closed door and the system shrinks to trivial questions. With obligations it becomes nuanced: a commercial role sees amounts aggregated with a minimum group size of five — so that a group of one does not bypass the masking; an operational role sees contact details masked; an employee who asks a financial question gets no empty screen but a statement of which right is missing and from whom to obtain it.
MODEL_RESTRICTION obligation is the most underrated building block of this architecture. Because the policy knows which class of data an answer contains, and the routing layer knows which properties each provider has, you can express: "personal data may only be processed by a provider with a processing location in the EU, with no training on input and with zero retention; special categories only by a model that runs inside our own network."
The PURPOSE_LIMITATION obligation raises the practical question immediately: users rarely say why they need something. The answer is that the purpose is not a form the user fills in, but an interpretation the agent makes and records. Four rules make that both workable and defensible:
Every policy rule can carry a defaultPurpose — for a commercial role on contact details that is obviously making contact, the standard purpose of that function. Routine questions therefore run through without friction; the trace marks the purpose as derived or explicit, so an auditor sees what was interpretation and what the user literally said.
The agent never refuses on a guessed purpose. If the question is unambiguous, it derives the purpose; if it is not, it asks one short question back. A refusal follows only when the purpose is stated or evidently forbidden. A purpose limitation regime that interrupts routine questions gets worked around — and a control that is worked around is worse than none.
Someone looking for the owner of a lost item does not need thirty telephone numbers but a list of names and after that one number. As soon as the purpose is known, the agent can propose the least data-intensive answer. Data minimisation thus becomes not a blockage but a better answer — something that neither a blunt refusal nor dumping everything ever produces.
It blocks stated forbidden purposes and records every claim — no more than that. It will not stop a user who lies about their intention; what it does give is proof afterwards of what was claimed and what was supplied. The locks are called whitelist, scoping, obligations and authorisation; purpose limitation is the declaration-under-logging within them.
own / team / organisation. A small organisation chooses team reading (colleagues stand in for each other); a strict environment chooses own plus delegation with an expiry date: a manager temporarily grants read rights on the absent colleague's portfolio — explicit, expiring, logged. That is the mandate mechanism regulated sectors already know, expressed as a policy rule.The resource register describes what can be read; the action register describes what can be done: the complete list of actions an agent may ever propose or execute, each with a risk profile. In a read-only environment (autonomy ladder up to and including L2) this register stays empty; it is designed before the first action is granted, never after.
An action is therefore never "a query with a write flag" (principle 9). Every action is declared in advance with its risk profile:
type Action = {
name: string // e.g. "reminder.send", "reserve.adjust"
domain: string // links to the knowledge layer and resources
reversibility: "REVERSIBLE" // undoable with no trace to the outside
| "COMPENSABLE" // repairable with a counter-action (credit note)
| "IRREVERSIBLE" // sent mail, external notification, payment
scope: { maxAmount?: Money; maxCount?: number; perPeriod?: Duration }
conditions: Condition[] // e.g. "own portfolio only", "status = X"
minimumLadder: "L3" | "L4" | "L5" // lowest autonomy level at which this is ever allowed
approval?: { role: string; fourEyes?: boolean } // required at L4
notification: Role[] // who always gets to see it — the door that makes noise
rollbackPlan?: string // mandatory at L5: how the envelope emergency stop recovers
}
Three examples show how the risk profile determines the place on the ladder — not the other way round:
| Action | Reversibility | Typical granting | Why |
|---|---|---|---|
| Create an internal task / move an appointment | Reversible | L5 — within the envelope | Fully repairable internally; the envelope bounds the number per day; notification to the person concerned is enough. |
| Send a payment reminder | Irreversible (externally visible) | L4 — after approval | Touches a client relationship. Approval per item or per batch; scope bounds the number per run. |
| Change the case owner / adjust a reserve | Compensable, sensitive | L4 with four eyes | Exactly the action from the intent framework (§2.3.B): the thief has to go through a door that makes noise — notification to the original owner is mandatory, not optional. |
The user (role FINANCE) types: "Send a payment reminder to everyone more than 30 days past the due date."
Through the ordinary read layer the agent establishes who is involved: 13 outstanding invoices, due date > 30 days past. This part is fully open — no register needed, the question could just as easily have been phrased quite differently.
The agent finds invoice.reminder in the action register and tests every candidate against the declared conditions. One invoice drops out: that client already received a reminder four days ago, and the condition requires a cooldown of seven days. That leaves 12 — within scope (max. 15 per run). The agent reports the excluded client explicitly, with the reason.
Nothing is sent. The agent puts forward a proposal: the list of 12, per client the outstanding amount, days past the due date and the chosen mail template. The user has role FINANCE — exactly the approver role from the register — and approves the batch with one click (or takes clients out of it).
Execution runs through the application's existing mail path — no second write route. In the trace: the query, the condition test (including the excluded client), the proposal, who approved, and the result per mail. The notification from the register goes to the role FINANCE.
Note where the intelligence sat: in translating "everyone too far past the date" into the right selection, in applying the cooldown, and in drafting the proposal. The register only set the guardrails: which action exists, its conditions, and the fact that a human sits in between. Had the user had role COMMERCIAL, step 3 would have ended in a recommendation: "12 candidates found — approval requires role FINANCE."
The fourth component of the governance layer is short but a matter of principle: which model may do what is a governance decision, not an implementation choice. The mechanics of model roles and adapters are in §2.5.B; here is what gets decided about it, and by whom.
The routing table is configuration — per organisational unit, changeable without a deploy, with version history:
{
"routing": {
"LIGHT": { "provider": "…", "model": "…", "maxTokens": 1024 },
"WORKER": { "provider": "…", "model": "…", "maxTokens": 4096 },
"FRONTIER": { "provider": "…", "model": "…", "maxTokens": 8192 },
"CRITIC": { "provider": "…other than WORKER…" } // diversity is the value
},
"residency": { // tied to MODEL_RESTRICTION (§2.3.B)
"PERSONAL_DATA": { "processingLocation": "EU", "trainingOnInput": false, "retentionDays": 0 },
"SPECIAL_CATEGORY": { "processingLocation": "ON_PREM" }
},
"escalation": { "onComplexity": {…}, "afterGatewayErrors": 2, "maxEscalations": 1 },
"budget": { "perConversationEur": 0.50, "perDayEur": 25, "onExceeding": "REFUSE" }
}
Four decisions live here, each with an owner (§3.4): the role-to-model assignment (AI platform team — this is the switch that makes a model swap a setting, principle 10); the residency requirements per data class (privacy and security — the gateway enforces them through the obligation MODEL_RESTRICTION: if an answer touches personal data, the permitted set of providers narrows automatically); the escalation rules (when a heavier model is justified — two refused queries are cheaper to escalate than five failed rounds); and the budgets with their behaviour on exceeding them — refuse, downgrade to a cheaper model, or let through with a notification; the choice belongs to the budget owner, not to the developer (§3.2).
The gateway is the only passage between reasoners and sources (principle 1) and the enforcement point for everything the governance layer declares. It contains no policy itself — it executes it. Every request, however small, passes here; there is no second path.
Three parts, in reading order:
Four API families (knowledge, catalogue, query, action) with six calls in the read-only environment, and the nine-step pipeline that runs behind the query API — including the mapping of which call goes through which steps, and the dataflow diagram. §2.4.A
The declarative language in which the agent asks (no SQL, no text path to storage), what is deliberately inexpressible, and the three traps the compiler must be tested against. §2.4.B
Every refusal is a structured counter-proposal with executable suggestions — the mechanism that makes the agent self-correcting. §2.4.C
Six capabilities instead of dozens of questions. That is not less intelligence but a different placement of it: a tool that is a question is finite; a tool that is a capability is not.
| API family | Call | Does | Returns | When |
|---|---|---|---|---|
| Knowledge | kennis.register | Tier 0 — which domains exist | Domain register, a few thousand tokens | Always, cached |
| kennis.lees | Tier 1, 2 or 3 of a domain, or a single section | Meaning, rules or precedent | Once the domain is known | |
| Catalogue | catalogus.beschrijf | Register cross-section for the named resources | Fields, classes, relations, metrics — annotated with access | Before composing a query |
| Query | bevraag.plan | Dry run: validate, authorise, estimate — without data | Admissibility, estimated volume, warnings | When size or rights are in doubt |
| bevraag.voer_uit | Execute the query in read mode under the full regime — this is not an action | Rows plus provenance envelope | The actual data access | |
| zoek | Helper call: free text → entity identification. Technically a predefined, bounded query | At most ten candidates with reference | When the question names an entity | |
| Action | handel.stel_voor · keur_goed · voer_uit · draai_terug | Do not exist in the read-only environment (ladder up to and including L2). They appear only once L3+ is granted, driven by the action register (§2.3.C) | From autonomy level L3 | |
The nine steps below are the full pipeline of the query API. The other calls are lighter and run through a shortened form — but never zero: a knowledge call is authorised and recorded too (knowledge is data, §2.2).
| Call | Steps run | Notes |
|---|---|---|
| kennis.register · kennis.lees | 1 · 2 · 9 | Bind (does the domain/the section exist?), authorise (may this role read this knowledge doc?), record. No estimate — docs have a fixed, known size. |
| catalogus.beschrijf | 1 · 2 · 9 | The per-field access annotation in the answer is step 2, carried out in advance for the whole cross-section. |
| bevraag.plan | 1 – 5 | Dry run: stops after admission, before execution. No data, but the verdict and the estimate. |
| bevraag.voer_uit | 1 – 9 | The full pipeline. |
| zoek | 1 · 2 · 6 · 9 | Fixed, bounded query (max. 10 candidates, INTERNAL fields only) — estimate and admission are redundant because the shape is fixed. |
Every bevraag.voer_uit runs through exactly these steps. No exceptions, no internal route that skips three of them. The steps numbered in red are the enforcement points — class 3.
The reasoner does not write SQL. It writes a declarative specification that the gateway compiles. That relocates expressive power instead of curtailing it: everything a business question needs is expressible, everything dangerous is not.
type Query = {
from: ResourceName // from the register
select?: string[] // fields, also via 1-to-1 paths
measure?: Measure[] // aggregations over relations or fields
where?: Filter // tree: and/or/not + field predicates
groupBy?: string[]
sort?: { field: string; direction: "asc"|"desc" }[]
limit?: number // bounded by the register maximum
purpose?: string // purpose binding, mandatory for personal data
}
type Measure =
| { as: string; count: RelationPath; where?: Filter } // count over relation
| { as: string; sum: FieldPath; where?: Filter } // if aggregatable
| { as: string; avg|min|max: FieldPath }
| { as: string; metric: MetricName } // CERTIFIED
Only declared relation paths, at most three steps deep. No cross products, no joining on fields that are not a relation. This rules out both performance derailments and unintended data combinations — the latter is a privacy risk that is rarely named.
There is no field in which text reaches the storage. The compiler builds from validated identifiers and parameterised values. Injection is not a risk that is managed but a construction that does not exist — the answer to the question of how you design an API so that dangerous queries cannot arise on the spot.
Fields that form the basis of a certified metric are set to aggregatable: false. A sum over them is refused with a reference to the metric. That way the reasoner cannot invent its own definition of margin or exposure.
Tenant, entity and jurisdiction keys are not filterable and not selectable. They exist solely as an injection. The reasoner cannot ask for them and cannot filter on them — and therefore cannot discover what it is not allowed to see.
Where a naive implementation breaks down. All three are real and all three belong in the compiler's test set, not in the user's attentiveness.
Count two relations in the same query with ordinary joins and the rows multiply: an entity with ten interactions and four messages gives forty rows and both counts come out wrong. Rule: every count or sum over a relation becomes a correlated subquery, never a join in the main query.
"Sort by number of interactions" forces full computation before the limit can cut. On two thousand rows that is fine, on two million it is not. Rule: the register declares usable indexes; sorting on a derived value is allowed up to an estimated base cardinality, above which the estimate refuses with the suggestion to filter first.
Scoping the main entity is not enough. If the reasoner counts over a relation, that subquery must be scoped as well — otherwise records outside the scope are counted along. A leak that looks like an ordinary number, and therefore more dangerous than a visible error. Rule: injection runs across the full relation path; a mandatory test per resource that a request from A touches no record of B.
The component that separates a rigid system from a learning one. A refusal is not a dead end but a counter-proposal — and that makes the reasoner self-correcting without anyone having to teach it anything.
{
"allowed": false,
"code": "VOLUME_EXCEEDED",
"estimated": { "rows": 2014, "tokens": 41200 },
"threshold": { "rows": 500, "tokens": 8000 },
"suggestions": [
{ "kind": "LIMIT",
"explanation": "You asked for 'the most' — sort descending and take the top 25.",
"patch": { "limit": 25, "sort": [{…}] } },
{ "kind": "FILTER",
"explanation": "Restrict to the current year (412 records).",
"patch": { "where": { "receivedOn": {"year": 2026} } } },
{ "kind": "AGGREGATE",
"explanation": "Or group by status (7 rows).",
"patch": { "groupBy": ["status"] } }
]
}
{
"allowed": false,
"code": "RIGHT_MISSING",
"refused": [
{ "element": "Policy.premiumAnnual",
"class": "FINANCIAL",
"missing": "read:FINANCIAL",
"requesterRole": "CLAIMS_HANDLER" }
],
"permitted": ["Policy.number", "Policy.status",
"Policy.coverageType", "Policy.startDate"],
"message": "Premium amounts fall under FINANCIAL. Counts, " +
"statuses and coverages are available."
}
The requester can now do two things: ask again without the amount — counts are often already a usable answer — or explain to the user which right is missing. Both are better than an empty table or a cryptic error.
The reasoning layer is the replaceable layer: this is where the models and the agents live, and this is where deliberately not a single safety property lives. The layer knows no storage, no rights and no scoping — everything it wants, it asks for through the gateway. That makes a model swap a configuration change (principle 10) and lets the value grow with every generation of better models, without the risk growing with it (§1.3).
The five blocks from the band are each worked out in a section of their own: orchestration (§2.5.A — who does what), provider adapters (§2.5.B — how models stay interchangeable), the agent loop (§2.5.C — how one agent works, round by round), the answer contract (§2.5.D — the fixed form of every answer) and the autonomy ladder (§2.5.E — the governed axis along which this layer grows with the models; the answer to "does this still work three years from now?").
One question is rarely answered by one agent. The orchestration divides the work across four fixed roles — and those roles are declarations in the configuration, not classes in code: adding or adjusting a role is configuration plus a prompt.
| Role | Task | May call these | Thinks with | Limits |
|---|---|---|---|---|
| Router | Classifies the question (complexity), splits it into sub-questions, picks the domains from the knowledge register | knowledge.register | LIGHT | 1 round |
| Analyst | Answers one sub-question: retrieve knowledge, read the catalogue, compose queries, interpret the result | all six read calls | WORKER | 8 rounds, 6 queries |
| Synthesis | Merges the analysts' findings into one answer in the answer contract (§2.5.D) | — (sees findings only) | WORKER / FRONTIER | 1 round |
| Critic | Re-checks the headline figure with an independently composed query; reports deviations | query.plan · execute | CRITIC | 2 rounds |
The router determines the shape of the graph: for a simple question one analyst handles everything, without synthesis; for a compound question (one domain, several measures) the synthesis is added; for a cross-domain question several analysts run in parallel — each with only the knowledge documents and the tool subset of their own domain — and the synthesis weighs their findings. The critic runs only when the answer carries a figure that can steer a decision.
No agent ever talks to a vendor directly. Everything runs through one neutral contract; per vendor an adapter translates that contract into the vendor's own format — and vendor-specific shape lives nowhere else.
// The only interface orchestration and agents know about.
interface ModelProvider {
name: string
properties: {
structuredCall: boolean // native function calling?
streaming: boolean
contextCache: boolean
contextWindow: number
// Decisive for MODEL_RESTRICTION from the policy:
processingLocation: "EU" | "US" | "ON_PREM" | "OTHER"
trainingOnInput: boolean
retentionDays: number
certifications: string[] // ISO 27001, SOC 2, …
}
generate(r: Request): Promise<Answer>
}
One per vendor, plus one OpenAI-compatible adapter that covers most self-hosted and local servers in one go. Translation from the neutral call schema into the vendor's format happens inside the adapter and nowhere else.
If a model does not support structured calls, the adapter falls back to a JSON mode with schema validation and a retry. Orchestration notices no difference; the property flags drive that.
A provider outage is a routing event, not an outage of the service. Concentration risk with a single vendor is an explicit supervisory concern for regulated institutions — here it is a configuration rule.
Agent code never names a model. It asks for a role; the routing table in the governance layer (§2.3.D) determines what that role means today — per organisational unit, changeable without a deploy.
| Role | For what | Decisive property | Share of traffic |
|---|---|---|---|
| Light | Classifying, routing, rephrasing | Latency and price | ± 40% |
| Worker | Composing queries, interpreting results, partial answers | Reliability of structured calls — most important here | ± 45% |
| Frontier | Synthesis across domains, weighing contradictions, forming judgement | Depth of reasoning; cost weighs less because it is rare | ± 10% |
| Critic | Independent check of the headline figure | Preferably a different vendor — diversity is the value here | ± 5% |
The critic is the translation of the challenger model from classic model risk management: preferably a different vendor than the worker, because diversity is the value here. A difference between worker and critic is not an error but a signal — and it is logged, not papered over.
Every role from §2.5.A runs on the same engine: a loop that lets the model think, executes its gateway calls, returns the results and lets it think again — until there is an answer or a limit is reached.
The synthesis does not write free text that then has to be parsed: through a forced structure (tool choice) it is obliged to fill in this envelope. One envelope, several renderings — and because of that the figure in the export cannot diverge from the figure on the screen.
type AnswerEnvelope = {
answer: string // markdown, short, in the user's language
keyValue?: { label: string; value: number|string; unit?: string
tone?: "neutral"|"positive"|"warning"|"critical" }
table?: { columns: Column[]; rows: Row[] } // typed: money/date/text/number
chart?: { kind: "bar"|"line"|"donut"; … }
assumptions: string[] // MANDATORY — "Period: 2026 (assumed)",
// quality notes from the register
sources: Source[] // per figure: query hash, spec, row count,
// truncated flag — the audit trail (§2.6)
followUps: string[] // max 3, clickable
}
Three rules make this contract more than a format. One: the renderers are deterministic — text, KPI tile, table, PDF and spreadsheet are all built from the same envelope, and the model never writes the file itself (a model that retypes a report will sooner or later retype a figure wrongly). Two: assumptions is mandatory and may not be empty when something was in fact assumed — a tacit assumption in a confidently phrased answer is exactly what makes a chat more dangerous than a dashboard. Three: sources carries the full provenance, so that "where does this come from?" is one click and every figure remains countable back to the source row (principle 8).
How a system grows with capability without a rebuild. The same gateway, the same policy engine; what changes is which actions are granted — per role, per domain, per environment.
Without this layer the system is an oracle. With this layer it is a business asset that can account for itself to an auditor, a regulator and a data subject requesting access.
Per conversation a tree: every round with model role, provider, prompt hash, tokens, costs, duration — and per gateway call the specification, the policy decisions, the estimate, the row count and the query hash. Retention period and redaction are themselves policy: traces contain data, so they fall under the same regime.
Running a trace again against a different model or a newer register version and showing the differences. This turns a model switch into a measurement instead of a gamble: run the last thousand conversations again, compare outcomes and costs, then decide. It is also the regression mechanism for changes in the semantic layer.
Golden questions in the build pipeline, in three kinds: correctness (does the figure hold against an independently calculated truth), safety (a request on behalf of A touches no record of B; a restricted role gets no protected class), frugality (do the number of rounds and the cost stay within the limit).
For a regulated institution this is the section that decides whether the system may go into production. The mapping is deliberately onto components, not onto promises.
| Framework | Core obligation | Where the architecture carries it |
|---|---|---|
| EU AI Act | Risk classification; logging of events across the lifetime; human oversight; transparency towards users | The trace is the event log — with input, decisions and outcome per step. The autonomy ladder turns human oversight into a granting decision per action instead of an intention. Classification of the use follows from the action register: advising is a different risk profile from deciding. |
| GDPR | Purpose limitation, data minimisation, lawful basis, rights of data subjects, no solely automated decisions with legal effect | Lawful basis per field in the register; purpose limitation as a mandatory parameter and check step; minimisation enforced by projection and thresholds; the trace answers a subject access request; Article 22 is carried by the fact that decision-making actions sit at L4 or lower. |
| DORA | Management of third-party ICT risk; concentration risk; failover and exit strategy | Provider abstraction turns failover into a routing rule. Several providers side by side lower concentration risk structurally; the exit strategy is demonstrable because replaying shows that the service gives the same outcomes on another supplier. |
| BCBS 239 principles | Accuracy, completeness and traceability of risk data aggregation | Certified metrics with an owner and a review date; provenance down to the source row; register version recorded with every result, so that a figure from last quarter stays reproducible. |
| Solvency II / EIOPA | Data quality for reporting; management of model risk; board accountability | Quality notes per resource that end up automatically in the assumptions of an answer; critic agent as challenger; evaluation set as continuous validation; the board sees one catalogue with owners. |
| Data sovereignty | Restrictions on processing location per data category | MODEL_BEPERKING links data class to provider properties. Personal data routes automatically to EU processing; special categories to own infrastructure — enforced, not agreed. |
Who asks what, what it costs, and what it returns. Without these figures every AI programme becomes a discussion based on opinions after a year.
The steering itself is policy, not code: budget ceilings per conversation, per user per day and per unit per month, with configurable behaviour on overrun — refuse, downgrade to a cheaper model, or let through with a notification. All three are defensible in different contexts; the choice belongs to the owner of the budget, not to the developer.
The test of generalisability. On the left a mid-sized multi-tenant ERP environment, on the right an international insurer. The same five layers, the same nine steps, the same ladder — different filling-in.
| Architectural concept | ERP — reference implementation | International insurer |
|---|---|---|
| Scoping axis 1 | Tenant (operating company within a group) | Entity per country / line of business, with different regulators |
| Scoping axis 2 | Legal entity for financial data | Jurisdiction plus distribution channel (own network, broker, binding authority) |
| Core resources | Opportunity, project, invoice, work order, schedule | Policy, cover, claim, premium, reserve, reinsurance cession, intermediary |
| Certified metrics | Revenue, subcontractor cost, margin, outstanding balance | Loss ratio, combined ratio, IBNR reserve, technical result, customer value |
| Special class | Contact details, personnel documents | Medical files in bodily injury claims, criminal data in fraud investigations |
| Tier-3 precedent | Earlier costing decisions, non-standard agreements per client | Earlier claim settlements in borderline cases, underwriting decisions, interpretations of policy conditions |
| Typical L2 question | "Which project had the lowest margin, and was that down to cost or price?" | "Which intermediaries deteriorated in motor loss ratio in 2024, and is that in frequency or in average claim cost?" |
| Typical L4 action | Sending a reminder; moving a schedule | Adjusting a reserve within mandate; settling a routine claim below threshold |
| Heaviest requirement | No cross-traffic between tenants; every financial figure countable back to source | Data sovereignty per jurisdiction; traceability for supervision; no solely automated decisions towards policyholders |
| Difference in scale | Tens of users, millions of rows | Thousands of users, billions of rows, dozens of source systems |
Architecture without ownership dilutes within two quarters. This is the division that keeps the layers maintained.
| Artefact | Owner | Approval | Cadence |
|---|---|---|---|
| Semantic register — fields, relations | Domain data owner | Code review + build pipeline check | On every schema change |
| Sensitivity classes and lawful bases | Privacy and information security | Four eyes, recorded | On new fields; annual review |
| Certified metrics | Functional owner (Finance, Actuarial, Commercial) | Owner + risk management | On definition change; review date mandatory |
| Policy — role × class × action | Information security | Four eyes + simulation before entry into force | On organisational change |
| Knowledge tiers 1–3 | Domain experts | Subject-matter review | Continuous; tier 3 grows with every borderline case handled |
| Model routing and budgets | AI platform team | Owner + procurement for a new supplier | Quarterly or on market change |
| Evaluation set | AI platform together with domain experts | Build pipeline blocks on regression | Grows with every error that is found |
| Autonomy grants (L3+) | Business owner of the process | Risk management; substantiated with trace evidence | Per process, with review after entry into force |
This architecture is not an invention of its own that the reader has to accept on authority. It is the vendor-neutral description of the pattern that the large platforms and the semantic-layer market converged on independently of each other in 2025–2026. That is a strength: the pattern is validated; what this document adds is the coherence and the decision framework.
| Layer (this document) | Microsoft | AWS / Google | Databricks / Snowflake | Independent players |
|---|---|---|---|---|
| Knowledge layer | Foundry knowledge sources, Copilot grounding | Bedrock Knowledge Bases / Vertex AI Search | — | Retrieval platforms; the tier structure with precedent is rare and mostly custom work |
| Governance layer | Purview (classification, labels), Entra Agent ID | Bedrock Guardrails policies / Vertex governance | Unity Catalog / Horizon | Immuta, Collibra; OPA and Cedar for policy-as-data |
| Gateway | AI Agent Landing Zone, Foundry Agent Service | Bedrock Agents + Guardrails / Agent Builder | Unity AI Gateway / Cortex Analyst semantic models | Cube, AtScale (semantic layer with compile-time permissions); Kong, Portkey, LiteLLM (model traffic) |
| Reasoning layer | Foundry model catalogue, multi-model routing | Bedrock model choice / Vertex Model Garden | Model serving endpoints | Portkey, LiteLLM, OpenRouter — routing, failover, cost measurement |
| Evidence layer | Purview audit, Foundry tracing | CloudWatch/Bedrock invocation logs / Vertex tracing | Lakehouse Monitoring | Langfuse, Arize, Braintrust — traces, evals, cost attribution |
Two observations that form the decision framework:
The established data gateways and semantic layers are built for analytical platforms — warehouse and lakehouse. For an organisation whose data already sits there, buying is the obvious route and this document becomes the evaluation framework. For an operational system on a transactional database — such as the reference implementation — there is no fitting product off the shelf, and a thin in-house gateway on the existing authorisation model is the shorter and safer path. Large organisations usually do both: buy for the analytical landscape, build for the operational cores.
No platform can classify the customer's data, define the metrics or capture the domain knowledge. A classification tool recognises a telephone number, but not that an invoiced receivable does not count as revenue. The semantic register, the certified metrics and the knowledge tiers are custom work in every set-up — so that is not overhead this architecture adds, but the core that has to be done in any case. The architecture choice only determines whether that work happens once, in one place, with one owner — or scattered and implicit in every integration again.
The five layers as infrastructure: which zones, which servers, which network — and per request type the path a request travels across those servers. Click a component for what, how and why.
Click a component in the diagram — or pick one below.
The same servers, five kinds of request. Every arrow is one step; every step has a measurement point in obs-01, and the "log" step is the legal burden of proof. Red is the only route outside; blue never leaves your own walls.
An explicit test: if the reasoner is considerably more capable than a human expert three years from now, which parts of this design hold and which have to evolve along with it?
| Component | Outcome | Why |
|---|---|---|
| Scoping injection | Unchanged | Class 3. Works identically regardless of who asks — that is the definition of capability-independent. |
| Policy evaluation | Unchanged | The same. It does not become weaker because the requester is smarter. |
| Admission control | Thresholds rise | The mechanism stays; a more capable model deserves a wider window because it handles more data better. A setting, not a rebuild. |
| Query language | Enriched | Stronger models compose more complex queries. Window functions, cohort analysis and time series are added — as an extension of the language, not as a detour around it. |
| Number of agent roles | Decreases | Router, analyst and synthesis exist because current models benefit from context separation. A more capable model does that itself. The graph configuration shrinks; the gateway underneath does not change. |
| Knowledge tiers | More valuable | A stronger reasoner gets more out of precedent, not less — it recognises more sharply which earlier case applies. Tier 3 becomes more important as the reasoner gets better. |
| Autonomy level | Rises deliberately | From L2 to L4, and L5 for some processes. A granting decision per role and domain, supported by trace evidence from the level below. |
| Verification by people | Shifts fundamentally | Reading through the reasoning loses its value. Evidence chains and sampling of outcomes take over. This is the only change the architecture has to carry from the outset — it cannot be retrofitted. |
| The prompt as control | Stops working | Class 1 degrades. Anyone who built safety on it will have to rebuild. Anyone who used it only for quality notices nothing. |
What this architecture explicitly rejects, and why. The first point is a correction to the first design — the mistake is instructive enough to show.
| Pattern | Why it looks attractive | Why it fails |
|---|---|---|
| Tool sprawl — one tool per type of question | Every tool is safe on its own and easy to understand | The question range is bounded by the designer's imagination; the catalogue grows until it no longer fits in the context itself; every new question requires a release. This was the mistake in the first version of this design. |
| The prompt as policy | Fast, flexible, no infrastructure needed | Class 1: not enforceable, not provable, not exhaustively testable — and it degrades precisely when the models get better. |
| Direct SQL generation against production | Maximum flexibility, quick to demonstrate | Scoping not enforceable, definitions re-derived instead of used, unbounded results, injection surface, and nothing is reproducible. |
| Vector retrieval as the default answer | One pattern for everything; mature tooling | Excellent for unstructured text, unsuitable for precise aggregation over structured data. Approximate search yields approximate figures — unacceptable for financial and actuarial questions. Both alongside each other, each for what it belongs to. |
| Putting everything in the context | Large context windows appear to solve the problem | Costs scale linearly with noise, precision drops with irrelevant content, and the permissions question does not disappear — it only becomes invisible. |
| Human oversight as a tick-box | Ostensibly satisfies the requirement | An approver who sees ten proposals a minute approves. Oversight only works with bounded volume, a real ability to refuse and visible evidence — otherwise it is false assurance with an audit trail. |
| Vendor-specific coupling | The fastest path to a working demo | Formats, call conventions and quirks leak into the business logic. Switching becomes a project instead of a setting — and regulators now ask about the fallback. |
What remains difficult after all this. A reference architecture that names only the solved problems is a sales document.
With an open query language, a reasoner can combine two sums and give the result a name that clashes with the authoritative definition. Four layers of defence — certified metrics, non-aggregatable base fields, self-labelling of answers as authoritative or self-composed, and a critic with an independent query — reduce it but do not rule it out. That is why verifiability is not an extra, but the condition under which financial answers may be presented.
The build-pipeline check prevents it from falling behind, but shifts the burden onto every schema proposal. In a large organisation with dozens of domain teams that is federated governance with all the coordination that comes with it. It is deliberate — it is the price of principle 3 — but it has to be budgeted for, not waved away.
One authoritative metric means that someone's existing reporting is proved wrong. That is a governance question with owners and interests, and it is usually the slowest part of the track. Technology can make it visible; the organisation has to decide for itself.
A perfectly traceable answer to a badly posed question remains misleading, and a correct figure over a period that is not representative is still a wrong insight. Hence the mandatory assumptions in every answer and the quality notes per resource — but the final judgement of whether the question was the right one stays human. That is not a shortcoming of this design; it is the limit of what a system can know about itself.
Window functions over irregular time windows, recursive hierarchies, statistical procedures. Two honest ways out: extend the language when a pattern recurs, or a tightly fenced escape with its own permissions, human confirmation and mandatory provenance. Pretending that those five per cent do not exist leads to shadow solutions outside the gateway — and that is worse than a governed exception.
The order is deliberate: governance before intelligence. The first two phases produce no visible chat — and without those two you build a system whose safety you have to prove afterwards, which does not work.
| Phase | What | Content | Done when |
|---|---|---|---|
| 0 | Semantics and policy | Register with classification and scoping paths for five core resources; policy engine with obligations; build-pipeline check on unclassified fields | Security tests green: no cross-traffic between scopes; a restricted role does not get a protected class |
| 1 | Gateway | Query language, compiler with correlated subqueries, scoping across relationship paths, estimation, admission, read-only role, six calls. No AI yet. | An unforeseen analytical question runs through the API from a test script |
| 2 | Reasoning layer | Provider interface with one adapter, agent loop, router/analyst/synthesis, model roles from configuration, full trace | Questions nobody thought of in advance are answered end to end, with provenance |
| 3 | Interface and delivery | Conversational interface with visible steps, provenance expandable, click-through to source rows, export | Usable without the intervention of a developer |
| 4 | Governance made visible | Admin screens for permissions, catalogue and conversations; second provider adapter; replay; evaluation set; critic | Switching models is a setting with a measurement; permissions can be simulated before they take effect |
| 5 | Broadening and autonomy | Extend the register per domain; build up tier-3 precedent; action register; L3 and then L4 for selected processes | Autonomy is granted on the basis of evidence from the trace of the level below |
"Which opportunities have the most interactions and the most e-mail communication?" — a question for which nothing has been prepared. This is the test the whole architecture has to survive.
Classifies with the domain register in the cached system prompt: a composite question, one domain with a touchpoint. One analyst, synthesis, no critic — there is no financial figure at stake.
Retrieves tier 1 of the commercial domain. Learns the status flows, and that interactions are stored polymorphically with a type field — so that it will not later count interactions of other entity kinds by accident. That is exactly the sort of domain knowledge that makes the difference between a figure that is right and a figure that merely looks plausible.
Asks the register for Opportunity and sees fields, classes, access annotations and relations. Notices that the relation to conversations points to a resource that itself has messages, requests that one in the same round as well, and thereby knows the two-step path.
Assembles its first specification and lets it run dry. The gateway authorises everything, injects the scoping, estimates 2,014 rows ≈ 41k tokens and refuses with three refinement suggestions. No data — but direction.
Takes over the suggestion and refines further on its own: inbound messages only, because communication from the customer is a better measure of engagement than post sent out by the company itself. That judgement is precisely the part you cannot capture in a tool — and the reason the question range has to be open.
{ "from": "Opportunity",
"select": ["id", "name", "status", "customer.name"],
"measure": [
{ "as":"interactions", "count":"interactions" },
{ "as":"inboundMail","count":"conversations.messages",
"where":{ "direction":"IN" } },
{ "as":"lastContact","max":"interactions.date" } ],
"sort": [{"field":"interactions","direction":"desc"},
{"field":"inboundMail","direction":"desc"}],
"limit": 25 }
The compiler produces no joins but correlated subqueries — otherwise pitfall 1 from §2.4.B spoils both counts — and injects the scoping the agent did not ask for and cannot leave out:
SELECT o.id, o.name, o.status, k.name AS customer_name,
(SELECT count(*) FROM interactions i
WHERE i.opp_id = o.id AND i.entity_type = 'opportunity') AS interactions,
(SELECT count(*) FROM messages b
JOIN conversations c ON c.id = b.conversation_id
WHERE c.opp_id = o.id AND b.direction = 'IN') AS inbound_mail,
(SELECT max(i.date) FROM interactions i WHERE i.opp_id = o.id) AS last_contact
FROM opportunities o
LEFT JOIN organisations k ON k.id = o.customer_id
-- scoping injection: not requested, not removable
WHERE EXISTS (SELECT 1 FROM opp_tenants t
WHERE t.opp_id = o.id AND t.tenant_id = ANY($1))
ORDER BY interactions DESC, inbound_mail DESC
LIMIT 25;
Interpretation, the table of 25, the assumptions ("engagement measured as inbound messages plus recorded interactions; all years"), the provenance (one query, hash, 25 of 2,014 after sorting) and two follow-up questions.
"Which intermediaries deteriorated most sharply in loss ratio on motor insurance in 2024, and does that deterioration sit in frequency or in average claim cost?"
The same five layers, three differences that carry the sector-specific requirements:
| Aspect | Detail |
|---|---|
| Authoritative metric | Loss ratio is not assembled by the reasoner. It is a certified metric with an owner in Actuarial, with the fixed treatment of IBNR, claims handling costs and reinsurance recoveries. The base fields are set to non-aggregatable, so a self-invented variant is refused with a reference to the metric. The breakdown into frequency and average cost are two further certified metrics — exactly the decomposition the question asks for. |
| Scoping | Two axes at once: the entity that carries the risk (jurisdiction and regulator) and the distribution channel. A user at the Belgian entity sees no French portfolio, not even inside a total — and the aggregate does not betray that difference, because the injection sits in the subquery. |
| Model restriction | The answer contains no personal data — it is about intermediaries and portfolios — so the full set of providers is permitted. Were the same analysis to descend to individual claim files with injury data, the policy automatically narrows the permitted models to on-premise processing, without anyone having to think about it. |
| Tier 3 | When interpreting outliers the analyst consults earlier underwriting decisions and portfolio remediations: has this deterioration been observed before and what measure followed? That is what makes the difference between a correct figure and usable advice. |
| Autonomy | Stays at L2 — analyse and report. Proposing a portfolio measure is L3 and requires an explicit grant; actually changing a commission or a mandate is L4 with four-eyes approval. The architecture carries all three; the organisation decides where the line sits today. |