RAG
Azure OpenAI RAG-audit: onze checklist vóór de offerte
Voordat we een RAG-retrofit op Azure offreren, draaien we een audit van 14 punten op de tenant. Index-drift, content-safety en een failover-test om 04:00.

Het is dinsdag 04:17 in maart. Een operations lead bij een Rotterdams logistiek bedrijf stuurt ons een screenshot. Hun customer-service-agent, vorig jaar zomer gebouwd op Azure OpenAI en Azure Cognitive Search, heeft net een vraag over routering van gevaarlijke stoffen beantwoord met een procedure uit 2022. Die procedure is in december herschreven. De citation in het antwoord wijst naar een Azure blob-URL die 404 geeft. De klant heeft het gevraagd. De agent heeft het beantwoord. Niemand weet wat te doen met allebei die feiten.
Dit is de situatie waar elk Nederlands mkb met een halfafgewerkte RAG-stack uiteindelijk in belandt. Niet omdat de techniek slecht is. Omdat niemand de tenant heeft geaudit voor ze gevraagd werden hem uit te breiden.
Als een prospect bij ons komt voor een RAG-retrofit — vertaald: zorg alsjeblieft dat onze bestaande kennisbank-agent ook echt correct antwoordt — offreren we niet voordat we onderstaande audit hebben gedraaid. Het kost ons ongeveer een dag. Het heeft ons drie projecten bespaard die we nooit hadden moeten aannemen, en klanten een rebuild bespaard die ze niet nodig hadden.
Waarom we auditen voordat we offreren
Het patroon dat we bij Nederlandse mkb's onder de €18M omzet zien, is consistent. Iemand heeft in 2023 of 2024 Azure OpenAI opgespind. Daar is Cognitive Search bij gezet (inmiddels rebranded als Azure AI Search) omdat de docs dat zeiden. Het is op SharePoint of een blob-container gericht, het werkte in een demo, het ging live, en daarna heeft niemand de indexer veertien maanden aangeraakt. Tegen de tijd dat wij aankomen, drift de index, is de content-safety-configuratie wat het portal als default had staan en is het failover-plan een Notion-pagina waarop staat "vraag het aan Marco."
Een retrofit hierop offreren zonder audit is hoe je de boel uiteindelijk gratis opnieuw bouwt.
Onze checklist heeft veertien punten. Drie ervan wegen zwaarder dan de rest, en die krijgen het grootste deel van deze post: index-refresh-drift over de top 30 containers, content-safety-filterdekking op de top 15 prompts, en region-failover-overleving van West Europe naar North Europe om 04:00. De rest — embedding-modelversies, RBAC-scope, Key Vault-rotatie, log-retentie — is mechanisch. Hier zit het geld.
De eerste keer dat we deze audit end-to-end draaiden was eind 2024, nadat een klant een week customer-service-capaciteit kwijtraakte aan een agent die een inkoopbeleid citeerde dat al negen maanden was vervangen. De retrofit die ze begroot hadden, zou dat niet hebben gevangen. De audit wel, in ongeveer veertig minuten, en de rebuild waarvan ze dachten dat hij nodig was, werd twee weken indexer-loodgieterswerk en één citation-router-aanpassing.
Index-drift over de top 30 containers
Het eerste dat we ophalen is een snapshot van elke AI Search-index in de tenant en de laatste succesvolle indexer-run per data source. We rangschikken de data sources op documentcount en kijken naar de top 30 containers.
Voor elke container berekenen we drift: het gat in wall-clock-tijd tussen de meest recente wijziging in de bron en de meest recente succesvolle index-refresh die hem heeft opgepikt. Niet de last-run-timestamp van de indexer, maar de timestamp van het laatste document dat hij ook echt heeft weggeschreven.
De query om er te komen is simpel. Trek de indexer-status uit de REST-API, join tegen de Last-Modified-headers van de source-container, en schrijf de delta's naar een CSV.
curl -s -H "api-key: $SEARCH_KEY" \
"https://$SVC.search.windows.net/indexers?api-version=2024-07-01" \
| jq -r '.value[] | [.name, .lastResult.endTime, .lastResult.status, (.lastResult.itemsProcessed|tostring)] | @tsv'
We hertrappen dit elke vijftien minuten een werkdag lang en kijken naar de variantie. Een indexer die met succes afsluit maar run na run nul nieuwe items binnenhaalt, is de klassieke stille fout: het schema staat op groen, de metric die Azure in het portal toont staat op groen, en de index loopt maanden achter op de werkelijkheid. Het itemsProcessed-veld in de JSON hierboven is het enige dat dit goedkoop vangt.
Waar we op letten is de long tail. De top drie indexers zijn vrijwel altijd gezond omdat iemand erop let. De drift zit verstopt tussen rang 8 en rang 25, in de indexers waarvan niemand had opgemerkt dat ze negen maanden stil faalden op één malformed PDF, wat betekent dat alles wat in de queue achter die PDF stond er nooit in is gekomen.
Onze drempel: elke index met een drift van meer dan 72 uur op een bron die dagelijks update, of waar de indexer dezelfde waarschuwing meer dan drie runs op rij heeft gelogd, zakt voor de audit. Bij een typische Nederlandse mkb-tenant met 30+ containers verwachten we er vier tot zeven te zien zakken. Zakken er meer dan tien, dan wordt het retrofit-gesprek een re-platform-gesprek, en dat zeggen we schriftelijk voordat we offreren.
Content-safety-dekking op de top 15 prompts
Vervolgens trekken we de top 15 user-prompts op volume uit Application Insights, of welke logging het team ook had aangezet. Meestal is het niet Application Insights, en de eerste halve dag gaat zitten in het reconstrueren van logs uit de stdout van de agent.
Elke prompt halen we twee keer door de bestaande pipeline. Eén keer as-is. Eén keer met een kleine adversarial mutation: een omgewisseld voornaamwoord, een verzoek herkaderd als hypothetisch, een geketende instructie die het model vraagt zijn eigen system prompt samen te vatten. We loggen welk van de vier content-filter-categorieën van Azure OpenAI (hate, sexual, violence, self-harm) afging, op welke severity, en of de trigger vuurde op input, output, of beide.
Wat niemand zegt: de default content-filter-configuratie in Azure OpenAI is geen verdediging tegen prompt-injection. Prompt Shield is een aparte, opt-in laag in de Azure AI Content Safety-service, en bij elke audit die we de afgelopen acht maanden hebben gedraaid, stond hij uit. Als je agent met één hypothetische omweg te overtuigen is om zijn system prompt prijs te geven, zakt de audit op dit onderdeel nog voor de tweede prompt.
Voor de 15 prompts willen we 100% dekking op output-filtering op medium severity of hoger, en Prompt Shield aan op elke prompt die opgehaalde context consumeert — wat in een RAG-agent op alles neerkomt.
Region-failover-overleving van West Europe naar North Europe
Dit is het onderdeel waar de meeste teams nog nooit over hebben nagedacht, en dat sinds de Europese regelgevingsstemming is gedraaid steeds vaker terugkomt. Drie van onze Nederlandse klanten stuurden ons het afgelopen kwartaal varianten van hetzelfde Slack-bericht: als Microsoft een region verplaatst of de AP pusht terug, wat gebeurt er dan met onze agent?
Het eerlijke antwoord voor de meesten van hen: hij ligt ergens tussen vier uur en vier dagen plat, en de citation trail is weg.
De test die we draaien is concreet. We pakken drie kennisbanken — die die persoonsgegevens raken en daarmee onder AVG-citatieverplichtingen vallen — en we simuleren een region-failover van West Europe (Amsterdam) naar North Europe (Dublin) om 04:00 CET, op het moment dat de indexer-cronjobs en de nachtelijke AI Search-merges allebei draaien.
Wat we feitelijk controleren:
- Is de AI Search-index gerepliceerd, paired, of single-region? Default is single-region. Replicatie is iets dat je zelf opzet, niet iets dat Azure voor je doet.
- Staan de blob-containers waar de indexers op leunen in een paired storage account (RA-GRS of GZRS), of zijn het LRS in één zone?
- Wijst de citation chain van de agent — de URL's die hij in zijn antwoorden meegeeft — naar region-specifieke resource-namen? Zo ja, dan geeft elke gecachte citation in je conversation history na de failover een 404.
- Heeft de Azure OpenAI-deployment een sibling-deployment in de secundaire region met dezelfde modelversie en dezelfde fine-tuning-state? Modelbeschikbaarheid is niet symmetrisch tussen regions.
Van de drie kennisbanken die we pakken, slaagt de audit als ten minste één een failover overleeft met de citation trail intact. De afgelopen twaalf maanden hebben we elf Nederlandse mkb-tenants geaudit. Twee slaagden voor dit onderdeel. Twee.
Het AVG-citation-trail-probleem om 04:00
De AVG, de Nederlandse implementatie van de GDPR, gebruikt nergens de woorden "RAG-citation." Wat er wél staat, via de richtlijnen van de Autoriteit Persoonsgegevens over geautomatiseerde besluitvorming, is dat een betrokkene recht heeft op een betekenisvolle uitleg van hoe een beslissing waarin zijn persoonsgegevens een rol spelen tot stand is gekomen. Voor een agent die ophaalt en antwoordt, betekent dat dat de citation trail — welk document, welke versie, welke alinea — reproduceerbaar moet zijn op het moment van uitleg, niet op het moment van het antwoord.
Hier krijgt de failover-test zijn tanden. Als je citation naar https://stwesteurope.blob.core.windows.net/contracts/2024-11-rev3.pdf wijst en de failover hernoemt de storage account, dan staat het document nog wel in Dublin, maar is de URL in het conversation log dood. De betrokkene vraagt waarom de agent een bepaald tarief heeft voorgesteld. Je kunt het niet laten zien. Dat is eerst een AVG-probleem en daarna pas een Microsoft-probleem.
Onze aanbeveling in elke audit: citations moeten resolven via een router in eigen beheer, niet via een directe blob-URL. Een simpele /cite/{doc_id}/{version_hash}-route die de agent uitstoot, en die je applicatie resolved naar welke region het document op dat moment ook heeft. Vijf dagen werk. Bespaart je dat failover-gesprek voorgoed.
Als de citations van je RAG-agent directe Azure blob-URL's zijn, sterft je AVG-uitlegverhaal de eerste keer dat Microsoft een region uit de lucht haalt. Route citations via je eigen app.
Wat de audit kost, en wat hij verandert in de offerte
Eén engineer-dag aan onze kant. We leveren een memo van 6 tot 8 pagina's met de drift-tabel, de content-safety-matrix, de failover-scorecard, en een lijst van de elf andere checks die we hebben gedraaid zonder erover te schrijven. Daarna offreren we de retrofit, of we vertellen de klant de eerlijke versie — soms is dat "dit moet opnieuw worden gebouwd, dit is waarom, en je zou een second opinion moeten vragen voor je ons gelooft."
Het patroon: ongeveer een derde van de audits leidt tot een retrofit. Ongeveer een kwart tot een kleiner, smaller stuk werk (fix de indexers, laat de rest staan). Ongeveer een vijfde tot een re-platform. De rest gaat terug in de la totdat de klant een incident heeft dat bewijst dat de audit gelijk had.
De versie van vijf minuten die je zelf kunt draaien
Je hebt ons niet nodig voor de eerste snede. Open het Azure-portal. Ga naar je AI Search-service, kies de indexers-blade en sorteer op Last run. Alles ouder dan zeven dagen dat dagelijks zou moeten draaien is een finding. Open daarna Azure OpenAI Studio, ga naar Content filters, en check of de deployment die je gebruikt iets anders heeft dan het default Medium-filter op hate, sexual, violence en self-harm, en of Prompt Shield überhaupt aanstaat.
Zijn die twee schoon, dan zit je in het hoogste kwartiel van de Nederlandse mkb-tenants die wij zien. Is een van beide niet schoon, dan heb je een middag werk voor de boeg, en een gesprek met je FG daarvoor.
Toen we afgelopen najaar de kennisbank-agent bouwden voor een Nederlandse industriële groothandel, was dit precies het citation-routing-probleem waar we tegenaan liepen: hun conversation logs stonden vol duizenden dode blob-URL's uit een storage-account-migratie die niemand aan de agent had gekoppeld. We hebben het opgelost door eigen citation-ID's uit te stoten en die op render time te resolven, en daarna de historie te backfillen met een one-shot-script. Kijk je naar een vergelijkbare puinhoop, dan begint het AI-agent-werk dat we bij ABN doen met de audit hierboven en eindigt het met een systeem dat je zonder krimpen aan je auditor kunt overdragen.
Doe je deze week niets anders, trek dan de indexer-status-JSON uit je search-service en sorteer op laatste succesvolle run. Vijf minuten. Het eerste dat je vindt vertelt je of je rustig kunt blijven lezen of moet beginnen met paniekeren.
Kern
Audit voordat je een Azure RAG-agent retrofit: index-drift, content-safety-dekking en citation-overleving onder een failover van West Europe naar North Europe.
FAQ
Hoe lang duurt de audit?
Eén engineer-dag aan onze kant, plus ongeveer een halve dag access-provisioning aan klantkant. De oplevering is een memo van 6 tot 8 pagina's met de drift-tabel, content-safety-matrix en failover-scorecard.
Moeten we productiecredentials afgeven?
Nee. Read-only Reader-rol op de resource group waar AI Search en Azure OpenAI in zitten, plus leesrechten op de logs in Application Insights of het equivalent. Schrijfrechten hebben we niet nodig om de audit te draaien.
Wat gebeurt er als onze tenant zakt voor het failover-onderdeel?
Zakken voor het failover-onderdeel is de norm, niet de uitzondering. Twee van de elf tenants die we vorig jaar audit, slaagden. De fix is meestal een citation-router en paired storage, geen volledige re-platform.
Is het default content-filter van Azure OpenAI voldoende?
Het vangt de vier klassieke categorieën op medium severity. Het stopt geen prompt-injection. Prompt Shield is een aparte opt-in laag in Azure AI Content Safety en staat default uit op elke tenant die we hebben geaudit.
Eist de AVG echt een citation trail?
Niet in die woorden. Hij eist een betekenisvolle uitleg van geautomatiseerde besluiten waarin persoonsgegevens een rol spelen. Voor een RAG-agent is de citation trail de enige praktische manier om die uitleg achteraf te leveren.