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
This project is a production-ready, portfolio-grade implementation of an autonomous financial analysis agent. It combines two powerful paradigms:
-
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.
-
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.
- Built with
langchaincreate_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
| 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 |
| 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 |
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.)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 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 β
ββββββββββββββββββββ βββββββββββββββββββ ββββββββββββββββββββββ
- Python 3.11+
- An OpenAI API key with GPT-4o-mini access
# 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.csvpython main.pyββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 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.
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
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 / β¦ |
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]
| 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) |
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
| 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 |
This project is licensed under the MIT License β see the LICENSE file for details.
- German Credit Dataset β UCI Machine Learning Repository
- LangChain ReAct Agent documentation
- Gower distance paper β Gower (1971)
- K-Medoids (PAM) β scikit-learn-extra