Skip to content

Latest commit

Β 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🏦 Autonomous Customer Profiling & Financial Clustering Agent

Python LangChain OpenAI scikit-learn License: MIT

An autonomous AI agent that segments banking customers using advanced unsupervised ML and evaluates new credit applications β€” powered by the LangChain ReAct architecture.

Features Β· Architecture Β· Installation Β· Usage Β· Project Structure Β· How It Works


🌟 Overview

This project is a production-ready, portfolio-grade implementation of an autonomous financial analysis agent. It combines two powerful paradigms:

  1. LangChain ReAct (Reasoning + Acting) β€” the agent reasons about what to do, picks the right tool, observes the result, and loops until it has a complete answer. Every Thought, Action, and Observation is fully visible.

  2. Mixed-Data Clustering with Gower Distance + K-Medoids β€” because real-world credit datasets contain both numerical (age, credit amount) and categorical (purpose, housing status) features, standard k-means fails. This project uses a statistically rigorous two-stage approach: Gower Distance matrix β†’ K-Medoids (PAM) clustering.

The result: an agent that can autonomously process raw data, discover hidden borrower profiles, and deliver an executive-grade risk opinion on any new applicant.


✨ Features

πŸ€– Autonomous ReAct Agent

  • Built with langchain create_react_agent + AgentExecutor
  • Full Thought β†’ Action β†’ Observation reasoning trace printed in real-time
  • Custom Senior Financial Analyst persona baked into the system prompt
  • Graceful error handling and self-correction via handle_parsing_errors
  • Hard iteration cap to prevent runaway loops

πŸ“Š Advanced Mixed-Data Clustering Pipeline

Stage Technique Why
Missing value imputation "Unknown" category + median for numerics Preserves signal in 'Saving accounts' (18.3% NaN) and 'Checking account' (39.4% NaN)
Categorical encoding Ordinal (savings/checking) + One-Hot (nominal) Respects natural ordering of account levels
Feature scaling MinMaxScaler β†’ [0, 1] Required for Gower distance calculation
Distance metric Gower Distance Handles mixed types natively (Manhattan for num, Dice for binary)
Clustering algorithm K-Medoids (PAM) Uses real data-points as centroids β†’ interpretable and outlier-robust

πŸ”§ Three Specialised LangChain Tools

Tool Responsibility
preprocess_german_credit_data Load β†’ Impute β†’ Validate β†’ Save cleaned CSV
train_mixed_data_clustering Encode β†’ Scale β†’ Gower Matrix β†’ K-Medoids β†’ Profile clusters
analyze_new_customer Load pipeline β†’ Transform new row β†’ Nearest-neighbour cluster assignment β†’ Risk report

πŸ’Ύ Persistent Model Artefacts

models/
β”œβ”€β”€ clustering_pipeline.joblib   # Fitted encoders, scaler, K-Medoids model
β”œβ”€β”€ preprocessed_data.csv        # Cleaned training data
β”œβ”€β”€ clustered_customers.csv      # Training data + cluster labels
└── cluster_profiles.json        # Per-cluster statistics (mean age, top purpose, etc.)

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         main.py                                  β”‚
β”‚   AgentExecutor.invoke({"input": complex_query})                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
                            β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   ReAct Agent Loop                               β”‚
β”‚                                                                  β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚   β”‚  Thought β”‚ β†’  β”‚    Action    β”‚ β†’  β”‚     Tool Call        β”‚  β”‚
β”‚   β”‚ (GPT-4o) β”‚    β”‚ (tool name)  β”‚    β”‚  (Python function)   β”‚  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚        β–²                                          β”‚              β”‚
β”‚        └──────────── Observation β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β–Ό                 β–Ό                  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Tool 1          β”‚ β”‚  Tool 2         β”‚ β”‚  Tool 3            β”‚
β”‚  preprocess_     β”‚ β”‚  train_mixed_   β”‚ β”‚  analyze_new_      β”‚
β”‚  german_credit_  β”‚ β”‚  data_          β”‚ β”‚  customer          β”‚
β”‚  data            β”‚ β”‚  clustering     β”‚ β”‚                    β”‚
β”‚                  β”‚ β”‚                 β”‚ β”‚                    β”‚
β”‚  pandas impute   β”‚ β”‚  Gower matrix   β”‚ β”‚  Load pipeline     β”‚
β”‚  save clean CSV  β”‚ β”‚  K-Medoids PAM  β”‚ β”‚  Gower NN search   β”‚
β”‚                  β”‚ β”‚  save pipeline  β”‚ β”‚  Risk report       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“¦ Installation

Prerequisites

  • Python 3.11+
  • An OpenAI API key with GPT-4o-mini access

Steps

# 1. Clone the repository
git clone https://github.com/MelihOrel/Autonomous-Customer-Profiling-Financial-Clustering-Agent.git
cd Autonomous-Customer-Profiling-Financial-Clustering-Agent

# 2. Create and activate a virtual environment
python -m venv .venv
source .venv/bin/activate       # macOS / Linux
# .venv\Scripts\activate        # Windows

# 3. Install all dependencies
pip install -r requirements.txt

# 4. Configure your API key
cp .env.example .env
# Open .env and paste your OPENAI_API_KEY

# 5. Verify the dataset is in place
ls data/german_credit_data.csv

πŸš€ Usage

python main.py

Expected terminal output

╔══════════════════════════════════════════════════════════════════════╗
β•‘   AUTONOMOUS CUSTOMER PROFILING & FINANCIAL CLUSTERING AGENT        β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

  Initialising ReAct agent…

╔══════════════════════════════════════════════════════════════════════╗
β•‘                       SUBMITTING QUERY TO AGENT                     β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

  Load the dataset at 'data/german_credit_data.csv' and preprocess it.
  Then, segment the customers using a mixed-data clustering algorithm
  (Gower Distance + K-Medoids) with 4 clusters...

> Entering new AgentExecutor chain...

Thought: I need to start by preprocessing the dataset before I can
         train the clustering model or analyse any new customer.
Action: preprocess_german_credit_data
Action Input: data/german_credit_data.csv

Observation:
╔══════════════════════════════════════════════════════════╗
β•‘         PREPROCESSING REPORT – German Credit Data        β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
  Dataset shape       : 1,000 rows Γ— 9 columns

  Missing values BEFORE imputation:
    β€’ Saving accounts       :  183 (18.3%)
    β€’ Checking account      :  394 (39.4%)

  Missing values AFTER imputation:
    β€’ Total remaining  : 0 βœ…
  ...

Thought: Preprocessing complete. Now I'll train the clustering model.
Action: train_mixed_data_clustering
Action Input: 4

Observation:
╔══════════════════════════════════════════════════════════╗
β•‘       CLUSTERING TRAINING REPORT – K-Medoids / Gower    β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
  Algorithm : K-Medoids (PAM) + Gower Distance
  Clusters  : 4
  Samples   : 1,000

============================================================
  Cluster 0  (n=287)
============================================================
  Avg Age           : 38.4 yrs
  Avg Credit Amount : €2,134
  Avg Loan Duration : 16.2 months
  Top Purpose       : radio/TV
  Risk Assessment   : βœ… LOW RISK – established customers...

  Cluster 1  (n=198)
  ...

Thought: Training complete. Now I'll analyse the new applicant.
Action: analyze_new_customer
Action Input: {"Age": 24, "Sex": "male", "Job": 2, "Housing": "rent",
               "Saving accounts": "little", "Checking account": "moderate",
               "Credit amount": 4500, "Duration": 36, "Purpose": "business"}

Observation:
╔══════════════════════════════════════════════════════════╗
β•‘          NEW CUSTOMER ANALYSIS – CLUSTER ASSIGNMENT      β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

  Assigned Cluster ID  : 2
  Cluster Size         : 243 historical customers
  ...
  Risk Assessment   : ⚑ MEDIUM RISK – moderate financial stability
  ...
  CAUTION ADVISED. Applicant is 14 years younger than typical cluster
  member β†’ limited credit history likely. Credit amount €4,500 is
  €1,200 above cluster average β†’ elevated exposure.

Thought: I now have all the information needed for a complete answer.
Final Answer: ...

╔══════════════════════════════════════════════════════════════════════╗
β•‘                       FINAL AGENT RESPONSE                          β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

  The 24-year-old male applicant requesting €4,500 over 36 months for
  a business purpose has been assigned to Cluster 2, which represents
  younger borrowers with limited savings and moderate checking balances
  seeking larger business or education loans...

  βœ…  Pipeline artefacts written to: models/
  βœ…  Run complete.

πŸ“ Project Structure

autonomous-credit-agent/
β”‚
β”œβ”€β”€ agents/
β”‚   β”œβ”€β”€ __init__.py
β”‚   └── react_agent.py          # ReAct agent factory (LLM + tools + prompt)
β”‚
β”œβ”€β”€ tools/
β”‚   β”œβ”€β”€ __init__.py
β”‚   └── clustering_tools.py     # 3 LangChain @tool functions
β”‚
β”œβ”€β”€ data/
β”‚   └── german_credit_data.csv  # Raw dataset (1,000 customers, 9 features)
β”‚
β”œβ”€β”€ models/                     # Auto-created on first run
β”‚   β”œβ”€β”€ clustering_pipeline.joblib
β”‚   β”œβ”€β”€ preprocessed_data.csv
β”‚   β”œβ”€β”€ clustered_customers.csv
β”‚   └── cluster_profiles.json
β”‚
β”œβ”€β”€ notebooks/                  # (Optional) EDA notebooks
β”‚
β”œβ”€β”€ main.py                     # Entry point
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ .env.example                # Template for API key config
β”œβ”€β”€ .gitignore
└── README.md

🧠 How It Works

1. Dataset

The German Credit Dataset contains 1,000 historical loan applicants with 9 features:

Feature Type Notes
Age Numerical Customer age in years
Sex Categorical male / female
Job Ordinal (0–3) 0 = unskilled, 3 = highly skilled
Housing Categorical own / rent / free
Saving accounts Ordinal little / moderate / quite rich / rich
Checking account Ordinal little / moderate / rich
Credit amount Numerical Loan amount in Deutsche Marks
Duration Numerical Loan duration in months
Purpose Categorical car / radio/TV / education / business / …

2. Why Gower Distance?

Standard distance metrics (Euclidean, Manhattan) cannot meaningfully combine numerical and categorical variables. Gower Distance solves this:

  • For numerical columns: normalised Manhattan distance
  • For categorical/binary columns: Dice similarity (0 if same, 1 if different)
  • The final distance is a weighted average across all features β†’ values in [0, 1]

3. Why K-Medoids over K-Means?

Property K-Means K-Medoids (PAM)
Centroid type Abstract mean vector Actual data point
Outlier robustness Low High
Mixed data support ❌ (needs precomputed matrix) βœ… (metric="precomputed")
Interpretability Low High (medoid = representative customer)

4. ReAct Loop

The agent uses chain-of-thought prompting inside the ReAct loop:

Thought  β†’ "I need to preprocess first, then train, then infer"
Action   β†’ preprocess_german_credit_data("data/german_credit_data.csv")
Obs      β†’ "1,000 rows cleaned, 0 nulls remaining…"
Thought  β†’ "Good, now train clustering…"
Action   β†’ train_mixed_data_clustering(4)
Obs      β†’ "4 clusters discovered…"
Thought  β†’ "Now analyse the new applicant…"
Action   β†’ analyze_new_customer({...})
Obs      β†’ "Assigned to Cluster 2, MEDIUM RISK…"
Thought  β†’ "I now have a complete answer."
Final    β†’ Executive risk report

πŸ”¬ Extending the Project

Idea How
Add a visualize_clusters tool Use UMAP β†’ 2D plot saved as PNG
Swap to K-Prototypes Replace Gower+KMedoids with kmodes.KPrototypes
Add LangSmith tracing Set LANGCHAIN_TRACING_V2=true in .env
Use GPT-4o for deeper reasoning Change model_name="gpt-4o" in main.py
REST API wrapper Wrap main.py logic with FastAPI
CI/CD Add GitHub Actions with pytest for tool unit tests

πŸ“„ License

This project is licensed under the MIT License β€” see the LICENSE file for details.


πŸ™ Acknowledgements


Built as a portfolio-grade demonstration of autonomous AI agents + advanced unsupervised learning for financial risk analysis.

About

πŸ€– An autonomous AI agent designed for end-to-end financial data clustering and customer profiling. Powered by LLMs and unsupervised machine learning, it automatically analyzes financial datasets, segments users, and generates data-driven, human-readable personas for targeted business strategies. πŸ“ŠπŸ’Ό

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages