An adversarial, multi-agent fraud detection pipeline for bank transactions. Instead of relying on a single classifier, a transaction is scored by two independent "expert" agents — one reasoning over historical behavioral patterns, one reasoning over semantic/contextual signals — whose findings are reconciled by a decider agent into a final risk score and action. The goal is fewer false positives and less friction (e.g. unnecessary 2FA challenges) for legitimate users, while still catching fraud.
- Pattern Expert (
src/ensemble/) — an ensemble of gradient-boosted models (XGBoost, LightGBM; a TabNet head is present but currently disabled) trained on the CIFER fraud dataset, producing a numeric risk score from transaction features. An LLM then explains/contextualizes that score. - Semantic Expert (
src/semantic_agent.py) — looks up the sender's recent transaction history in PostgreSQL to build a "digital footprint," then uses an LLM to judge how consistent the new transaction is with that history. - Decider Agent (
src/decider_agent.py) — an LLM judge that reconciles the pattern and semantic risk scores/analyses into afinal_risk_scoreand a decision:>= 0.7→ Flag for review>= 0.4→ Require human verification (e.g. 2FA)< 0.4→ Allow
Each expert is implemented as its own LangGraph graph, orchestrated from main.py.
.
├── app.py # Streamlit UI
├── main.py # CLI entry point / pipeline wiring
├── requirements.txt # pip dependencies
├── environment.yml # conda environment (mirrors requirements.txt)
└── src/
├── decider_agent.py # final risk assessment graph
├── semantic_agent.py # semantic expert graph
├── ensemble/
│ ├── ensemble_agent.py # pattern expert graph
│ ├── ensemble_model.py # weighted XGBoost/LightGBM ensemble
│ ├── helper/ # preprocessing + metrics helpers
│ └── models/ # trained model artifacts (.pkl / .pt)
└── utils/
├── database.py # SQLAlchemy engine/session
├── models.py # `transactions` ORM model
├── nodes.py # LangGraph node implementations
├── prompts.py # LLM prompt templates
└── states.py # LangGraph state schemas
- Python 3.13
- A PostgreSQL database containing a
transactionstable (seesrc/utils/models.pyfor the schema) populated with historical transactions - An OpenAI API key
Using conda:
conda env create -f environment.yml
conda activate fintech-hackathonOr with pip:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtCreate a .env file in the project root (this file is gitignored — never commit it):
OPENAI_API_KEY=sk-...
POSTGRES_DB_URL=postgresql://<user>:<password>@<host>/<database>
streamlit run app.pyPaste a transaction as JSON and click Analyze Transaction to see the semantic and pattern analyses plus the final decision.
python main.pyRuns the pipeline against the sample transaction defined in main.py. To use programmatically:
from main import semantic_pattern_adverserial_analysis
result = semantic_pattern_adverserial_analysis({
"nameOrig": "C123456789",
"type": "TRANSFER",
"amount": 8500.0,
"oldbalanceOrg": 9000.0,
"newbalanceOrig": 500.0,
"nameDest": "C987654321",
"oldbalanceDest": 10000.0,
"newbalanceDest": 18500.0,
})MIT — see LICENSE.
