RAG Banking Regulatory MCP Server
by bilelammouri
README.md
# 🏦 RAG Banking Regulatory Agent — V.2.0 (POC Industrialisé)






> **Agent IA orchestrant plusieurs LLM gratuits (Ollama, Gemini) sur un corpus de réglementation bancaire française/européenne, avec support MCP (serveur + client) et déploiement cloud-ready (Docker, Kubernetes, CI/CD, monitoring).**
> ⚠️ **Statut : POC / Démonstration technique.** Ce projet illustre des patterns d'ingénierie IA (RAG hybride, routage LLM, MCP, observabilité). Il n'est pas destiné à un usage en production bancaire sans revue de sécurité complémentaire. Voir [SECURITY.md](./SECURITY.md).
Ce projet part d'un pipeline RAG simple (scripts `ingest.py` / `query.py` / `evaluate.py`) et le transforme en **agent industrialisé** :
- 🧠 **Orchestration LLM** : routage intelligent + fallback automatique entre Ollama (gratuit, local), Gemini (palier gratuit) et OpenAI (optionnel, payant)
- 🔌 **MCP (Model Context Protocol)** : le RAG est exposé comme **serveur MCP** (utilisable depuis Claude Desktop ou tout client MCP), et l'agent peut consommer des **serveurs MCP externes** comme outils
- 🌐 **API REST** (FastAPI) avec authentification par clé, endpoints de santé et métriques Prometheus
- 🐳 **Conteneurisation** complète (Docker multi-stage, docker-compose)
- ☸️ **Cloud-ready** : manifestes Kubernetes (Deployment, HPA, PDB, Ingress, ConfigMap/Secret)
- 🔁 **CI/CD** : GitHub Actions (lint → tests → build → push registre → déploiement K8s)
- 📊 **Observabilité** : logs structurés JSON (structlog), métriques Prometheus, dashboards Grafana
---
## 🏗️ Architecture
```
┌─────────────────────────────────────────┐
│ Clients │
│ API REST · Claude Desktop (MCP) · │
│ Autres agents MCP │
└───────────────┬───────────────────────────┘
│
┌──────────────────────────┼──────────────────────────┐
▼ ▼ │
┌───────────────────┐ ┌────────────────────────┐ │
│ API FastAPI │ │ Serveur MCP │ │
│ /query /ingest │ │ rag_search / rag_answer│ │
│ /health /metrics │ └────────────┬────────────┘ │
└──────────┬──────────┘ │ │
└──────────────┬──────────────┘ │
▼ │
┌─────────────────────────┐ ┌──────────────────────────┐
│ Orchestrateur (Agent) │◀──────▶│ Client MCP (outils │
│ - retrieval RAG │ │ externes : web, fichiers,│
│ - sélection d'outil │ │ Slack, Drive...) │
│ - construction prompt │ └──────────────────────────┘
└────────────┬──────────────┘
▼
┌─────────────────────────┐
│ RAG Retriever │
│ FAISS (dense) + BM25 │
│ (sparse) → RRF fusion │
└────────────┬──────────────┘
▼
┌─────────────────────────────────────┐
│ LLM Router │
│ Stratégie: cost_first / quality_first│
│ Ollama (gratuit) → Gemini → OpenAI │
│ Fallback automatique en cascade │
└───────────────┬───────────────────────┘
▼
Réponse citant ses sources
[Document.pdf, p. X]
```
### Décision de routage LLM
Le `LLMRouter` (`src/rag_agent/llm/router.py`) choisit le backend selon `LLM_ROUTING_STRATEGY` :
| Stratégie | Ordre d'essai | Cas d'usage |
|---|---|---|
| `cost_first` (défaut) | Ollama → Gemini → OpenAI | Minimiser les coûts, tout en gardant un filet de sécurité qualité |
| `quality_first` | Gemini → Ollama → OpenAI | Prioriser la qualité de réponse |
| `ollama_only` | Ollama uniquement | Confidentialité maximale (aucune donnée ne sort du réseau local) |
| `gemini_only` | Gemini uniquement | Pas d'infrastructure Ollama disponible |
| `round_robin` | Alterne à chaque appel | Répartition de charge / comparaison A/B |
Si le backend prioritaire échoue (indisponible, timeout, quota dépassé), le router **retente automatiquement** le suivant dans la cascade — chaque tentative est journalisée (`llm_provider_failed`, `llm_call_succeeded`) pour l'observabilité.
---
## 📂 Structure du projet
```
rag-banking-agent/
├── src/rag_agent/
│ ├── config.py # Configuration centralisée (pydantic-settings)
│ ├── logging_config.py # Logs structurés JSON (structlog)
│ ├── cli.py # CLI unifié (ingest/query/evaluate/serve/mcp-serve)
│ ├── llm/ # ── Orchestration LLM ──
│ │ ├── base.py # Interface commune (Strategy pattern)
│ │ ├── ollama_provider.py # Backend gratuit local
│ │ ├── gemini_provider.py # Backend API gratuit
│ │ ├── openai_provider.py # Backend optionnel (payant)
│ │ └── router.py # Choix + fallback automatique
│ ├── rag/ # ── Pipeline RAG ──
│ │ ├── ingest.py # Parsing → chunking → embeddings → FAISS
│ │ ├── retrieval.py # Dense + BM25 + RRF
│ │ └── prompts.py # Prompt système (citation + abstention)
│ ├── agent/ # ── Orchestrateur ──
│ │ ├── orchestrator.py # RAG + outils + LLM router, façade unique
│ │ └── tools.py # Registre d'outils (RAG, MCP externes)
│ ├── mcp/ # ── Model Context Protocol ──
│ │ ├── server.py # Expose le RAG comme serveur MCP
│ │ └── client.py # Consomme des serveurs MCP externes
│ ├── api/ # ── API REST ──
│ │ ├── main.py, routes/, schemas.py, metrics.py, dependencies.py
│ └── evaluation/ # ── Évaluation ──
│ ├── test_set.py # 15 questions de test
│ └── evaluate.py # Precision@k + fidélité + provider utilisé
├── tests/ # Tests unitaires + intégration API (pytest)
├── deploy/
│ ├── docker/ # Dockerfiles (API + MCP), multi-stage
│ ├── docker-compose.yml # Environnement complet local
│ ├── k8s/ # Manifestes Kubernetes (cloud-ready)
│ └── monitoring/ # Config Prometheus
├── .github/workflows/ci-cd.yml # Pipeline complet
├── scripts/download_corpus.py # Téléchargement + génération corpus synthétique
├── Makefile # Raccourcis de commandes
└── requirements.txt / requirements-dev.txt
```
---
## 🚀 Démarrage rapide (local, sans Docker)
```bash
# 1. Installation (Linux/Mac)
python -m venv .venv && source .venv/bin/activate
make install-dev
# Windows :
# python -m venv .venv && .venv\Scripts\Activate.ps1
# pip install -r requirements.txt
# 2. Configuration
cp .env.example .env
# Éditer .env : renseigner GEMINI_API_KEY (palier gratuit sur https://aistudio.google.com/apikey)
# et/ou installer Ollama (https://ollama.com) + `ollama pull mistral`
# 3. Préparer le corpus
make download-corpus
# 4. Indexer
make ingest
# 5. Interroger l'agent en CLI
make query Q="Quel est le ratio minimum de CET1 imposé par Bâle III ?"
# 6. Lancer l'API
make serve
# → http://localhost:8000/docs (Swagger UI)
# 7. Lancer le serveur MCP (ex: pour Claude Desktop)
make mcp-serve
```
### Évaluation
```bash
make evaluate
# → Precision@k, score de fidélité (recouvrement de mots-clés), taux d'abstention,
# répartition de l'usage par provider LLM (utile pour arbitrer coût/qualité)
```
---
## 🐳 Démarrage avec Docker Compose (API + MCP + Ollama + monitoring)
```bash
export GEMINI_API_KEY=your_key_here # optionnel mais recommandé en secours
docker compose -f deploy/docker-compose.yml up --build -d
# Télécharger le modèle Ollama dans le conteneur
docker compose -f deploy/docker-compose.yml exec ollama ollama pull mistral
# Indexer le corpus (monté dans le conteneur API)
curl -X POST localhost:8000/ingest
# Interroger
curl -X POST localhost:8000/query -H "Content-Type: application/json" \
-d '{"question": "Quelles sont les obligations LCB-FT des banques françaises ?"}'
```
Accès :
- API + Swagger : http://localhost:8000/docs
- Prometheus : http://localhost:9090
- Grafana : http://localhost:3000 (admin/admin)
- Serveur MCP (SSE) : http://localhost:8765
---
## ☸️ Déploiement Kubernetes
```bash
# 1. Construire et pousser les images (ou laisser le CI/CD s'en charger)
docker build -f deploy/docker/Dockerfile -t ghcr.io/your-org/rag-banking-agent-api:latest .
docker build -f deploy/docker/Dockerfile.mcp -t ghcr.io/your-org/rag-banking-agent-mcp:latest .
# 2. Configurer les secrets (NE PAS committer les valeurs réelles)
cp deploy/k8s/secret.example.yaml deploy/k8s/secret.yaml
# éditer secret.yaml avec les vraies clés, puis :
kubectl apply -f deploy/k8s/secret.yaml
# 3. Déployer le reste
make k8s-apply
```
Le déploiement inclut :
- **2 replicas minimum** de l'API avec `HorizontalPodAutoscaler` (2→8 selon CPU/mémoire)
- **PodDisruptionBudget** pour rester disponible pendant les mises à jour de nœuds
- **Liveness/Readiness probes** sur `/health/live` et `/health/ready`
- **PersistentVolumeClaims** partagés (`ReadWriteMany`) pour l'index FAISS et le corpus
- **Ingress** TLS (via cert-manager) pour l'exposition externe
- Le pipeline CI/CD (`.github/workflows/ci-cd.yml`) automatise build/push/déploiement à chaque merge sur `main`
---
## 🔌 Utilisation via MCP
### Comme serveur MCP (le RAG exposé à Claude Desktop ou tout client MCP)
Ajouter dans la configuration MCP du client (ex: `claude_desktop_config.json`) :
```json
{
"mcpServers": {
"rag-banking-regulatory": {
"command": "python",
"args": ["-m", "rag_agent.mcp.server"],
"env": { "PYTHONPATH": "/chemin/vers/rag-banking-agent/src" }
}
}
}
```
Deux outils sont alors disponibles : `rag_search` (extraits bruts + sources) et `rag_answer` (réponse complète avec citations).
### Comme client MCP (l'agent utilise des outils externes)
Configurer `MCP_CLIENT_SERVERS_JSON` dans `.env` :
```json
[{"name": "filesystem", "url": "http://localhost:8001/sse"}]
```
L'agent peut alors enregistrer un `Tool` (voir `agent/tools.py`) qui invoque ce serveur via `MCPClientManager.call_tool(...)`, et le déclencher automatiquement selon des mots-clés (extensible vers un routage piloté par LLM/function-calling).
---
## ⚠️ Limites connues et pistes d'évolution
| Limite | Détail | Piste |
|---|---|---|
| Routage par mots-clés | Le choix d'outil MCP est heuristique, pas piloté par le LLM | Passer à un function-calling structuré (JSON schema) piloté par le LLM |
| Corpus de démo | ~5 documents synthétiques + 2 PDF publics | Étendre à un corpus réel de circulaires ACPR |
| Ingestion synchrone | `/ingest` bloque la requête HTTP | Passer en job asynchrone (Celery/Argo Workflows) avec suivi de statut |
| Ollama en K8s | Nécessite un nœud avec assez de CPU/RAM (voire GPU) | Prévoir un `nodeSelector`/GPU pool dédié pour les modèles plus lourds |
| Pas de cache de réponses | Chaque question relance retrieval + LLM | Ajouter un cache sémantique (Redis + embeddings) pour les questions fréquentes |
| FAISS IndexFlatIP | Recherche exhaustive O(n) | Passer à IndexIVFFlat ou HNSW pour +100K vecteurs |
## 📂 Fichiers importants
| Fichier | Rôle |
|---|---|
| [SECURITY.md](./SECURITY.md) | Politique de sécurité et risques connus (POC) |
| [CONTRIBUTING.md](./CONTRIBUTING.md) | Guide de contribution et standards de code |
| [.env.example](./.env.example) | Variables d'environnement (avec avertissements) |
| [guide\_local\_use.md](./guide_local_use.md) | Guide d'utilisation locale + 6 flux I/O détaillés |
## 📜 Licence & Sources
- **Code** : MIT
- **Corpus** : documents publics (ACPR, Banque de France, EBA) + documents synthétiques clairement labellisés `Synthetic_*`. Aucune donnée client ou confidentielle.
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues