merithalle-ai / docs /ARCHITECTURE.md
Cyril Dupland
First Commit
bd44418
# Architecture du Projet
## Vue d'ensemble
Ce projet suit les principes de **Clean Architecture** et **SOLID** pour garantir:
- Maintenabilité
- Testabilité
- Extensibilité
- Séparation des responsabilités
## Structure des dossiers
```
routeur_ia_api/
├── config/ # Configuration
│ ├── __init__.py
│ └── settings.py # Settings avec pydantic-settings
├── core/ # Noyau de l'application
│ ├── __init__.py
│ ├── security.py # Authentification JWT
│ └── dependencies.py # Dépendances FastAPI
├── domain/ # Couche domaine (modèles métier)
│ ├── __init__.py
│ ├── enums.py # Enums (ModelName, AgentType, etc.)
│ └── models.py # Modèles Pydantic (DTO)
├── services/ # Couche service (logique métier)
│ ├── __init__.py
│ ├── llm_service.py # Factory LLM multi-providers
│ ├── agent_service.py # Orchestration des agents
│ ├── agent_registry.py # Registre des agents disponibles
│ └── transcription_service.py # Service Whisper
├── graphs/ # Graphes LangGraph
│ ├── __init__.py
│ ├── base_graph.py # Graphe conversationnel simple
│ └── README.md # Doc pour créer des graphes
├── api/ # Couche présentation (API)
│ ├── __init__.py
│ ├── routes/
│ │ ├── __init__.py
│ │ ├── auth.py # Routes authentification
│ │ ├── completion.py # Routes completion
│ │ ├── transcription.py # Routes transcription
│ │ ├── models.py # Routes liste modèles/agents
│ │ └── realtime.py # Routes WebSocket/WebRTC
│ └── middleware.py # Middleware personnalisé
└── app.py # Point d'entrée FastAPI
```
## Flux de données
```
┌─────────────┐
│ Client │
└──────┬──────┘
│ HTTP Request + JWT
┌─────────────────────────────────┐
│ FastAPI App │
│ ┌──────────────────────────┐ │
│ │ Security Middleware │ │
│ └──────────┬───────────────┘ │
│ ▼ │
│ ┌──────────────────────────┐ │
│ │ API Routes Layer │ │
│ │ (auth, completion, etc) │ │
│ └──────────┬───────────────┘ │
└─────────────┼───────────────────┘
┌─────────────────────────────────┐
│ Services Layer │
│ ┌─────────────────────────┐ │
│ │ Agent Service │ │
│ │ LLM Service │ │
│ │ Transcription Service │ │
│ └──────────┬──────────────┘ │
└─────────────┼───────────────────┘
┌─────────────────────────────────┐
│ External Services │
│ - OpenAI API │
│ - Mistral AI API │
│ - LangChain/LangGraph │
└─────────────────────────────────┘
```
## Principes SOLID appliqués
### 1. Single Responsibility Principle (SRP)
Chaque module a une seule responsabilité:
- `llm_service.py`: Gestion des LLM
- `agent_service.py`: Exécution des agents
- `transcription_service.py`: Transcription audio
- `security.py`: Authentification JWT
### 2. Open/Closed Principle (OCP)
**Extensible sans modification:**
```python
# Ajouter un nouvel agent sans toucher au code existant
agent_registry.register_agent(
AgentType.NEW_AGENT,
create_new_graph,
"Description"
)
```
### 3. Liskov Substitution Principle (LSP)
Tous les LLM respectent l'interface `BaseChatModel` de LangChain:
```python
def get_llm(...) -> BaseChatModel:
# Peut retourner ChatOpenAI ou ChatMistralAI
# Les deux sont interchangeables
```
### 4. Interface Segregation Principle (ISP)
Interfaces spécifiques et minimales:
- Route `/completion` ne dépend que de `AgentService`
- Route `/transcription` ne dépend que de `TranscriptionService`
### 5. Dependency Inversion Principle (DIP)
Les dépendances pointent vers les abstractions:
```python
# AgentService dépend de l'abstraction BaseChatModel
# pas d'une implémentation concrète
class AgentService:
def invoke(self, ..., model_name: ModelName):
llm: BaseChatModel = llm_service.get_llm(model_name)
# llm peut être n'importe quelle implémentation
```
## Patterns utilisés
### Factory Pattern
`LLMService` est un factory pour créer les bons LLM:
```python
llm = llm_service.get_llm(ModelName.GPT_4)
# ou
llm = llm_service.get_llm(ModelName.MISTRAL_LARGE)
```
### Registry Pattern
`AgentRegistry` gère les agents disponibles:
```python
builder = agent_registry.get_builder(AgentType.SIMPLE)
graph = builder(llm)
```
### Dependency Injection
FastAPI injecte les dépendances:
```python
async def route(current_user: dict = Depends(CurrentUser)):
# current_user est injecté automatiquement
```
### Singleton Pattern
Services instanciés une seule fois:
```python
llm_service = LLMService() # Singleton
agent_registry = AgentRegistry() # Singleton
```
## Sécurité
### Authentification JWT
1. Client demande un token: `POST /auth/token`
2. Serveur génère un JWT signé
3. Client inclut le token dans chaque requête: `Authorization: Bearer <token>`
4. Middleware vérifie et décode le token
5. Si valide, la requête est traitée
### Validation des entrées
Tous les inputs sont validés par Pydantic:
```python
class CompletionRequest(BaseModel):
message: str = Field(...)
model: ModelName = Field(...) # Enum validation
temperature: float = Field(ge=0.0, le=2.0) # Range validation
```
## Extensibilité
### Ajouter un nouveau modèle LLM
1. Ajouter dans `domain/enums.py`:
```python
class ModelName(str, Enum):
NEW_MODEL = "new-model-name"
```
2. Ajouter dans `services/llm_service.py`:
```python
def list_available_models():
# Ajouter les métadonnées
```
### Ajouter un nouveau type d'agent
1. Créer le graphe dans `graphs/`:
```python
def create_custom_graph(llm):
# Votre graphe
return workflow.compile()
```
2. Enregistrer dans `services/agent_registry.py`:
```python
agent_registry.register_agent(
AgentType.CUSTOM,
create_custom_graph,
"Description"
)
```
3. Utiliser directement via l'API!
### Ajouter une nouvelle route API
1. Créer le fichier dans `api/routes/`:
```python
router = APIRouter(prefix="/custom", tags=["Custom"])
@router.get("/")
async def custom_route():
return {"message": "Custom"}
```
2. Inclure dans `app.py`:
```python
from api.routes import custom
app.include_router(custom.router)
```
## Tests (à implémenter)
Structure recommandée:
```
tests/
├── unit/
│ ├── test_llm_service.py
│ ├── test_agent_service.py
│ └── test_security.py
├── integration/
│ ├── test_completion_api.py
│ ├── test_transcription_api.py
│ └── test_auth_flow.py
└── e2e/
└── test_full_workflow.py
```
## Performance
### Asynchronicité
Toutes les opérations I/O sont async:
- Appels API externes (OpenAI, Mistral)
- Requêtes base de données (futures)
- Opérations fichiers (transcription)
### Streaming
Support du streaming pour réduire la latence perçue:
- Server-Sent Events (SSE) pour completion
- WebSocket pour communication temps réel
## Monitoring
### LangSmith
Intégration optionnelle pour tracer les agents LangChain:
```env
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=...
```
### Logs
Logging structuré avec Python logging:
```python
logger.info(f"Request: {method} {path}")
logger.error(f"Error: {error}", exc_info=True)
```
## Déploiement
### Docker
```dockerfile
FROM python:3.12
# Configuration sécurisée
# Installation dépendances
# Lancement uvicorn
```
### Production
Recommandations:
- Uvicorn avec workers multiples
- Reverse proxy (nginx, traefik)
- HTTPS obligatoire
- Variables d'environnement sécurisées
- Rate limiting
- Monitoring (Prometheus, Grafana)
## Évolutions futures
- [ ] Cache Redis pour réponses fréquentes
- [ ] Base vectorielle pour RAG
- [ ] Queue Celery pour tâches longues
- [ ] Métriques Prometheus
- [ ] Tests automatisés
- [ ] CI/CD pipeline