How to Build a transaction monitoring Agent Using LlamaIndex in Python for lending
A transaction monitoring agent for lending watches borrower and account activity, scores suspicious patterns, and explains why a case needs review. In lending, that matters because you are not just catching fraud; you are protecting underwriting quality, meeting compliance obligations, and creating an audit trail that can stand up to internal review or regulator scrutiny.
Architecture
- •Transaction ingestion layer
- •Pulls payments, disbursements, chargebacks, ACH returns, and account events from your core banking or loan servicing system.
- •Feature normalization layer
- •Converts raw transactions into a consistent schema: amount, velocity, merchant category, repayment status, delinquency flags, geography, and device metadata.
- •LlamaIndex retrieval layer
- •Uses
VectorStoreIndexplusQueryEngineto retrieve policy docs, lending rules, prior case notes, and historical alerts.
- •Uses
- •Decisioning agent
- •Uses an LLM-backed
ReActAgentor query engine to classify risk, summarize evidence, and recommend escalation.
- •Uses an LLM-backed
- •Case management output
- •Writes structured alerts into your workflow system with reason codes and supporting evidence.
- •Audit and controls
- •Stores prompts, retrieved context, model outputs, and final decisions for traceability.
Implementation
1) Define the transaction schema and load policy context
You want the agent to reason over both live transaction data and your lending policies. Keep the transaction payload structured and keep policy documents indexed separately.
from dataclasses import dataclass
from typing import List
from llama_index.core import VectorStoreIndex, Document
from llama_index.core.settings import Settings
from llama_index.llms.openai import OpenAI
@dataclass
class Transaction:
txn_id: str
borrower_id: str
amount: float
txn_type: str
channel: str
country: str
days_past_due: int
is_chargeback: bool = False
policy_docs = [
Document(text="Flag borrowers with >3 failed repayment attempts in 30 days."),
Document(text="Escalate if cash advance behavior appears after disbursement."),
Document(text="Review cross-border repayments against residency restrictions."),
]
Settings.llm = OpenAI(model="gpt-4o-mini")
policy_index = VectorStoreIndex.from_documents(policy_docs)
policy_query_engine = policy_index.as_query_engine(similarity_top_k=2)
2) Build a risk assessment function with retrieval-backed reasoning
The pattern here is simple: retrieve the relevant lending rules first, then ask the model to assess a single transaction against those rules. That keeps outputs grounded in your policy corpus.
def assess_transaction(txn: Transaction) -> str:
query = (
f"Evaluate this lending transaction for monitoring risk:\n"
f"txn_id={txn.txn_id}\n"
f"borrower_id={txn.borrower_id}\n"
f"amount={txn.amount}\n"
f"txn_type={txn.txn_type}\n"
f"channel={txn.channel}\n"
f"country={txn.country}\n"
f"days_past_due={txn.days_past_due}\n"
f"is_chargeback={txn.is_chargeback}\n"
"Return a concise risk assessment with reason codes."
)
policy_context = policy_query_engine.query(
"What lending monitoring rules apply to repayment anomalies, chargebacks, "
"cross-border activity, and post-disbursement cash movement?"
)
prompt = f"""
Policy context:
{policy_context}
Transaction:
{query}
Output format:
- risk_level: low|medium|high
- reason_codes: comma-separated list
- summary: one short paragraph
"""
return Settings.llm.complete(prompt).text
sample_txn = Transaction(
txn_id="TXN-10021",
borrower_id="B-4421",
amount=1250.0,
txn_type="repayment",
channel="ach",
country="KE",
days_past_due=18,
)
print(assess_transaction(sample_txn))
3) Turn it into an agent that can answer analyst questions
If your ops team wants interactive investigation, wrap the retrieval engine in a ReActAgent. This gives analysts a natural-language interface while still grounding answers in indexed policy material.
from llama_index.core.agent import ReActAgent
tools = [
policy_query_engine.as_tool(
name="lending_policy_lookup",
description="Look up lending monitoring rules and escalation criteria."
)
]
agent = ReActAgent.from_tools(
tools=tools,
llm=Settings.llm,
verbose=True,
)
response = agent.chat(
"For a borrower who made three small repayments followed by a large cash withdrawal "
"two days after disbursement, what should the monitoring team do?"
)
print(response)
4) Emit structured alerts for downstream case management
Do not send free-form text into your case system. Convert the model output into a strict structure so you can route alerts consistently.
import json
def create_alert(txn: Transaction) -> dict:
result_text = assess_transaction(txn)
alert = {
"transaction_id": txn.txn_id,
"borrower_id": txn.borrower_id,
"risk_assessment": result_text,
"source": "llamaindex-monitoring-agent",
"status": "open",
}
return alert
alert = create_alert(sample_txn)
print(json.dumps(alert, indent=2))
Production Considerations
- •Deploy in-region for data residency
- •Lending data often has residency constraints. Keep embeddings, vector stores, and LLM endpoints in approved regions.
- •Log every decision path
- •Store retrieved policy chunks from
QueryEngine, prompt text, model output, timestamp, and analyst override. That is your audit trail.
- •Store retrieved policy chunks from
- •Add guardrails around adverse actions
- •The agent should recommend review or escalation only. It should not make final credit decisions without human approval.
- •Monitor drift on transaction patterns
- •Repayment behavior changes by geography and product type. Track false positives by cohort so you do not bury analysts in noise.
Common Pitfalls
- •
Using raw LLM output as the source of truth
- •Avoid this by forcing structured fields like
risk_level,reason_codes, andsummary. Parse or validate before writing to your case system.
- •Avoid this by forcing structured fields like
- •
Mixing policy docs with noisy transactional history in one index
- •Keep policies separate from event data. Policy retrieval should be stable; transaction facts should come from your operational database or feature store.
- •
Ignoring explainability requirements
- •Every alert needs a clear reason chain: which rule triggered, which facts were observed, and what evidence was retrieved. If you cannot explain it to compliance or audit, it is not production-ready.
- •
Letting the agent see unnecessary personal data
- •Minimize PII before indexing or prompting. Mask account numbers, addresses, and identifiers unless they are required for the decision path.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
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