How to Build a KYC verification Agent Using AutoGen in TypeScript for retail banking
A KYC verification agent in retail banking takes customer-submitted identity data, checks it against internal policy and external sources, flags mismatches, and produces an auditable decision trail. It matters because onboarding speed is tied directly to conversion, but the bank still has to satisfy AML/KYC controls, data residency rules, and regulator-ready evidence.
Architecture
- •
Orchestrator agent
- •Coordinates the workflow: document intake, data extraction, verification, escalation, and final recommendation.
- •In AutoGen, this is typically a
AssistantAgentthat reasons over the case and delegates tool calls.
- •
Document extraction tool
- •Pulls structured fields from passport, national ID, proof of address, or utility bills.
- •Should return normalized JSON: name, DOB, address, document number, expiry date.
- •
Verification tools
- •Internal customer master lookup
- •Sanctions/PEP screening
- •Address validation
- •Liveness or selfie match if your onboarding flow includes biometrics
- •
Compliance policy layer
- •Encodes bank-specific rules like required documents by country, age thresholds, sanctions hit handling, and escalation thresholds.
- •This should be deterministic code outside the model.
- •
Audit logger
- •Stores every prompt input, tool call, output decision, and human override.
- •Needed for explainability and regulator review.
- •
Human review queue
- •Handles ambiguous cases: partial matches, low-confidence OCR results, expired documents close to grace period.
- •The agent should route these cases instead of forcing a binary approve/reject.
Implementation
1) Set up AutoGen agents for KYC orchestration
For TypeScript, use the AutoGen agent runtime with an assistant for reasoning and a user proxy for executing tool-backed actions. The important pattern is that the model proposes actions; your code performs the actual compliance checks.
import { AssistantAgent } from "@microsoft/autogen";
import { UserProxyAgent } from "@microsoft/autogen";
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
const kycAgent = new AssistantAgent({
name: "kyc_verifier",
llmConfig: {
model: "gpt-4o-mini",
client,
temperature: 0,
},
systemMessage: `
You are a KYC verification assistant for retail banking.
Your job is to assess identity documents and customer profile data against bank policy.
Never make up facts. If evidence is missing or conflicting, escalate to human review.
Return concise decisions with reasons and required next actions.
`,
});
const executor = new UserProxyAgent({
name: "kyc_executor",
});
2) Define deterministic banking checks as tools
Do not ask the model to “decide” sanctions hits or residency constraints. Put those in code so the outcome is reproducible and audit-friendly.
type KycInput = {
fullName: string;
dateOfBirth: string;
countryOfResidence: string;
idDocumentNumber: string;
};
type KycResult = {
status: "approve" | "reject" | "review";
reasons: string[];
};
function runPolicyChecks(input: KycInput): KycResult {
const reasons: string[] = [];
if (!input.fullName || !input.dateOfBirth || !input.idDocumentNumber) {
reasons.push("Missing required identity fields");
return { status: "review", reasons };
}
const restrictedCountries = ["IR", "KP", "SY"];
if (restrictedCountries.includes(input.countryOfResidence)) {
reasons.push("Country of residence requires enhanced due diligence");
return { status: "review", reasons };
}
if (input.idDocumentNumber.length < 6) {
reasons.push("Document number format invalid");
return { status: "reject", reasons };
}
return { status: "approve", reasons: ["Basic policy checks passed"] };
}
3) Run the agent on a real case and force structured output
The model should summarize evidence and explain why a case is approved or escalated. Keep the final decision bounded by your policy function.
async function verifyCustomer(input: KycInput) {
const policyResult = runPolicyChecks(input);
const prompt = `
KYC case:
${JSON.stringify(input, null, 2)}
Policy result:
${JSON.stringify(policyResult, null, 2)}
Task:
1. Summarize what was checked.
2. Explain whether this should be approved or sent to review.
3. Do not override policy results.
`;
const response = await kycAgent.generateReply([
{ role: "user", content: prompt },
]);
return {
decision: policyResult.status,
policyReasons: policyResult.reasons,
agentSummary: response,
auditTimestamp: new Date().toISOString(),
dataResidencyNote:
"Store case artifacts in-region only; do not send PII to non-approved jurisdictions.",
};
}
(async () => {
const result = await verifyCustomer({
fullName: "Amina Khan",
dateOfBirth: "1991-04-12",
countryOfResidence: "GB",
idDocumentNumber: "GB1234567",
});
console.log(JSON.stringify(result, null, 2));
})();
Remaining step you should add in production
Wire verifyCustomer() into your onboarding service so that:
- •document OCR feeds the input object,
- •sanctions/PEP screening runs before any approval,
- •every response is written to an immutable audit store.
Production Considerations
- •
Deployment
- •Keep the agent stateless. Persist case state in your banking backend or workflow engine, not in memory.
- •Pin models and prompts by version so behavior changes go through change control.
- •
Monitoring
| Signal | Why it matters |
|---|---|
| Review rate | Spikes usually mean OCR drift or policy regressions |
| False reject rate | Directly impacts onboarding conversion |
| Human override rate | Shows where model summaries are misleading |
| Tool failure rate | Indicates upstream vendor or network issues |
- •Guardrails
| Guardrail | Implementation |
|---|---|
| No free-form approvals | Final approve/reject must come from deterministic policy code |
| PII minimization | Send only required fields to the model |
| Audit logging | Store prompt hash, tool inputs/outputs, timestamp, reviewer ID |
| Data residency | Route EU/UK customer cases to region-bound infrastructure |
- •Compliance controls
| Control area | What to enforce |
|---|---|
| AML/KYC | Sanctions hits always escalate |
| Record retention | Keep evidence per jurisdictional retention rules |
| Explainability | Every decision needs a reason chain |
| Access control | Limit who can view raw identity documents |
Common Pitfalls
- •
Letting the model make final compliance decisions
- •Fix it by separating reasoning from decisioning. The LLM explains; your policy engine decides.
- •
Sending too much PII into prompts
- •Fix it by redacting fields you do not need. For example, pass last four digits of an ID instead of the full number when possible.
- •
Skipping human review paths
- •Fix it by defining explicit escalation thresholds for expired documents near cutoff dates, OCR confidence drops, and partial sanctions matches.
- •
Ignoring jurisdictional constraints
- •Fix it by routing cases based on customer country and keeping logs plus artifacts inside approved regions only.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit