How to Build a transaction monitoring Agent Using LangChain in Python for insurance

By Cyprian AaronsUpdated 2026-04-21
transaction-monitoringlangchainpythoninsurance

A transaction monitoring agent for insurance watches policy payments, claims payouts, refunds, and premium adjustments for patterns that look abnormal, risky, or non-compliant. It matters because insurers need to catch fraud, duplicate payments, money laundering signals, and operational errors early while keeping a clean audit trail for regulators and internal review.

Architecture

  • Data ingestion layer
    • Pulls transactions from policy admin systems, claims platforms, payment gateways, and data warehouses.
  • Normalization layer
    • Converts raw events into a consistent schema: customer_id, policy_id, amount, currency, channel, timestamp, and transaction_type.
  • Rules + LLM decision layer
    • Uses deterministic rules for hard checks and a LangChain agent for contextual assessment and explanation.
  • Evidence retrieval layer
    • Fetches prior claims history, policy status, KYC flags, and prior alerts using retrieval tools.
  • Audit logging layer
    • Stores every input, tool call, model output, and final decision for compliance review.
  • Case management output
    • Sends suspicious transactions to analysts with a reason code and supporting evidence.

Implementation

1. Define the transaction schema and risk rules

Keep the first pass deterministic. In insurance, you do not want an LLM inventing risk from thin air when a simple rule already catches it.

from dataclasses import dataclass
from typing import Optional

@dataclass
class InsuranceTransaction:
    transaction_id: str
    customer_id: str
    policy_id: str
    transaction_type: str   # premium_payment, claim_payout, refund
    amount: float
    currency: str
    channel: str            # bank_transfer, card, cash
    country: str
    timestamp: str

def rule_based_flags(txn: InsuranceTransaction) -> list[str]:
    flags = []

    if txn.amount >= 10000:
        flags.append("high_value_transaction")

    if txn.transaction_type == "refund" and txn.amount > 5000:
        flags.append("large_refund")

    if txn.channel == "cash":
        flags.append("cash_channel")

    if txn.country not in {"US", "GB", "DE", "ZA"}:
        flags.append("cross_border_risk")

    return flags

2. Build tools for evidence lookup

Use LangChain tools to fetch context from your internal systems. In production this is where you connect to policy history, claims history, sanctions screening results, or prior alerts.

from langchain_core.tools import tool

@tool
def get_policy_summary(policy_id: str) -> str:
    """Return a short policy summary for compliance review."""
    mock_db = {
        "POL123": "Active motor policy. Premium paid monthly. No lapse history.",
        "POL999": "Active life policy. Beneficiary recently changed.",
    }
    return mock_db.get(policy_id, "No policy record found.")

@tool
def get_prior_alerts(customer_id: str) -> str:
    """Return prior alert summary for the customer."""
    mock_alerts = {
        "CUST1": "2 prior alerts in last 90 days; both cleared by analyst.",
        "CUST7": "1 open fraud review; duplicate payout concern.",
    }
    return mock_alerts.get(customer_id, "No prior alerts found.")

3. Create a LangChain agent that explains risk with evidence

This pattern uses ChatOpenAI, create_tool_calling_agent, and AgentExecutor. The agent receives the normalized transaction plus rule flags and can call tools for evidence before producing a structured assessment.

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.agents import create_tool_calling_agent, AgentExecutor

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

prompt = ChatPromptTemplate.from_messages([
    ("system",
     "You are an insurance transaction monitoring analyst. "
     "Assess suspicious activity using only the provided data and tool results. "
     "Return concise findings with risk level and reason codes. "
     "Do not invent facts."),
    ("human",
     "Transaction:\n{transaction}\n\nRule flags:\n{rule_flags}"),
    MessagesPlaceholder(variable_name="agent_scratchpad"),
])

tools = [get_policy_summary, get_prior_alerts]
agent = create_tool_calling_agent(llm=llm, tools=tools, prompt=prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=False)

txn_text = (
    "transaction_id=T1001; customer_id=CUST7; policy_id=POL999; "
    "transaction_type=claim_payout; amount=12500; currency=USD; "
    "channel=bank_transfer; country=US; timestamp=2026-04-21T10:15:00Z"
)

result = executor.invoke({
    "transaction": txn_text,
    "rule_flags": ["high_value_transaction"]
})

print(result["output"])

4. Wrap it into a monitoring function with audit output

In insurance you need traceability. Store inputs, rule flags, tool outputs if available through your own logging wrapper, and the final decision.

import json
from datetime import datetime

def monitor_transaction(txn: InsuranceTransaction) -> dict:
    flags = rule_based_flags(txn)

    prompt_input = {
        "transaction": f"{txn}",
        "rule_flags": flags,
    }

    response = executor.invoke(prompt_input)

    audit_record = {
        "event_time": datetime.utcnow().isoformat(),
        "transaction_id": txn.transaction_id,
        "customer_id": txn.customer_id,
        "policy_id": txn.policy_id,
        "rule_flags": flags,
        "agent_output": response["output"],
        "decision": "review" if flags else "clear",
    }

    print(json.dumps(audit_record))
    return audit_record

Production Considerations

  • Keep deterministic controls first
    • Use rules for threshold checks, duplicate payouts, unusual refund patterns, and jurisdiction-based restrictions before calling the model.
  • Log everything needed for audit
    • Persist prompt inputs, tool calls, outputs, model version, timestamps, and analyst overrides.
    • Regulators will care about why the alert was raised.
  • Respect data residency
    • If policies or claims data cannot leave a region, keep the model endpoint in-region or use a private deployment.
    • Do not send raw PII unless your legal/compliance team has approved it.
  • Add human-in-the-loop review
    • For high-risk cases like large claim payouts or repeated refunds across related accounts, route to an analyst instead of auto-actioning.

Common Pitfalls

  • Letting the LLM make final decisions without guardrails
    • Avoid this by using rules to gate obvious cases and limiting the agent to explanation plus triage.
  • Passing raw sensitive data into prompts
    • Mask names, account numbers, addresses where possible.
    • Use tokenized identifiers so the model sees enough context without exposing unnecessary PII.
  • Skipping explainability
    • If you cannot show why an alert fired at audit time, the system is not production-ready.
    • Always return reason codes tied to concrete signals like high value transfer or prior alert history.

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