How to Build a transaction monitoring Agent Using AutoGen in Python for lending

By Cyprian AaronsUpdated 2026-04-21
transaction-monitoringautogenpythonlending

A transaction monitoring agent for lending watches borrower activity, flags suspicious or policy-breaking behavior, and routes the right cases to analysts or automated workflows. For lenders, this matters because transaction patterns can signal fraud, loan stacking, synthetic identity use, first-party default risk, or covenant abuse before losses show up on the books.

Architecture

  • Transaction ingestion layer

    • Pulls events from card processors, ACH rails, bank feeds, loan servicing systems, or event streams.
    • Normalizes raw transactions into a consistent schema: borrower_id, timestamp, amount, counterparty, channel, geo, and merchant category.
  • Policy and rules engine

    • Applies hard controls first: velocity limits, high-risk geographies, cash-like merchant categories, and unusual repayment patterns.
    • Keeps deterministic checks separate from LLM reasoning so auditability stays clean.
  • AutoGen agent layer

    • Uses AssistantAgent for reasoning over transaction context and UserProxyAgent for tool execution.
    • Produces a structured risk assessment and recommended action.
  • Case management / escalation

    • Sends high-risk cases to an analyst queue with evidence attached.
    • Stores the model output alongside the exact input features used for the decision.
  • Audit and logging store

    • Persists prompts, tool calls, outputs, timestamps, model version, and rule hits.
    • Supports regulator review and internal model governance.

Implementation

1) Install AutoGen and define your transaction schema

Use the current AutoGen package and keep your schema explicit. In lending workflows, vague JSON blobs are a liability because you need traceability across repayment behavior, borrower identity signals, and source-of-funds patterns.

pip install pyautogen pydantic
from typing import List, Literal
from pydantic import BaseModel

class Transaction(BaseModel):
    borrower_id: str
    tx_id: str
    amount: float
    currency: str = "USD"
    channel: Literal["ach", "card", "wire", "cash", "crypto"]
    merchant_category: str
    country: str
    timestamp: str
    description: str

class MonitoringResult(BaseModel):
    risk_level: Literal["low", "medium", "high"]
    reasons: List[str]
    recommended_action: Literal["allow", "review", "block"]

2) Build tools for deterministic checks

Keep rule checks outside the LLM. The agent should explain and prioritize findings; it should not be the only enforcement layer.

def velocity_check(tx: Transaction) -> bool:
    return tx.amount > 5000

def high_risk_geo_check(tx: Transaction) -> bool:
    return tx.country in {"IR", "KP", "SY"}

def cash_like_check(tx: Transaction) -> bool:
    return tx.merchant_category in {"money_transfer", "casino", "gift_card"}

3) Wire up AutoGen agents and run a monitoring conversation

This pattern uses AssistantAgent for analysis and UserProxyAgent as the orchestrator. The assistant receives structured transaction data plus rule outputs and returns a concise case assessment.

import json
from autogen import AssistantAgent, UserProxyAgent

llm_config = {
    "config_list": [
        {
            "model": "gpt-4o-mini",
            "api_key": os.environ["OPENAI_API_KEY"],
        }
    ],
    "temperature": 0,
}

assistant = AssistantAgent(
    name="transaction_monitor",
    llm_config=llm_config,
    system_message=(
        "You are a lending transaction monitoring analyst. "
        "Classify transactions using compliance-aware reasoning. "
        "Return only valid JSON with keys risk_level, reasons, recommended_action."
    ),
)

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

def monitor_transaction(tx: Transaction):
    rule_hits = []
    if velocity_check(tx):
        rule_hits.append("amount_above_velocity_threshold")
    if high_risk_geo_check(tx):
        rule_hits.append("high_risk_country")
    if cash_like_check(tx):
        rule_hits.append("cash_like_or_high_risk_merchant_category")

    prompt = {
        "transaction": tx.model_dump(),
        "rule_hits": rule_hits,
        "lending_context": {
            "purpose": "transaction monitoring for borrower behavior",
            "requirements": ["auditability", "compliance review", "data residency awareness"],
        },
        "output_schema": MonitoringResult.model_json_schema(),
    }

    result = user_proxy.initiate_chat(
        assistant,
        message=json.dumps(prompt),
        max_turns=2,
    )
    return result

tx = Transaction(
    borrower_id="B12345",
    tx_id="T98765",
    amount=12000,
    channel="wire",
    merchant_category="money_transfer",
    country="NG",
    timestamp="2026-04-21T10:15:00Z",
    description="Outgoing transfer"
)

chat_result = monitor_transaction(tx)
print(chat_result)

4) Parse the output and enforce downstream actions

Do not trust free-form text in production. Validate the assistant output against your schema before creating a case or blocking activity.

import json

def extract_monitoring_result(raw_text: str) -> MonitoringResult:
    payload = json.loads(raw_text)
    return MonitoringResult(**payload)

def decide_action(result: MonitoringResult) -> str:
    if result.risk_level == "high":
        return f"BLOCK_AND_ESCALATE: {result.recommended_action}"
    if result.risk_level == "medium":
        return f"REVIEW_QUEUE: {result.recommended_action}"
    return f"ALLOW: {result.recommended_action}"

Production Considerations

  • Keep PII inside your boundary

    • Mask account numbers, names, and addresses before sending context to the model.
    • For lending portfolios with residency requirements, route data to region-specific inference endpoints.
  • Separate rules from judgment

    • Hard compliance rules should block or escalate independently of the agent.
    • Use the agent to summarize evidence and classify ambiguous cases.
  • Log everything needed for audit

    • Store input features, rule hits, prompt version, model version, output JSON, and final disposition.
    • Regulators will ask why a transaction was flagged; “the model said so” is not enough.
  • Monitor drift by portfolio segment

    • Watch false positives by product type: personal loans behave differently from SME lending.
    • Track approval/decline outcomes against later delinquency or charge-off signals.

Common Pitfalls

  • Letting the LLM make final compliance decisions

    • Avoid using AutoGen as the control plane for blocking funds.
    • Put deterministic policy checks in code first; let the agent assist with triage and explanation.
  • Sending raw sensitive data into prompts

    • Do not pass full statements with names and account numbers unless you have explicit controls.
    • Tokenize identifiers and redact unnecessary fields before calling initiate_chat.
  • Using unstructured outputs in production

    • Free-text responses break downstream automation.
    • Force JSON output with a strict schema like MonitoringResult, then validate it before any action is taken.

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