← Blog

Chat agents

Chat agent stacks scoren: kosten, AVG en vrijdag-CVE's

Een rapportage-agent die 240 klantrapportages per week binnentrekt heeft drie redelijke thuishavens. Wij scoren ze op kosten per klant, AVG-verdedigbare logs en wie op vrijdag de pieper draagt.

Jacob Molkenboer· Oprichter · A Brand New Company· 6 sep 2025· 8 min
Drie manila dossiers met linnen koord, brons label, groene lakzegel, bronzen bel, rood lint op ivoor papier.

Dinsdagochtend bij een Amsterdams bureau van 28 mensen. De client services-lead wil een chat-agent die de vraag "hoe deed de mei-campagne het voor klant Y" beantwoordt door GA4, Meta Ads en een Mollie-betaalfeed binnen te halen, samen te vatten en een Slack-bericht te droppen voor de standup. De operations manager wil weten wie de bak bezit als het model breekt. De founder wil de kosten per klant op één regel van een Google Sheet.

Drie stacks komen voorbij in het overleg. Wij hebben een scoremethode om ertussen te kiezen. Het kost 15 minuten en sluit de verkeerde uit voordat de bouw begint.

De workload, in cijfers

Breng eerst de workload in kaart, anders is elke kosteninschatting verderop fictie. Een typisch Nederlands retainerbureau van de grootte waar wij mee werken ziet er zo uit:

  • 14 actieve retainerklanten
  • ~17 pulls per week per klant (geplande rapportages plus ad-hoc vragen in Slack), dus 240 chat-agent calls per week
  • Elke call: ~1,2k input tokens aan gestructureerde cijfers plus een output van 600 tokens
  • De audit trail moet een AVG-vraag van de FG van een klant overleven zonder zes uur paniek
  • De engineer die de stack patcht woont in Eindhoven en ligt vrijdag om 18:00 al te slapen

Die laatste randvoorwaarde vergeten de meeste stackdiscussies. Het is ook degene die het antwoord bepaalt.

Cloudflare Workers AI plus D1

De dunste stack. Workers AI draait Llama 3.x of Mistral-inference aan de edge, D1 is SQLite-on-the-edge, Vectorize doet de embeddings. Totale infrastructuurfootprint: één wrangler.toml.

Kostenrekensom bij 240 pulls per week:

  • ~432k tokens per week gegenereerd, plus embedding calls
  • Een paar euro per klant per maand bij de huidige Workers AI neuron-prijzen voor een Llama 3.3-achtig model
  • De free tier van D1 en Vectorize dekt het tot je een paar miljoen audit log-rijen voorbij gaat

Wat we mooi vinden: nul ops. Elke request landt op een gedeployde Worker. EU data residency is een checkbox in Workers AI, en dat geeft je een geloofwaardig antwoord op de eerste vraag die een Nederlandse FG stelt.

Wat schuurt: de beschikbaarheid van het model schuift onder je. Wij hebben agents opgeleverd waarbij het model achter een Workers AI-alias stil veranderde en de prompt al woensdag regresseerde. Hangt je rapportage-agent aan de specifieke manier waarop Mistral 7B tabellen rendert, dan zit je voor altijd op dat compatibiliteitsrisico. De oplossing: pin op een specifieke modelversie in de binding, niet op de alias, en hang er een smoke-test prompt aan die bij elke deploy meedraait.

CVE-reactie op vrijdag: Cloudflare patcht. Jij leest een statuspagina. Eindhoven slaapt.

Supabase plus pgvector

Postgres-mensen kiezen dit. Je krijgt auth, row-level security, pgvector en Edge Functions in één project. De chat-agent zelf belt een externe LLM (Anthropic, Mistral La Plateforme, OpenAI) want Supabase host geen modellen. Dat is een feature, geen bug. Het betekent dat op de dag dat er een nieuwe checkpoint uitkomt, je één string in een Edge Function omgooit en een eval-suite draait tegen de audit log van de laatste 200 prompts.

Kostenrekensom bij 240 pulls per week:

  • Supabase Pro: ongeveer 25 euro per maand, vast bedrag ongeacht het aantal klanten tot aan het inbegrepen quotum
  • Externe LLM-tokens: meer per call dan Workers AI, met grotere context en sterker redeneervermogen
  • pgvector op 14 klanten maal een paar duizend chunks komt niet in de buurt van een tuningprobleem

Wat we mooi vinden: pgvector is echt Postgres. Het audit-verhaal schrijft zichzelf. Je bezit een audit_log-tabel, je back-upt 'm 's nachts naar een Hetzner-bak, je geeft een externe FG leesrechten. De jurist van het bureau kan het schema lezen, en dat is meer dan ze van de meeste SaaS audit trails kunnen zeggen.

Voor je elke prompt in één platte tabel logt: plan je partitionering. De operationele realiteit bijt in jaar twee. Een retentie-sweep over een paar miljoen rijen ongepartitioneerde audit log kan de database tientallen minuten offline trekken terwijl die indexes herschrijft. Partitioneer per maand vanaf dag één (PostgreSQL declarative partitioning docs) en een jaarlijkse rollover wordt een metadata-operatie.

CVE-reactie op vrijdag: Supabase patcht Postgres. Jij patcht je Edge Functions. De modelprovider patcht zichzelf. Drie piepers, en in het normale geval geen enkele voor jou.

Self-hosted Ollama plus Qwen3

De "onder het bureau van een partner"-stack. Eén of twee RTX 4090's, Ollama die Qwen3 14B of 32B serveert, Postgres ernaast voor de logs, en een WireGuard-tunnel terug naar de VPC van het bureau.

Kostenrekensom bij 240 pulls per week:

  • Hardware: ~3.000 euro eenmalig voor een 4090-bak, ~80 euro per maand stroom tegen Nederlandse netprijzen
  • LLM-tokens: nul marginaal
  • De aandacht van één engineer. De regel die de meeste decks weglaten en tegelijk de regel die bepaalt of deze stack over 24 maanden goedkoop of duur uitvalt

Wat we mooi vinden: data verlaat het pand niet. Voor een bureau met klanten in zorg, juridisch of gemeentelijk schrijft dat argument zichzelf in het inkoopformulier. Qwen3 32B is oprecht competent in het samenvatten van gestructureerde cijfers waar een rapportage-agent zich mee bezighoudt. Inference rond de 40 tokens per seconde op één 4090 is prima voor een asynchrone Slack-bot workload.

Wat schuurt: model provenance. "Eigen" open-weights deployments blijken bij inspectie regelmatig een merge van twee bestaande checkpoints met een dunne fine-tune erbovenop. Dezelfde val ligt klaar voor elk bureau dat "onze eigen AI" verkoopt aan een Nederlandse klant. Wil je richting een inkoper claimen dat het self-hosted draait, host dan gewichten die je tegen de SHA op Hugging Face hebt geverifieerd, leg vast welke checkpoint je serveert, en hou de merge-config in dezelfde git-repo als de deployment.

CVE-reactie op vrijdag: van jou. Een CVE op Ollama, op de container runtime, op de kernel, op cuDNN, op de NVIDIA-driver. Jij patcht, jij herstart, jij verifieert dat het embedding endpoint nog steeds de juiste vectoren teruggeeft. Eindhovens weekend is weg. Tenzij je er een onderhoudscontract bovenop legt, dat voor onze klanten meestal tussen de 350 en 600 euro per maand landt. Dat is de regel die de discussie "maar het is gratis" afsluit.

De scorekaart die wij echt gebruiken

We scoren elke stack op vijf regels, niet drie, omdat verborgen kosten zich daartussen verstoppen.

RegelCloudflareSupabaseOllama-bak
Per klant €/maand bij 240 pulls3 tot 610 tot 256 (geamortiseerd over 24 maanden)
AVG audit-verhaalGoedUitstekendUitstekend
CVE-pieper op vrijdagCloudflareSupabase plus jijJij
Model lock-inHoogLaagLaag
Tijd tot eerste werkende agent3 dagen5 dagen12 dagen

Wij wegen deze per bureau. Een bureau van 28 mensen met twee Drupal-sites en nul toegewijde DevOps wordt 80% van de tijd naar Supabase gerouteerd. Een boetiek die aanbestedingen voor gemeenten doet gaat naar de Ollama-bak, met een betaald onderhoudscontract aan de offerte vastgemaakt. Een puur marketingbureau met DTC e-commerce klanten krijgt Cloudflare. We mixen stacks gerust. Een redelijke hybride: Cloudflare voor het publieke chat-oppervlak, Supabase voor de audit en pgvector-store, een externe LLM voor het model. De Ollama-bak is de enige die niet lekker met de andere twee combineert, omdat het hele punt is dat er niets van de LAN af gaat.

De beslissingscode

We draaien dit letterlijk in een notebook tijdens de scoping van een bouw.

def pick_stack(agency):
    if agency.handles_health_or_municipality_data:
        return "ollama-on-prem"
    if agency.client_count < 8 and agency.values_speed_to_ship:
        return "cloudflare"
    if agency.has_dedicated_devops and agency.values_postgres:
        return "supabase"
    return "supabase"  # the safe default

Het is niet subtiel. Dat is precies de bedoeling. Drie geneste ifs dwingen je de randvoorwaarden hardop te benoemen, ten overstaan van de operations manager. Trekt zij aan values_speed_to_ship, dan heb je het echte argument boven tafel voordat het contract getekend wordt.

Het logging-schema dat wij opleveren

Welke stack ook wint, de audit-tabel is dezelfde. Wij gebruiken deze bij elke chat-agent build van de afgelopen 18 maanden.

create table chat_audit (
  id uuid primary key default gen_random_uuid(),
  ts timestamptz not null default now(),
  client_id text not null,
  user_email text not null,
  prompt_hash text not null,        -- sha256 of input, not the input
  prompt_redacted text,             -- PII-scrubbed copy for audit
  model text not null,
  input_tokens int,
  output_tokens int,
  response_redacted text,
  data_source text,                 -- 'ga4', 'meta_ads', 'mollie'
  cost_eur numeric(8,4)
) partition by range (ts);

create table chat_audit_2026_06 partition of chat_audit
  for values from ('2026-06-01') to ('2026-07-01');
Waarschuwing

Sla nooit de ruwe prompt op als die klant-PII bevat. Hash 'm, redact een kopie, en bewaar de geredacteerde kopie. De AP behandelt letterlijke prompts als persoonsgegevens zodra er een naam of e-mailadres in voorkomt. Sla dit over en een FG-vraag wordt een incident, geen log query.

De partitionering is de operationele les. Een platte audit-tabel groeit lineair met het gebruik en krimpt nooit. Per maand partitioneren betekent dat een jaarlijkse retentie-rollover een drop table chat_audit_2025_06 is die in milliseconden draait, en geen delete-where job die je op zondagmiddag uit bed pieept.

Het AVG-stuk, gewoon

De Autoriteit Persoonsgegevens kijkt naar drie dingen wanneer een chat-agent persoonsgegevens raakt: rechtmatige grondslag, proportionaliteit en de audit trail. De stack die je kiest verandert het derde. Op Cloudflare schrijf je logs naar Workers Analytics Engine of D1 en accepteer je de retentie-defaults. Op Supabase bezit je het schema en de back-ups. Op de Ollama-bak bezit je de schijf.

Verdedigbaarheidsranglijst volgens onze ervaring: Ollama, dan Supabase, dan Cloudflare. De kostenranglijst is ruwweg het omgekeerde. Het bureau kiest waar het op die curve gaat zitten.

Wat we deze maand daadwerkelijk zouden bouwen

Voor het bureau van dinsdagochtend in de opening, 14 retainerklanten, geen eigen DevOps, vooral DTC e-commerce: Supabase. Het audit-verhaal is schoon, de kosten zijn voorspelbaar, en als er een nieuwe modelcheckpoint uitkomt wisselen we één string. Eerder dit jaar bouwden wij dezelfde rapportage-agent voor een Rotterdamse media buyer op precies deze stack. Waar wij tegenaan liepen was dat pgvector hybride zoek op ruwe GA4-dimensies rotzooi opleverde tot we de dimensies vooraf clusterden tot een "campagneprofiel"-embedding per rapportageperiode. We losten het op met een nightly job die de profielvectoren bouwt voordat de agent draait, zodat de query op chat-moment altijd een snelle cosine-lookup is. Dat werk hoort thuis in onze AI-agents-praktijk.

Open een spreadsheet. Drie kolommen: stack, euro per klant per maand, wie op vrijdag de pieper draagt. Vul je echte klantenaantal in, je echte DevOps-capaciteit, je echte risicotolerantie. Het juiste antwoord rolt er in vijftien minuten uit.

Kern

Kies je chat-agent stack op wie op vrijdag de CVE-pieperrekening betaalt, niet op wie de mooiste demo heeft op het moment van scopen.

FAQ

Waarom niet gewoon OpenAI's Assistants API gebruiken en de stack-vraag overslaan?

In onze scorekaart valt dat samen met Supabase plus een LLM-provider, alleen met slechter audit-eigendom. Je bezit de logs niet, je bezit de orchestratie niet, en je AVG-antwoord wordt een vendor questionnaire in plaats van een schema.

Hoe verhoudt Qwen3 zich tot Llama 3.3 70B voor rapportage-samenvatting?

Op gestructureerde numerieke samenvattingen (GA4, ad spend-tabellen) komt Qwen3 32B in onze interne evals binnen een paar procent van Llama 3.3 70B, op een fractie van de GPU-footprint. Voor vrije-tekst klantcommunicatie staat Llama 3.3 nog voorop.

Wat duwt een bouw van Cloudflare af richting Supabase?

Zodra één klant ruwweg de 80 dagelijkse pulls passeert of lange contexts gaat gebruiken (8k+ input tokens), haalt de Workers AI-rekening een equivalent van Supabase plus externe LLM in. Dat is het kantelpunt dat wij het vaakst zien.

Kunnen we Supabase en de Ollama-bak naast elkaar draaien?

Ja, mits je voorzichtig bent. Gebruik Supabase voor auth en de audit trail, route inference naar de on-prem Ollama via een private endpoint. Het risico is dat de audit log nu wel het pand verlaat, waardoor het AVG-argument voor self-hosting verzwakt.

chat agentsai agentsarchitecturestrategyoperations

Iets bouwen?

Start een project