# Session 2026-07-20 : jean-router et gestion VRAM dynamique ## Résumé Création de **jean-router**, un proxy dynamique qui remplace LiteLLM pour router intelligemment entre Jean (llama.cpp) et Ollama, avec gestion automatique de la VRAM partagée. ## Contexte ### Problème initial - OpenWebUI ne voyait pas les modèles Jean (Ornith) car configuré uniquement pour Ollama - LiteLLM avait une configuration statique des modèles (codée en dur dans `litellm/config.yaml`) - Nouveaux presets Jean nécessitaient de modifier manuellement la config LiteLLM - Jean et Ollama partagent la même VRAM (RX 7800 XT, 16GB) → contention mémoire ### Architecture avant ``` OpenWebUI → LiteLLM:4000 (config statique) ├→ jean-proxy:3012 → Jean (.11:8080) └→ wol-proxy:3011 → Ollama (.11:11434) ``` **Problèmes :** - LiteLLM ne faisait pas de pass-through de `/v1/models` - Configuration statique : `qwen3.6-reason`, `qwen3.6-27b`, etc. codés en dur - Jean faisait tourner **Ornith** mais LiteLLM attendait Qwen3.6 - Pas de gestion VRAM : Jean et Ollama pouvaient charger simultanément → OOM ## Solution : jean-router ### Architecture après ``` OpenWebUI → jean-router:3014 (routing dynamique) ├→ jean-proxy:3012 → Jean (.11:8080) └→ wol-proxy:3011 → Ollama (.11:11434) ``` ### Fonctionnalités **1. Découverte dynamique des modèles** - Interroge `/api/presets` de Jean (port 8090) pour lister les presets disponibles - Interroge `/api/tags` d'Ollama (port 11434) pour lister les modèles - Expose tout via `/v1/models` (API OpenAI-compatible) - **Nouveaux presets Jean automatiquement visibles dans OpenWebUI** **2. Routing intelligent** - Si le modèle demandé est un preset Jean → switch automatique + route vers Jean - Si c'est un modèle Ollama → route vers Ollama - Sinon → erreur 404 **3. Gestion VRAM (RX 7800 XT, 16GB partagés)** | Backend | Modèle typique | VRAM utilisée | |---------|---------------|---------------| | Jean | Ornith 35B Q6_K | ~28.5GB (déborde en RAM) | | Ollama | mistral/qwen3.5 | ~4-6GB | **Logique de gestion :** **Switch Jean → Ollama :** 1. `stop_jean()` arrête Jean via son API web (port 8090) 2. Attend confirmation que Jean est arrêté (max 30s) 3. Route la requête vers Ollama **Switch Ollama → Jean :** 1. Programme le déchargement d'Ollama dans 5 minutes (timer) 2. `start_jean()` redémarre Jean 3. Attend que le modèle soit chargé (max 90s) 4. Route la 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 pour libérer VRAM ## Fichiers créés/modifiés ### Nouveau : `jean-router/` - `app.py` (320 lignes) : Service Flask avec routing dynamique + gestion VRAM - `Dockerfile` : Container Python 3.12-slim ### Modifiés : - `docker-compose.litellm.yml` : - Ajout service jean-router - Suppression service litellm - OpenWebUI pointe directement vers jean-router:3014 - `litellm/config.yaml` : Supprimé (plus nécessaire) ### Configuration jean-router ```yaml environment: - JEAN_WEB_HOST=${OLLAMA_HOST} - JEAN_WEB_PORT=8090 - JEAN_PROXY_HOST=localhost - JEAN_PROXY_PORT=3012 - OLLAMA_PROXY_HOST=localhost - OLLAMA_PROXY_PORT=3011 - OLLAMA_DIRECT_HOST=${OLLAMA_HOST} - OLLAMA_DIRECT_PORT=11434 - ENABLE_OLLAMA=true - ENABLE_VRAM_MANAGEMENT=true - OLLAMA_KEEP_ALIVE_MINUTES=5 - LISTEN_PORT=3014 - SWITCH_TIMEOUT=90 - CHECK_INTERVAL=2 - JEAN_STOP_TIMEOUT=30 - OLLAMA_UNLOAD_TIMEOUT=15 ``` ## Déploiement sur effi-server ### Initialisation du repo git Le dossier `/home/effi/effi` n'était pas un repo git. Initialisation : ```bash cd /home/effi/effi git init git remote add origin https://gitea.folzocorp.fr/Folzo/Effi.git git fetch origin git checkout -b main origin/main ``` **Note :** Conflits avec fichiers existants (docker-compose.yml, jean-proxy/, etc.) résolus en les déplaçant temporairement dans `/tmp/effi-backup/`. ### Commandes de déploiement ```bash cd /home/effi/effi git pull docker compose -f docker-compose.yml -f docker-compose.litellm.yml up -d --build jean-router docker compose -f docker-compose.yml -f docker-compose.litellm.yml up -d --force-recreate open-webui docker stop litellm && docker rm litellm # Suppression LiteLLM ``` ## Tests et validation ### Modèles visibles dans OpenWebUI **Jean (5 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 **Ollama :** - mistral (7.2B, Q4_K_M, tools) - qwen3.5:9b (9.7B, Q4_K_M, vision, thinking) ### 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 ``` ## Avantages 1. **Dynamique** : Nouveaux presets Jean automatiquement visibles sans modifier de config 2. **Simplifié** : Une couche de moins (LiteLLM supprimé) 3. **VRAM-safe** : Pas de contention mémoire entre Jean et Ollama 4. **Intelligent** : Ollama reste en mémoire 5 min pour les usages répétés 5. **Transparent** : OpenWebUI voit tous les modèles via un seul endpoint ## Limitations et points d'attention ### 1. 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 ### 2. 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 ### 3. 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` ### 4. Pas de failover - Si Jean échoue (timeout, erreur), pas de fallback automatique vers Ollama - **À considérer** : Ajouter un fallback dans jean-router si besoin ## Commits Gitea ``` 8b7c4fb feat: add VRAM management for Jean/Ollama switching 20767c2 feat: keep Ollama models in memory for 5 minutes babe4ee chore: add OLLAMA_KEEP_ALIVE_MINUTES=5 to docker-compose 43aacc0 refactor: OpenWebUI points directly to jean-router (no LiteLLM needed) 856ba4a refactor: remove LiteLLM, jean-router handles all routing fcad415 feat: jean-router — routing dynamique Jean + Ollama b441f34 fix: jean-router syntax error (missing except block) ``` ## Réflexions et décisions ### Pourquoi supprimer LiteLLM ? - LiteLLM ne faisait pas de pass-through de `/v1/models` - Configuration statique incompatible avec les presets dynamiques de Jean - Couche supplémentaire inutile : jean-router fait le même travail - **Décision** : OpenWebUI pointe directement vers jean-router:3014 ### Pourquoi garder Ollama en mémoire 5 min ? - Ollama sert principalement pour la vision (modèles que Jean ne supporte pas) - Usage typique : quelques requêtes vision consécutives, puis retour à Jean - 5 min = bon compromis entre réactivité et libération VRAM - **Configurable** : `OLLAMA_KEEP_ALIVE_MINUTES` dans docker-compose ### Pourquoi arrêter Jean complètement ? - Jean n'a pas d'API pour décharger le modèle sans arrêter le service - Le modèle reste en VRAM tant que llama-server tourne - **Alternative envisagée** : `systemctl stop jean` (mais nécessite sudo) - **Solution retenue** : API web de Jean (`/api/stop`) plus simple ### Architecture future possible - **JeanOrchestrator** : Jean pourrait gérer lui-même le switch entre presets - **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.) ## Prochaines étapes 1. **Monitorer** : Vérifier que la gestion VRAM fonctionne bien en production 2. **Ajuster** : Modifier `OLLAMA_KEEP_ALIVE_MINUTES` selon l'usage réel 3. **Documenter** : Mettre à jour `docs/ARCHITECTURE-LITELLM.md` (à renommer `ARCHITECTURE-JEAN-ROUTER.md`) 4. **Tester** : Valider que les nouveaux presets Jean apparaissent bien automatiquement ## Conclusion **jean-router** remplace avantageusement LiteLLM avec : - Routing dynamique basé sur les presets Jean - Gestion automatique de la VRAM partagée - Architecture simplifiée (une couche de moins) - Nouveaux modèles automatiquement disponibles L'architecture est maintenant prête pour Effi : quand un nouveau preset Jean est créé, il apparaît immédiatement dans OpenWebUI sans aucune configuration supplémentaire.