How to Build a KYC verification Agent Using LlamaIndex in Python for pension funds

By Cyprian AaronsUpdated 2026-04-21
kyc-verificationllamaindexpythonpension-funds

A KYC verification agent for pension funds ingests identity documents, validates them against policy, extracts key fields, and flags mismatches or missing evidence before a human reviewer signs off. It matters because pension funds handle regulated retirement assets, so bad onboarding is not just an ops problem; it creates compliance exposure, audit gaps, and downstream account restrictions.

Architecture

  • Document ingestion layer

    • Pulls PDFs, scans, IDs, proof of address, tax forms, and trust documents from secure storage.
    • Normalizes files into text and metadata for downstream retrieval.
  • Indexing and retrieval layer

    • Uses LlamaIndex to build searchable indexes over KYC policies, checklists, and customer-submitted documents.
    • Supports policy-grounded answers instead of free-form LLM guesses.
  • Verification engine

    • Compares extracted identity attributes against the pension fund’s KYC rules.
    • Detects missing fields, expired documents, name mismatches, and inconsistent addresses.
  • Decisioning and escalation layer

    • Produces a structured outcome: pass, fail, or manual review.
    • Escalates edge cases like politically exposed persons, sanctions hits, or trust structures.
  • Audit logging layer

    • Stores every retrieved source chunk, model output, rule hit, and reviewer action.
    • Gives compliance teams a defensible trail for regulators and internal audit.
  • Data governance layer

    • Enforces residency constraints, retention rules, encryption, and access control.
    • Keeps pension member data isolated from general-purpose AI workloads.

Implementation

1) Install dependencies and load your KYC policy corpus

For this pattern you want two corpora:

  • internal KYC policy documents
  • customer-submitted verification documents

Use SimpleDirectoryReader to load files and VectorStoreIndex to make them queryable.

from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
from llama_index.core.settings import Settings
from llama_index.llms.openai import OpenAI

# Configure your LLM once at startup
Settings.llm = OpenAI(model="gpt-4o-mini", temperature=0)

# Load internal policy docs
policy_docs = SimpleDirectoryReader(
    input_dir="./data/kyc_policies",
    recursive=True
).load_data()

# Load submitted customer docs
customer_docs = SimpleDirectoryReader(
    input_dir="./data/customer_case_001",
    recursive=True
).load_data()

policy_index = VectorStoreIndex.from_documents(policy_docs)
customer_index = VectorStoreIndex.from_documents(customer_docs)

policy_engine = policy_index.as_query_engine(similarity_top_k=3)
customer_engine = customer_index.as_query_engine(similarity_top_k=3)

This gives you two separate retrieval surfaces. That separation matters because the agent should compare evidence against policy without mixing the sources into one undifferentiated blob.

2) Extract a structured KYC checklist from policy

Use QueryEngine output to turn policy text into explicit checks. For pension funds that usually means identity verification, address verification, tax residency, beneficial ownership for trusts, and document freshness.

policy_prompt = """
Extract the KYC requirements as a JSON list with fields:
- check_name
- requirement
- evidence_needed
- fail_condition

Focus on pension-fund onboarding rules only.
"""

response = policy_engine.query(policy_prompt)
print(str(response))

In production you should parse this into strict JSON and persist it as your rule baseline. Don’t leave policy interpretation buried in prompt text; compliance teams need versioned rules they can review.

3) Compare customer evidence against the checklist

Now query the customer corpus for each required item. The agent should not “decide” from memory; it should cite retrieved evidence from the submitted documents.

from llama_index.core import PromptTemplate

verification_template = PromptTemplate(
    """
You are verifying KYC evidence for a pension fund onboarding case.

Policy requirement:
{requirement}

Evidence needed:
{evidence_needed}

Customer document excerpts:
{context}

Return:
- status: PASS | FAIL | REVIEW
- reason: short explanation
- cited_fields: list of fields found or missing
"""
)

checks = [
    {
        "check_name": "Identity document",
        "requirement": "Government-issued ID must be valid and unexpired.",
        "evidence_needed": "Full name, date of birth, document number, expiry date.",
    },
    {
        "check_name": "Proof of address",
        "requirement": "Proof of address must be dated within the last 3 months.",
        "evidence_needed": "Name and residential address matching application data.",
    },
]

results = []

for check in checks:
    context_response = customer_engine.query(
        f"Find evidence relevant to: {check['check_name']}. Return only supporting excerpts."
    )

    prompt = verification_template.format(
        requirement=check["requirement"],
        evidence_needed=check["evidence_needed"],
        context=str(context_response),
    )

    decision = Settings.llm.complete(prompt)
    results.append({
        "check_name": check["check_name"],
        "decision": str(decision),
        "source": str(context_response),
    })

for item in results:
    print(item["check_name"])
    print(item["decision"])

This pattern is simple but production-friendly. You retrieve only what you need per check, then force the model to justify a structured outcome using cited excerpts.

4) Add a human-review gate for risky cases

Pension fund onboarding often includes trusts, nominees, employer-sponsored accounts, or cross-border members. Those cases should default to review when confidence is low or when the document set is incomplete.

def needs_manual_review(decision_text: str) -> bool:
    risky_markers = ["REVIEW", "missing", "inconsistent", "expired", "unable to verify"]
    lowered = decision_text.lower()
    return any(marker in lowered for marker in risky_markers)

manual_review_queue = []
auto_passed = []

for item in results:
    if needs_manual_review(item["decision"]):
        manual_review_queue.append(item)
    else:
        auto_passed.append(item)

print("Manual review:", len(manual_review_queue))
print("Auto passed:", len(auto_passed))

That gate is important. For regulated onboarding workflows you want deterministic escalation instead of letting the model overrule weak evidence.

Production Considerations

  • Keep data residency explicit

    • Store member documents and embeddings in-region if your pension fund operates under local residency rules.
    • Make sure your LlamaIndex vector store backend supports the required deployment boundary.
  • Log every decision with source traces

    • Persist retrieved chunks, prompt versions, model version, timestamps, and final disposition.
    • Auditors will ask why a case was passed or escalated six months later.
  • Use strict guardrails on outputs

    • Require JSON responses for status/reason/citations.
    • Reject free-form answers that do not reference source material from approved corpora.
  • Separate PII handling from general chat workflows

    • Use dedicated service accounts and encrypted storage.
    • Never route raw passport numbers or tax IDs into broad conversational logs.

Common Pitfalls

  1. Mixing policy docs with applicant docs in one index

    • This makes retrieval noisy and can cause the model to quote applicant data as if it were policy.
    • Keep separate indexes for rules and evidence.
  2. Treating LLM output as a final compliance decision

    • The agent should recommend pass/fail/review based on evidence.
    • Final approval still belongs to compliance operations for high-risk pension cases.
  3. Ignoring document freshness and jurisdiction

    • A valid ID copy is not enough if proof of address is stale or the member is subject to foreign tax reporting rules.
    • Encode expiry windows and country-specific checks explicitly in your verification logic.

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