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:

# 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:

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:

# 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:

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:

builder = agent_registry.get_builder(AgentType.SIMPLE)
graph = builder(llm)

Dependency Injection

FastAPI injecte les dépendances:

async def route(current_user: dict = Depends(CurrentUser)):
    # current_user est injecté automatiquement

Singleton Pattern

Services instanciés une seule fois:

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:

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:
class ModelName(str, Enum):
    NEW_MODEL = "new-model-name"
  1. Ajouter dans services/llm_service.py:
def list_available_models():
    # Ajouter les métadonnées

Ajouter un nouveau type d'agent

  1. Créer le graphe dans graphs/:
def create_custom_graph(llm):
    # Votre graphe
    return workflow.compile()
  1. Enregistrer dans services/agent_registry.py:
agent_registry.register_agent(
    AgentType.CUSTOM,
    create_custom_graph,
    "Description"
)
  1. Utiliser directement via l'API!

Ajouter une nouvelle route API

  1. Créer le fichier dans api/routes/:
router = APIRouter(prefix="/custom", tags=["Custom"])

@router.get("/")
async def custom_route():
    return {"message": "Custom"}
  1. Inclure dans app.py:
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:

LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=...

Logs

Logging structuré avec Python logging:

logger.info(f"Request: {method} {path}")
logger.error(f"Error: {error}", exc_info=True)

Déploiement

Docker

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