How to Build a KYC verification Agent Using AutoGen in TypeScript for retail banking

By Cyprian AaronsUpdated 2026-04-21
kyc-verificationautogentypescriptretail-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 AssistantAgent that 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

SignalWhy it matters
Review rateSpikes usually mean OCR drift or policy regressions
False reject rateDirectly impacts onboarding conversion
Human override rateShows where model summaries are misleading
Tool failure rateIndicates upstream vendor or network issues
  • Guardrails
GuardrailImplementation
No free-form approvalsFinal approve/reject must come from deterministic policy code
PII minimizationSend only required fields to the model
Audit loggingStore prompt hash, tool inputs/outputs, timestamp, reviewer ID
Data residencyRoute EU/UK customer cases to region-bound infrastructure
  • Compliance controls
Control areaWhat to enforce
AML/KYCSanctions hits always escalate
Record retentionKeep evidence per jurisdictional retention rules
ExplainabilityEvery decision needs a reason chain
Access controlLimit who can view raw identity documents

Common Pitfalls

  1. Letting the model make final compliance decisions

    • Fix it by separating reasoning from decisioning. The LLM explains; your policy engine decides.
  2. 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.
  3. Skipping human review paths

    • Fix it by defining explicit escalation thresholds for expired documents near cutoff dates, OCR confidence drops, and partial sanctions matches.
  4. Ignoring jurisdictional constraints

    • Fix it by routing cases based on customer country and keeping logs plus artifacts inside approved regions only.

Keep learning

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

Related Guides