Strategy
KYC-agent orchestratie: LangGraph, Mastra of zelfgebouwd
Om 23:07 verplaatst iDIN zijn consent endpoint. 3.400 checks per week stapelen zich op. Wie de orchestratielaag bezit, bezit de pager. We vergeleken drie opties.

Het is 23:07 op een dinsdag in Tilburg. De on-call engineer van een fintech met 25 mensen krijgt een pager-alert. iDIN, de Nederlandse bank-uitgegeven identiteitsdienst, heeft zijn consent endpoint stilletjes geroteerd tijdens een gepland change window. De KYC-agent gooit 422's op elke nieuwe aanvraag. Tegen de ochtend staan er 480 onverwerkte identiteitscontroles in de queue en vraagt een customer-success lead waarom onboarding stilstaat.
De vraag die nacht is niet welk framework de beste DX heeft. De vraag is wie een gepatchte workflow voor 06:30 in productie kan krijgen, en of het beslisspoor over zes maanden nog overeind staat als DNB vraagt hoe die aanvraag is gescoord.
We hebben in de afgelopen twaalf maanden KYC-pipelines gebouwd op drie verschillende orchestratielagen. Wat elk kost, breekt en overleeft.
Het scoringsraster
Drie assen. De rest is ruis.
- Kosten per aanvraag in steady state. De Tilburgse winkel draait 3.400 checks per week, ongeveer 177.000 per jaar.
- Wwft-verdedigbare step replay. Als een transactiemonitoring-officer vraagt waarom een aanvraag is gemarkeerd voor EDD, moet het systeem het volledige beslispad reconstrueren: modelinputs, tool-outputs, prompt-versies, timestamps. Zeven jaar bewaartermijn.
- Time-to-patch wanneer een upstream API verschuift. iDIN, Veriff, Onfido, het KvK-handelsregister: ze veranderen allemaal van vorm. Het incident om 23:00 is de echte test.
We hebben LangGraph 0.4, Mastra 0.10 en een zelfgebouwde stack op de Claude Agent SDK plus Postgres tegen elkaar gezet. Dezelfde prompts, dezelfde tools, dezelfde modellen (Sonnet voor de orchestratie, Haiku voor de goedkope classifier-calls).
LangGraph trial
LangGraph modelleert de pipeline als een stateful graph: nodes zijn tools of LLM-calls, edges zijn conditionele transities, state wordt automatisch gecheckpoint. Voor Wwft-replay kun je elke run rehydrateren vanuit de persisted checkpoint store. Dat deel is echt en werkt.
De adder is de abstractietax. Een KYC-flow heeft misschien negen nodes: parse het BSN, hit het iDIN consent endpoint, haal UBO-data op bij KvK, draai de sanctiescreen, classificeer het risico, route naar EDD of pass, schrijf audit log, notify de klant, sluit de case. In LangGraph kwam dat neer op ongeveer 600 regels Python inclusief de State TypedDict, conditionele edges en de LangSmith tracing-bedrading.
from langgraph.graph import StateGraph, END
class KYCState(TypedDict):
bsn: str
idin_token: str | None
ubo: list[dict] | None
sanctions_hits: list[dict]
risk_band: Literal["pass", "edd", "deny"]
audit: list[dict]
graph = StateGraph(KYCState)
graph.add_node("idin", call_idin)
graph.add_node("kvk_ubo", fetch_ubo)
graph.add_node("sanctions", screen_sanctions)
graph.add_node("classify", llm_classify_risk)
graph.add_conditional_edges("classify", route_by_band, {
"pass": "audit_pass",
"edd": "audit_edd",
"deny": "audit_deny",
})
Toen iDIN zijn endpoint roteerde, was de patch een one-line URL-wijziging. Makkelijk. Maar twee weken eerder had een LangChain 0.3.x point release stilletjes veranderd hoe geneste tool-calls werden gerresolved binnen MessagesPlaceholder, waardoor onze classifier prompt cache zes uur kapot was voordat iemand het doorhad. Het pager-event zat in het framework, niet bij de vendor. Dat is de LangGraph-deal: het framework geeft je veel, en je erft zijn release-cadans.
Kosten per aanvraag in onze run: ongeveer €0,011 aan modelkosten, plus LangSmith als je de replay-UI wil zonder zelf te hosten. Wij self-hostten, dus €0 hosted. Engineering overhead landde op ruwweg 0,4 FTE alleen al om upstream changes bij te houden.
Mastra trial
Mastra is op dit moment de schoonste TypeScript-optie in dit veld. Workflows zijn composable steps met typed inputs en outputs, agents zijn first-class, en de lokale dev-UI laat step-by-step traces zien out of the box. Voor een Nederlandse shop die al Next.js op Vercel schrijft, is de frictie bijna nul.
import { Workflow, Step } from "@mastra/core";
const kyc = new Workflow({ name: "kyc-aanvraag" })
.step(new Step({
id: "idin",
execute: async ({ context }) => idin.exchange(context.bsn),
}))
.step(new Step({
id: "ubo",
execute: async ({ context }) => kvk.ubo(context.kvkNummer),
}))
.then("classify")
.commit();
Het Wwft-verhaal is out of the box zwakker. Mastra persisteert workflow-runs, maar het schema is van hen, de replay-UI is van hen, en er is geen gedocumenteerd patroon voor zeven jaar retentie. Uiteindelijk hebben we onze eigen append-only audit-tabel in Postgres geschreven en gestructureerde events uit elke step geëmit. Dat werkte, maar het betekende dat we de helft van het werk deden dat het framework had moeten opvangen.
De patch om 23:00 was de makkelijkste van de drie: hot reload, redeploy op Vercel binnen drie minuten. De adder is dat Mastra jong is. De 0.10 release in ons venster bracht twee breaking changes ten opzichte van 0.9. Als je vandaag adopteert, commit je je aan het bijhouden van een hardlopend project. Hun eigen docs zijn daar eerlijk over.
Kosten per aanvraag: ongeveer €0,011 aan modelkosten. Engineering overhead: 0,3 FTE, lager omdat het oppervlak kleiner is.
Zelfgebouwd op Claude Agent SDK plus Postgres
Dit is wat we naar productie hebben gebracht. De orchestrator is ongeveer 900 regels TypeScript. Elke KYC-step is een functie die een case_id aanneemt, de vorige step uit een kyc_steps-tabel in Postgres leest, de volgende tool of het volgende model aanroept, en het resultaat als append-only row terugschrijft.
create table kyc_steps (
id bigserial primary key,
case_id uuid not null,
step_name text not null,
step_input jsonb not null,
step_output jsonb,
model_id text,
prompt_hash text,
started_at timestamptz not null default now(),
finished_at timestamptz,
cost_eur numeric(10,6)
);
create index on kyc_steps (case_id, started_at);
Replay is een SQL-query. Gegeven een case_id, selecteer alle steps op volgorde en je hebt het volledige beslispad, inclusief de prompt-hash zodat je kunt bewijzen welke versie van de template draaide. Een Wwft-auditor loopt binnen, je geeft 'm een CSV. We hebben nooit met de toezichthouder hoeven discussiëren over wat als reconstrueerbaar telt.
De iDIN-patch om 23:00 was een twaalf-regelige diff in de idinConsent-functie en een redeploy. Geen framework upgrade, geen checkpoint-migratie, geen breaking-change changelog om om middernacht door te lezen. De on-call engineer had 'm om 23:41 weer in de lucht.
De adder is reëel: je bezit alles. Er is geen LangSmith-dashboard om naar je CISO te sturen, geen Mastra DevTools-UI voor het productteam. Je bouwt de observability die je nodig hebt, of je slaat het over. Voor een shop van 25 mensen met één senior backend engineer die van Postgres houdt, prima. Voor een team van vijf dat alles out of the box wil laten werken, een slechte gok.
Kosten per aanvraag: ongeveer €0,0094 aan modelkosten, omdat we framework-overhead per call wegslopen en agressief leunen op de Anthropic prompt cache. Engineering overhead: 0,5 FTE voor de bouw, 0,2 FTE doorlopend.
Economie per aanvraag bij 177k per jaar
Steady-state getallen, afgerond op euro's:
LangGraph Mastra Zelfgebouwd
Modelkosten €1.947 €1.947 €1.665
Hosting €240 €0 (Vercel) €180
Eng overhead* €38.400 €28.800 €19.200 (jr 2+)
Totaal / jaar €40.587 €30.747 €21.045
Per aanvraag €0,230 €0,174 €0,119
* 0,4 / 0,3 / 0,2 FTE @ €96k loaded
Het verschil in modelkosten is klein. Het verschil in engineering overhead is enorm, en dat is het enige getal dat na maand drie nog telt. Een framework dat je een halve FTE kost om bij te houden, is duurder dan een zelfgebouwde stack op elke plausibele schaal onder een miljoen aanvragen per jaar.
De Wwft step-replay test
We hebben dezelfde fictieve EDD-escalatie door alle drie de stacks gedraaid en één vraag gesteld: kan een compliance officer met read-only Postgres-toegang in minder dan vijf minuten reconstrueren waarom aanvraag #A-44219 is gemarkeerd?
- LangGraph: ja, via de LangSmith replay-UI of door de checkpoint store direct te lezen. Vereist dat de officer de state shape van het framework begrijpt.
- Mastra: deels. De workflow-run staat er, maar onze custom audit-tabel deed het zware werk.
- Zelfgebouwd: ja, via één SQL-query. Het schema is het schema dat we voor compliance hebben ontworpen, niet voor het framework.
Als de audit-tabel het product is, laat het orchestratie-framework dan niet de vorm ervan bezitten. Compliance-schema's overleven frameworks met een decennium.
De 23:00-patchvraag
Dit is degene die niemand stelt tijdens de proof-of-concept en iedereen stelt op de post-mortem. Wanneer iDIN op een dinsdag om 23:00 zijn consent endpoint roteert, wie patcht de workflow?
LangGraph: je senior Python engineer, nadat hij eerst heeft gecheckt of het onderliggende probleem in LangChain core, LangGraph of je eigen code zit. Mediane time-to-fix in onze trial: 47 minuten.
Mastra: je senior TypeScript engineer. Mastra heeft een dunnere abstractie dus het verdachte oppervlak is kleiner. Mediane time-to-fix: 18 minuten.
Zelfgebouwd: wie er ook on-call is, omdat de code leest als de rest van de codebase. Mediane time-to-fix: 11 minuten.
Het gebruikelijke advies is: kies de orchestratielaag die je kunt forken. De scherpere versie: kies de laag die je on-call engineer om 23:00 kan fixen zonder een changelog te lezen.
Wat we hebben opgeleverd
De Tilburgse fintech is uiteindelijk op de zelfgebouwde stack uitgekomen. Drie maanden verder zit de prijs per aanvraag op €0,12, is de Wwft-audit zonder bevindingen doorgekomen en is de on-call rotatie twee keer afgegaan. Beide keren was de fix een pull request, geen framework upgrade.
Toen we de KYC-AI-agents voor deze klant bouwden, liepen we ertegenaan dat elke kijk hoe makkelijk dit is framework-demo uitgaat van een workflow die niet verandert. We hebben dat opgelost door de audit-tabel als het product te behandelen en de orchestratiecode als wegwerpsteigers eromheen.
Als je iets gereguleerds draait en je kunt de 23:00-vraag niet in één zin beantwoorden, open dan vanavond je audit-tabel en schrijf de SQL die je morgen aan een DNB-inspecteur zou geven. Als die query langer is dan vijf regels, zit het framework in de weg.
Kern
Kies de orchestratielaag die je on-call engineer om 23:00 kan patchen zonder een changelog te lezen. Compliance-schema's overleven frameworks.
FAQ
Is LangGraph een slechte keuze voor KYC?
Nee. Het werkt en de checkpoint-replay is echt. De kosten zitten in framework-drift: je besteedt ruwweg 0,4 FTE per jaar aan het bijhouden van LangChain-releases waar je niet om hebt gevraagd.
Is Mastra production-ready voor Nederlandse gereguleerde werk?
Voor TypeScript-shops die het audit-verhaal zelf bezitten, ja. Voor Wwft-gebonden werk: reken erop dat je je eigen append-only audit-tabel schrijft. Vertrouw niet op de ingebouwde run history voor zeven jaar retentie.
Wat vereist Wwft step replay precies?
Een reconstrueerbaar beslispad met inputs, outputs, model id, prompt-versie en timestamps, zeven jaar bewaard. De meeste teams onderspecificeren het prompt-versioning deel.
Hoe lang duurde de zelfgebouwde build?
Twee senior engineers, zes weken, inclusief het Postgres audit-schema, prompt versioning, een minimale interne replay-UI en integratietests tegen een iDIN-sandbox.