How to Build a fraud detection Agent Using AutoGen in Python for pension funds

By Cyprian AaronsUpdated 2026-04-21
fraud-detectionautogenpythonpension-funds

A fraud detection agent for pension funds watches contribution flows, benefit claims, member profile changes, and payout requests for patterns that don’t fit normal behavior. It matters because pension fraud is usually low-volume but high-impact: one bad payout, one manipulated beneficiary record, or one synthetic identity can create regulatory exposure and damage member trust.

Architecture

  • Data ingestion layer

    • Pulls events from member administration systems, claims systems, payment rails, and case management.
    • Normalizes records into a common schema: member ID, event type, timestamp, amount, channel, jurisdiction.
  • Rules and signal extraction layer

    • Computes deterministic checks like duplicate bank accounts, rapid address changes, unusual withdrawal timing, and mismatched KYC fields.
    • Produces a compact risk summary for the agent.
  • AutoGen multi-agent decision layer

    • Uses AssistantAgent instances for fraud analysis and compliance review.
    • Uses a UserProxyAgent to execute code or call internal services when needed.
  • Case triage and audit layer

    • Generates an explainable risk assessment.
    • Stores the reasoning trail, inputs used, and final recommendation for auditability.
  • Action layer

    • Escalates to manual review, blocks payout, or requests additional verification.
    • Never auto-rejects without policy support in regulated pension workflows.

Implementation

1. Install AutoGen and define your case schema

Use the current AutoGen package and keep your event payloads explicit. Pension data is sensitive; do not let the agent infer missing fields from free text if you can avoid it.

pip install pyautogen
from dataclasses import dataclass
from typing import Literal, Optional

@dataclass
class PensionFraudCase:
    case_id: str
    member_id: str
    event_type: Literal["withdrawal", "beneficiary_change", "address_change", "bank_change", "claim"]
    amount: float
    jurisdiction: str
    kyc_match_score: float
    days_since_last_profile_update: int
    bank_account_reuse_count: int
    suspicious_velocity_score: float
    notes: Optional[str] = None

2. Create the AutoGen agents

Use one agent to analyze fraud signals and another to enforce compliance constraints. In pension funds, this split matters because fraud risk and regulatory admissibility are not the same thing.

import os
from autogen import AssistantAgent, UserProxyAgent

llm_config = {
    "model": os.environ.get("OPENAI_MODEL", "gpt-4o-mini"),
    "api_key": os.environ["OPENAI_API_KEY"],
}

fraud_analyst = AssistantAgent(
    name="fraud_analyst",
    llm_config=llm_config,
    system_message=(
        "You analyze pension fund events for fraud risk. "
        "Return concise findings with a risk score from 0 to 100. "
        "Cite only the provided case fields. "
        "Do not recommend actions that violate pension regulations or require unsupported evidence."
    ),
)

compliance_reviewer = AssistantAgent(
    name="compliance_reviewer",
    llm_config=llm_config,
    system_message=(
        "You review fraud recommendations for compliance with pension fund policy. "
        "Focus on auditability, data residency concerns, retention rules, and escalation requirements."
    ),
)

user_proxy = UserProxyAgent(
    name="user_proxy",
    human_input_mode="NEVER",
)

3. Run a two-agent fraud review workflow

This pattern keeps the model output structured enough for downstream triage. The first agent scores risk; the second checks whether the recommendation is acceptable under pension operations policy.

import json

def build_prompt(case: PensionFraudCase) -> str:
    return f"""
Assess this pension fund event for fraud risk.

Case:
{json.dumps(case.__dict__, indent=2)}

Return:
- risk_score: integer 0-100
- reasons: bullet list
- recommended_action: one of [monitor, step_up_verification, manual_review, hold_payment]
- audit_notes: short text explaining what fields drove the decision
"""

case = PensionFraudCase(
    case_id="CF-10482",
    member_id="M-88921",
    event_type="bank_change",
    amount=0.0,
    jurisdiction="ZA",
    kyc_match_score=0.62,
    days_since_last_profile_update=2,
    bank_account_reuse_count=3,
    suspicious_velocity_score=0.91,
)

fraud_result = user_proxy.initiate_chat(
    fraud_analyst,
    message=build_prompt(case),
)

compliance_result = user_proxy.initiate_chat(
    compliance_reviewer,
    message=f"""
Review this proposed action for a pension fund case:

{fraud_result.summary}

Confirm whether it is acceptable under policy.
If not acceptable, propose the safest alternative action.
""",
)
print(fraud_result.summary)
print(compliance_result.summary)

4. Add guardrails before any operational action

Do not let the agent directly move money or change member records. Put a deterministic policy gate in front of execution so only approved actions are allowed.

ALLOWED_ACTIONS = {"monitor", "step_up_verification", "manual_review", "hold_payment"}

def decide_action(agent_text: str) -> str:
    text = agent_text.lower()
    if "hold_payment" in text:
        return "hold_payment"
    if "manual_review" in text:
        return "manual_review"
    if "step_up_verification" in text:
        return "step_up_verification"
    return "monitor"

action = decide_action(fraud_result.summary)

if action not in ALLOWED_ACTIONS:
    raise ValueError("Blocked unsafe action")

# Example downstream handoff to case management system
case_payload = {
    "case_id": case.case_id,
    "member_id": case.member_id,
    "action": action,
}

Production Considerations

  • Keep data residency explicit

    • Pension data often has jurisdictional constraints.
    • Pin model hosting and logs to approved regions; do not send member PII across borders unless legal review has cleared it.
  • Log every decision path

    • Store input fields, prompt version, model version, output summary, and final human override.
    • Auditors will ask why a payout was held or why it was allowed through.
  • Use step-up verification instead of hard blocking by default

    • For beneficiary changes or bank detail updates, trigger OTP callbacks, document upload checks, or branch verification before freezing benefits.
    • This reduces false positives that frustrate retirees.
  • Separate detection from enforcement

    • The agent should recommend; a policy engine should execute.
    • That keeps controls explainable and makes it easier to prove segregation of duties.

Common Pitfalls

  1. Letting the model decide on raw PII

    • Don’t pass entire member profiles into prompts.
    • Extract only the fields needed for fraud assessment and redact everything else.
  2. Treating every anomaly as fraud

    • A recent address change plus a bank change is not proof of misconduct.
    • Use risk scoring with thresholds tied to workflow actions like manual review or step-up verification.
  3. Skipping audit trails

    • If you cannot reconstruct why a claim was flagged six months later, your control failed.
    • Version prompts, preserve outputs verbatim, and store reviewer overrides alongside case IDs.
  4. Using one agent for both detection and compliance

    • Fraud logic will optimize for catching suspicious activity; compliance logic will optimize for admissibility and process control.
    • Keep them separate so your escalation decisions survive internal audit and regulator review.

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