Beslisrecords, drie van tien. Een architectuurbeslissing per stuk, uit een beheerst AI-agentplatform dat ik als prototype ontwierp en bouwde voor de Nederlandse lokale overheid.
De situatie
Een platform dat alleen de agents draait die het eigen team heeft geschreven, is geen platform. Het hele punt was dat een gemeente, of een leverancier die er meerdere bedient, een component kon toevoegen: een retriever over de eigen documentopslag, een toolserver voor het zaaksysteem, een gespecialiseerde agent. Extensie is de waarde.
Extensie is ook het gat. Elke component die je binnenlaat is code die jij niet hebt geschreven en die draait binnen een grens waar jij verantwoordelijk voor bent. Het gebruikelijke antwoord is toetsing: de component reviewen, ondertekenen, toelaten. Dat deed ik ook. Maar toetsing verlaagt de kans op een slechte component. Het maakt de garanties van het platform niet onafhankelijk van het gedrag van de component, en onafhankelijkheid is wat een garantie betekent.
Ik ontdekte aan mijn eigen ontwerp hoe makkelijk dit misgaat. Het autorisatiefilter voor retrieval, het ding dat voorkomt dat een retriever documenten teruggeeft die de huidige principal niet mag zien, stond in een vroege versie van het componentmodel vermeld als iets dat een retriever met een eigen implementatie mocht vervangen. Dat is redelijk als je de retriever vertrouwt. Het is een bypass als je dat niet doet.
De beslissing
Een vaste set controls leeft in de kernel en is buiten bereik van elke extensie. Een extensie mag controls toevoegen. Ze mag er nooit een van deze vervangen, uitschakelen of omhullen.
De set: identiteit, beleidsbeslissing en afdwinging, goedkeuring, het bewijsregister, geheimenautoriteit, ondertekening en vertrouwen, isolatie, noodintrekking, en het run- en correlatiemodel. Die negen zijn het platform. Al het andere is een component.
Het retrieval-filter werd het uitgewerkte voorbeeld van wat “buiten bereik” in de praktijk betekent. De fix bestond uit drie regels. De kernel past het autorisatiefilter toe nadat een component heeft gedraaid, op de teruggegeven items, niet ervoor. Een component mag de resultaatset versmallen, nooit verbreden; als een retriever iets teruggeeft dat het filter van de kernel zou hebben uitgesloten, sluit de kernel het alsnog uit. En items zonder autoriteitsmetadata worden uitgesloten. Een document dat niet kan zeggen wie het mag lezen, wordt aan niemand teruggegeven.
Die derde regel is degene die bijt. Hij betekent dat een retriever die vergeet autoriteitsmetadata mee te geven niets teruggeeft, wat tijdens de ontwikkeling een luide fout is en precies de bedoeling.
Wat ik afwees, en waarom
Vertrouwen op getoetste componenten. Review en ondertekening zitten in het platform en ik zou ze niet weghalen. Maar een toetsingsproces is een kansverlager. Een reviewer mist dingen, een component wordt na review bijgewerkt, een ondertekeningssleutel lekt. De controls in de vaste set moeten standhouden ook als een component actief kwaadaardig is, en toetsing kan dat niet beloven. Niet te omzeilen is een structurele eigenschap, geen procesuitkomst.
Alleen een pre-filter. Het verleidelijke ontwerp is om te beperken wat de retriever gevraagd wordt: geef hem de autoriteitsscope van de principal mee en laat hem alleen daarbinnen zoeken. Dat is de moeite waard voor efficiëntie, en het prototype doet het. Maar een pre-filter beperkt de vraag, niet het antwoord. Een retriever die de scope negeert, of een bug heeft, of documenten onder de verkeerde autoriteit indexeert, geeft nog steeds terug wat hij teruggeeft. Alleen een post-filter op de daadwerkelijke items sluit dat af.
Chesterton zou je laten vragen waarom het hek er staat voordat je het weghaalt. Deze ring is de verzameling hekken waarop het antwoord op het hek zelf staat, en de poort heeft geen scharnieren.
Wat het kost
Autoriteit opnieuw controleren op elk teruggegeven item, elke keer. Dat is een tweede gang over elk retrieval-resultaat, met een lookup tegen de autoriteitsmetadata per item, voordat iets het model bereikt. In het prototype was de overhead klein omdat het corpus klein was. Op gemeentelijke schaal is het een echte latentie- en rekenkost waar je voor moet ontwerpen in plaats van te hopen dat het meevalt.
Het kost ook een specifiek soort test: een opzettelijk kwaadaardige retriever. Om te bewijzen dat het post-filter standhoudt, moet je een component schrijven die documenten probeert terug te geven die het niet mag, en die tegen de kernel draaien. Ik heb er een gebouwd. Het is een ongemakkelijk ding om in een repository te hebben en het is de enige test die de eigenschap daadwerkelijk aantoont.
En de vaste set is een beperking op de eigen evolutie van het platform. Een tiende control aan de lijst toevoegen is een grotere beslissing dan een feature toevoegen, want het verandert het contract met elke bestaande extensie.
Wat het niet doet
Het maakt de autoriteitsmetadata niet correct. Als een document als voor iedereen leesbaar is gelabeld terwijl dat niet zou moeten, geeft het post-filter het trouw terug. De control dwingt de labels af; hij controleert ze niet.
Het dekt geen kanalen die de kernel niet ziet. Een component die data ophaalt over een eigen netwerkverbinding en die via een zijpad aan het model voert, omzeilt het retrieval-filter omdat hij retrieval heeft omzeild. Isolatie, een ander lid van de vaste set, is wat dat afsluit, en in het prototype was isolatie grondiger ontworpen dan bewezen.
Als je een ding meeneemt
Schrijf de controls in je platform op die moeten standhouden ook als een plugin vijandig is. Zoek dan voor elk ervan op waar hij wordt toegepast. Als er een vóór de plugin draait in plaats van erna, of binnen de plugin in plaats van eromheen, heb je jouw versie van mijn retrieval-filter gevonden.
Standards and practices, zoals de kelder van The IT Crowd wist, daar is de brandblusser voor. De ring is de brandblusser die niet tegelijk ook een brand is.
Verwijzingen
De knipogen en citaten in dit stuk, met hun herkomst:
- G. K. Chesterton, The Thing (1929): Chesterton’s fence, do not remove a fence until you know why it was put there.
- The IT Crowd, “Calamity Jen” (2006): the fire extinguisher that is itself on fire, and the fire-safety training video.
- #Beslisrecords
- #AI-governance
- #Architectuur

Rutger Hemrika
AI-strategie en -governance voor sectorsoftware. Schrijft vanuit bouwen, niet vanuit slides; elke claim draagt een bewijsniveau.