- Add SESSION-2026-07-20-JEAN-ROUTER.md (complete session journal) - Add ARCHITECTURE-JEAN-ROUTER.md (new architecture documentation) - Remove ARCHITECTURE-LITELLM.md (replaced by jean-router) - Update README.md with jean-router, Jean backend, and VRAM management - Document dynamic preset discovery and VRAM switching logic
314 lines
11 KiB
Markdown
314 lines
11 KiB
Markdown
# Architecture LLM — jean-router (routing dynamique + gestion VRAM)
|
|
|
|
## Vue d'ensemble
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ OpenWebUI (:3000) │
|
|
│ http://192.168.1.27:3000 │
|
|
└────────────────────────┬────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ jean-router (:3014) │
|
|
│ Routing dynamique + Gestion VRAM automatique │
|
|
│ │
|
|
│ • Interroge Jean /api/presets (découverte dynamique) │
|
|
│ • Interroge Ollama /api/tags (modèles vision) │
|
|
│ • Switch automatique de preset Jean │
|
|
│ • Arrête Jean quand on passe sur Ollama (libère VRAM) │
|
|
│ • Garde Ollama 5 min en mémoire avant déchargement │
|
|
└────────┬──────────────────────────────────────┬────────────────┘
|
|
│ │
|
|
▼ ▼
|
|
┌────────────────────────┐ ┌────────────────────────┐
|
|
│ jean-proxy (:3012) │ │ wol-proxy (:3011) │
|
|
│ + WOL si PC éteint │ │ + WOL si PC éteint │
|
|
└────────┬───────────────┘ └────────┬───────────────┘
|
|
│ │
|
|
▼ ▼
|
|
┌────────────────────────┐ ┌────────────────────────┐
|
|
│ Jean (.11:8080) │ │ Ollama (.11:11434) │
|
|
│ llama.cpp server │ │ Modèles vision │
|
|
│ Presets dynamiques │ │ mistral, qwen3.5 │
|
|
│ Ornith, Qwen3.6... │ │ │
|
|
└────────────────────────┘ └────────────────────────┘
|
|
```
|
|
|
|
## Composants
|
|
|
|
### jean-router (`/jean-router/`) — Proxy dynamique
|
|
|
|
**Rôle :** Router intelligemment entre Jean et Ollama avec gestion VRAM
|
|
|
|
**Fonctionnalités :**
|
|
1. **Découverte dynamique** : Interroge `/api/presets` (Jean) et `/api/tags` (Ollama)
|
|
2. **Routing intelligent** : Route vers Jean ou Ollama selon le modèle demandé
|
|
3. **Switch automatique** : Change de preset Jean si nécessaire
|
|
4. **Gestion VRAM** : Évite la contention mémoire entre Jean et Ollama
|
|
|
|
**Endpoints :**
|
|
- `GET /v1/models` : Liste tous les modèles (Jean + Ollama)
|
|
- `POST /v1/chat/completions` : Route vers le bon backend
|
|
|
|
**Configuration :**
|
|
```bash
|
|
JEAN_WEB_HOST=192.168.1.11 # Jean Web UI (API presets)
|
|
JEAN_WEB_PORT=8090
|
|
JEAN_PROXY_HOST=localhost # jean-proxy (backend Jean)
|
|
JEAN_PROXY_PORT=3012
|
|
OLLAMA_PROXY_HOST=localhost # wol-proxy (backend Ollama)
|
|
OLLAMA_PROXY_PORT=3011
|
|
OLLAMA_DIRECT_HOST=192.168.1.11 # Ollama direct (pour unload)
|
|
OLLAMA_DIRECT_PORT=11434
|
|
ENABLE_OLLAMA=true
|
|
ENABLE_VRAM_MANAGEMENT=true
|
|
OLLAMA_KEEP_ALIVE_MINUTES=5 # Ollama reste 5 min en mémoire
|
|
SWITCH_TIMEOUT=90 # Timeout chargement Jean (s)
|
|
JEAN_STOP_TIMEOUT=30 # Timeout arrêt Jean (s)
|
|
LISTEN_PORT=3014
|
|
```
|
|
|
|
### jean-proxy (`/jean-proxy/`) — Reverse-proxy Jean + WOL
|
|
|
|
**Rôle :** Proxy vers Jean avec Wake-on-LAN si le PC gaming est éteint
|
|
|
|
**Fonctionnalités :**
|
|
- Écoute `:3012` sur le host (`network_mode: host`)
|
|
- Health-check : `GET /health` sur Jean
|
|
- Si cible DOWN → envoi paquets WOL vers `TARGET_MAC`
|
|
- Attente jusqu'à `WAKE_TIMEOUT` (60s)
|
|
- Route toutes les requêtes vers `http://${OLLAMA_HOST}:8080`
|
|
|
|
**Configuration :**
|
|
```bash
|
|
TARGET_HOST=192.168.1.11
|
|
TARGET_PORT=8080
|
|
TARGET_MAC=04:D9:F5:D1:EC:DF
|
|
LISTEN_PORT=3012
|
|
WAKE_TIMEOUT=60
|
|
CHECK_INTERVAL=5
|
|
BROADCAST_IP=192.168.1.255
|
|
HEALTH_PATH=/health
|
|
```
|
|
|
|
### wol-proxy (`/wol-proxy/`) — Reverse-proxy Ollama + WOL
|
|
|
|
**Rôle :** Proxy vers Ollama avec Wake-on-LAN
|
|
|
|
**Fonctionnalités :**
|
|
- Écoute `:3011` sur le host
|
|
- Health-check : `GET /api/version` sur Ollama
|
|
- Si cible DOWN → envoi paquets WOL
|
|
- Route toutes les requêtes vers `http://${OLLAMA_HOST}:11434`
|
|
|
|
**Configuration :**
|
|
```bash
|
|
TARGET_HOST=192.168.1.11
|
|
TARGET_PORT=11434
|
|
TARGET_MAC=04:D9:F5:D1:EC:DF
|
|
LISTEN_PORT=3011
|
|
WAKE_TIMEOUT=180
|
|
CHECK_INTERVAL=5
|
|
BROADCAST_IP=192.168.1.255
|
|
```
|
|
|
|
## Gestion VRAM
|
|
|
|
### Problème
|
|
Jean et Ollama partagent la même carte graphique (RX 7800 XT, 16GB VRAM). Charger les deux simultanément cause une contention mémoire.
|
|
|
|
| Backend | Modèle typique | VRAM utilisée |
|
|
|---------|---------------|---------------|
|
|
| Jean | Ornith 35B Q6_K | ~28.5GB (déborde en RAM) |
|
|
| Ollama | mistral 7B Q4_K_M | ~4GB |
|
|
| Ollama | qwen3.5:9b Q4_K_M | ~6GB |
|
|
|
|
### Solution : Switch automatique
|
|
|
|
**Switch Jean → Ollama :**
|
|
```
|
|
1. Arrêt de Jean via API web (/api/stop)
|
|
2. Attente confirmation (max 30s)
|
|
3. Route requête vers Ollama
|
|
```
|
|
|
|
**Switch Ollama → Jean :**
|
|
```
|
|
1. Programme déchargement Ollama dans 5 min (timer)
|
|
2. Démarrage de Jean via API web (/api/start)
|
|
3. Attente chargement modèle (max 90s)
|
|
4. Route requête vers Jean
|
|
```
|
|
|
|
**Timer Ollama :**
|
|
- Ollama reste en mémoire pendant **5 minutes** après le dernier usage
|
|
- Chaque requête vers Ollama annule le timer
|
|
- Si retour sur Ollama avant expiration → déchargement annulé
|
|
- Après 5 min d'inactivité → déchargement automatique
|
|
|
|
### Logs observés
|
|
|
|
**Switch Jean → Ollama :**
|
|
```
|
|
[VRAM] Switch Jean → Ollama
|
|
[VRAM] Arrêt de Jean pour libérer la VRAM...
|
|
[VRAM] Jean arrêté via API web
|
|
[VRAM] Jean confirmé arrêté
|
|
[Router] → Ollama (gemma4:e4b)
|
|
```
|
|
|
|
**Switch Ollama → Jean :**
|
|
```
|
|
[VRAM] Switch Ollama → Jean
|
|
[VRAM] Déchargement Ollama programmé dans 5 minutes
|
|
[VRAM] Démarrage de Jean...
|
|
[VRAM] Jean prêt après 45s
|
|
[Router] → Jean (ornith-35b-q6)
|
|
```
|
|
|
|
**Timer Ollama :**
|
|
```
|
|
[VRAM] Timer écoulé (5min), déchargement Ollama...
|
|
[VRAM] Ollama déchargé via API
|
|
```
|
|
|
|
## Modèles disponibles
|
|
|
|
### Jean (presets dynamiques)
|
|
Les presets sont découverts automatiquement via `/api/presets` :
|
|
- **ornith-35b-q6** (actif, Q6_K, reasoning)
|
|
- **qwen3.6-27b-mtp** (IQ4_XS, reasoning)
|
|
- **qwen3.6-35b-moe-compact**
|
|
- **qwen3.6-35b-moe-compact-reason** (reasoning)
|
|
- **qwen3.6-35b-moe-nano**
|
|
|
|
**Note :** Nouveaux presets Jean apparaissent automatiquement dans OpenWebUI sans configuration.
|
|
|
|
### Ollama (modèles vision)
|
|
- **mistral** (7.2B, Q4_K_M, tools)
|
|
- **qwen3.5:9b** (9.7B, Q4_K_M, vision, thinking)
|
|
|
|
**Note :** Ollama sert principalement pour les modèles avec vision que Jean ne supporte pas.
|
|
|
|
## Déploiement
|
|
|
|
### Commandes (sur effi-server .27)
|
|
|
|
```bash
|
|
cd /home/effi/effi
|
|
git pull
|
|
|
|
# Build et démarrage jean-router
|
|
docker compose -f docker-compose.yml -f docker-compose.litellm.yml up -d --build jean-router
|
|
|
|
# Recréer open-webui avec nouvelle config
|
|
docker compose -f docker-compose.yml -f docker-compose.litellm.yml up -d --force-recreate open-webui
|
|
|
|
# Vérifier
|
|
docker logs jean-router --tail 20
|
|
curl -s http://localhost:3014/v1/models | jq
|
|
```
|
|
|
|
### Tests
|
|
|
|
**1. Liste des modèles :**
|
|
```bash
|
|
curl -s http://localhost:3014/v1/models | python3 -m json.tool
|
|
```
|
|
|
|
**2. Requête Jean :**
|
|
```bash
|
|
curl -X POST http://localhost:3014/v1/chat/completions \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"model": "ornith-35b-q6",
|
|
"messages": [{"role": "user", "content": "Bonjour"}],
|
|
"max_tokens": 50
|
|
}'
|
|
```
|
|
|
|
**3. Requête Ollama :**
|
|
```bash
|
|
curl -X POST http://localhost:3014/v1/chat/completions \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"model": "mistral",
|
|
"messages": [{"role": "user", "content": "Hello"}],
|
|
"max_tokens": 30
|
|
}'
|
|
```
|
|
|
|
**4. Vérifier logs VRAM :**
|
|
```bash
|
|
docker logs jean-router -f | grep -E "VRAM|Router"
|
|
```
|
|
|
|
## Avantages vs LiteLLM
|
|
|
|
| Aspect | LiteLLM | jean-router |
|
|
|--------|---------|-------------|
|
|
| Configuration | Statique (config.yaml) | Dynamique (API Jean) |
|
|
| Nouveaux presets | Modifier config + restart | Automatique |
|
|
| Pass-through /v1/models | Non | Oui |
|
|
| Gestion VRAM | Aucune | Automatique |
|
|
| Couches | 2 (LiteLLM + jean-proxy) | 1 (jean-router) |
|
|
| Complexité | Élevée | Faible |
|
|
|
|
## Limitations
|
|
|
|
### 1. Latence de switch
|
|
- Jean → Ollama : ~3s (arrêt Jean)
|
|
- Ollama → Jean : ~45-90s (démarrage + chargement modèle)
|
|
- **Impact** : Première requête après switch plus lente
|
|
|
|
### 2. Timer Ollama non-persistant
|
|
- Si jean-router redémarre, le timer est perdu
|
|
- Ollama restera en mémoire indéfiniment (jusqu'à son propre timeout)
|
|
- **Acceptable** : Ollama gère son propre `keep_alive`
|
|
|
|
### 3. Pas de failover
|
|
- Si Jean échoue (timeout, erreur), pas de fallback automatique vers Ollama
|
|
- **À considérer** : Ajouter un fallback dans jean-router si besoin
|
|
|
|
### 4. Jean n'a pas d'auto-unload natif
|
|
- Ollama décharge automatiquement après `OLLAMA_KEEP_ALIVE` (défaut 5min)
|
|
- Jean garde son modèle chargé tant que le service tourne
|
|
- **Solution actuelle** : Arrêt complet de Jean via API web
|
|
|
|
## Évolution possible
|
|
|
|
### Court terme
|
|
- **Monitorer** : Vérifier que la gestion VRAM fonctionne bien en production
|
|
- **Ajuster** : Modifier `OLLAMA_KEEP_ALIVE_MINUTES` selon l'usage réel
|
|
- **Tester** : Valider que les nouveaux presets Jean apparaissent bien automatiquement
|
|
|
|
### Moyen terme
|
|
- **VRAM monitoring** : jean-router pourrait vérifier la VRAM disponible avant de router
|
|
- **Fallback automatique** : Si Jean échoue, router vers Ollama
|
|
- **Metrics** : Exposer des statistiques (temps de switch, VRAM utilisée, etc.)
|
|
|
|
### Long terme
|
|
- **JeanOrchestrator** : Jean pourrait gérer lui-même le switch entre presets
|
|
- **Multi-GPU** : Si plusieurs GPU, router vers celui avec le plus de VRAM libre
|
|
- **Load balancing** : Si plusieurs instances Jean/Ollama, répartir la charge
|
|
|
|
## Historique
|
|
|
|
**2026-06-27** : Architecture initiale avec LiteLLM
|
|
- Routing statique par nom de modèle
|
|
- Configuration codée en dur dans `litellm/config.yaml`
|
|
|
|
**2026-07-20** : Migration vers jean-router
|
|
- Routing dynamique basé sur les presets Jean
|
|
- Gestion automatique de la VRAM
|
|
- Suppression de LiteLLM (une couche de moins)
|
|
- Nouveaux modèles automatiquement disponibles
|
|
|
|
## Références
|
|
|
|
- **Code jean-router** : `/jean-router/app.py`
|
|
- **Docker compose** : `/docker-compose.litellm.yml`
|
|
- **Journal de session** : `/docs/05-journal/SESSION-2026-07-20-JEAN-ROUTER.md`
|
|
- **Repo Gitea** : https://gitea.folzocorp.fr/Folzo/Effi
|