How to Build a KYC verification Agent Using AutoGen in Python for investment banking

By Cyprian AaronsUpdated 2026-04-21
kyc-verificationautogenpythoninvestment-banking

A KYC verification agent for investment banking takes client onboarding data, checks it against internal and external sources, flags risk signals, and produces an auditable recommendation for compliance review. It matters because onboarding delays cost revenue, but weak verification creates regulatory exposure, sanctions risk, and audit findings.

Architecture

Build this agent as a small multi-agent workflow, not a single monolithic prompt.

  • Intake agent

    • Normalizes client-submitted data: legal name, entity type, UBOs, jurisdiction, address, tax IDs.
    • Validates required fields before any downstream checks run.
  • Verification agent

    • Cross-checks the submission against internal KYC records, watchlists, sanctions lists, and corporate registry data.
    • Produces structured findings with evidence references.
  • Risk scoring agent

    • Assigns a risk level based on jurisdiction, ownership complexity, PEP/sanctions hits, adverse media, and missing documents.
    • Keeps the scoring rules explicit and versioned.
  • Compliance reviewer agent

    • Converts machine findings into a human-readable recommendation: approve, reject, or escalate.
    • Must be constrained to policy-only outputs.
  • Audit logger

    • Stores every prompt, tool call, result, and final decision with timestamps and correlation IDs.
    • This is non-negotiable in investment banking.
  • Human-in-the-loop gate

    • Routes edge cases to compliance analysts when confidence is low or policy thresholds are breached.
    • Prevents the agent from making autonomous approval decisions on high-risk clients.

Implementation

1) Install AutoGen and define the agent roles

Use autogen-agentchat and create separate agents for each function. For investment banking workflows, keep the LLM agents narrow and deterministic where possible.

pip install pyautogen autogen-agentchat
import os
from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient

model_client = OpenAIChatCompletionClient(
    model="gpt-4o-mini",
    api_key=os.environ["OPENAI_API_KEY"],
)

intake_agent = AssistantAgent(
    name="intake_agent",
    model_client=model_client,
    system_message=(
        "You normalize KYC intake data for investment banking. "
        "Return strict JSON only. Do not infer missing facts."
    ),
)

verification_agent = AssistantAgent(
    name="verification_agent",
    model_client=model_client,
    system_message=(
        "You analyze KYC evidence for sanctions, PEP, adverse media, "
        "and beneficial ownership issues. Return structured findings only."
    ),
)

compliance_agent = AssistantAgent(
    name="compliance_agent",
    model_client=model_client,
    system_message=(
        "You produce compliance recommendations for investment banking KYC. "
        "Use policy language only. Cite evidence fields from prior outputs."
    ),
)

2) Add deterministic tool functions for registry and watchlist checks

Do not ask the model to “know” sanctions data. Pull that from tools you control. In production these functions would call internal systems or vendors like World-Check or Dow Jones; here they are placeholders with real Python structure.

from typing import Dict, Any

def check_sanctions(name: str) -> Dict[str, Any]:
    # Replace with vendor API call or internal screening service
    hits = ["OFAC"] if "acme" in name.lower() else []
    return {"source": "sanctions_screen", "hits": hits}

def check_corporate_registry(entity_name: str) -> Dict[str, Any]:
    # Replace with registry API call
    return {
        "source": "corporate_registry",
        "registered": True,
        "jurisdiction": "GB",
        "status": "active",
    }

3) Orchestrate the workflow with AutoGen messages

The pattern is: normalize input first, run deterministic checks second, then ask the model to synthesize a recommendation. Keep the final output bounded to what compliance needs.

import json

client_input = {
    "legal_name": "Acme Capital Holdings Ltd",
    "entity_type": "corporation",
    "jurisdiction": "GB",
    "ubo_count": 2,
    "tax_id_present": True,
}

normalized = intake_agent.run(task=f"Normalize this KYC payload as JSON: {json.dumps(client_input)}")
normalized_json = normalized.messages[-1].content

screening_result = check_sanctions(client_input["legal_name"])
registry_result = check_corporate_registry(client_input["legal_name"])

verification_prompt = f"""
Client data:
{normalized_json}

Sanctions result:
{json.dumps(screening_result)}

Registry result:
{json.dumps(registry_result)}

Return JSON with:
- risk_level: low|medium|high
- findings: array of objects with field, issue, severity
- recommendation: approve|escalate|reject
- rationale: short string
"""

verification_output = verification_agent.run(task=verification_prompt)
findings_json = verification_output.messages[-1].content

compliance_prompt = f"""
Review this KYC assessment and produce a compliance decision memo.

Assessment:
{findings_json}

Rules:
- If sanctions hits exist -> reject or escalate depending on policy.
- If UBO count is high or jurisdiction is higher risk -> escalate.
- Do not invent facts.
"""

decision_output = compliance_agent.run(task=compliance_prompt)
print(decision_output.messages[-1].content)

4) Wrap it in an audit trail before you deploy

Investment banking teams need replayable decisions. Log every input and output with immutable metadata so audit can reconstruct why a client was escalated or rejected.

from datetime import datetime
from pathlib import Path

def audit_event(case_id: str, stage: str, payload: str) -> None:
    record = {
        "case_id": case_id,
        "stage": stage,
        "timestamp_utc": datetime.utcnow().isoformat(),
        "payload": payload,
    }
    Path("audit_log.jsonl").open("a", encoding="utf-8").write(json.dumps(record) + "\n")

case_id = "KYC-2026-00042"
audit_event(case_id, "input", json.dumps(client_input))
audit_event(case_id, "sanctions_check", json.dumps(screening_result))
audit_event(case_id, "registry_check", json.dumps(registry_result))
audit_event(case_id, "decision", decision_output.messages[-1].content)

Production Considerations

  • Data residency

    • Keep client PII in-region if your bank operates under UK/EU/US residency constraints.
    • If the LLM endpoint leaves your approved boundary, redact names, addresses, tax IDs, and document numbers before sending prompts.
  • Auditability

    • Persist raw tool outputs alongside model outputs.
    • Store prompt versions and policy versions so compliance can reproduce historical decisions during audits or regulatory exams.
  • Guardrails

    • Never let the model approve high-risk clients autonomously.
    • Hard-code escalation rules for sanctions hits, missing UBO disclosure, complex offshore structures, and mismatched legal entities.
  • Monitoring

    • Track false positives on watchlist screening and manual override rates by analyst team.
    • Alert on drift in risk scoring distributions because onboarding patterns change fast across regions and products.

Common Pitfalls

  1. Using one agent for everything

    • This turns verification into prompt soup.
    • Split intake, screening synthesis, compliance recommendation, and logging into separate responsibilities.
  2. Letting the model fabricate evidence

    • If you ask for “missing info,” it will often fill gaps incorrectly.
    • Force strict JSON outputs and only allow conclusions grounded in tool results or provided documents.
  3. Ignoring policy thresholds

    • A technically correct answer can still violate bank policy.
    • Encode escalation thresholds outside the model so sanctions hits or high-risk jurisdictions always trigger deterministic handling.

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