Multi-tenant RAG sur Kubernetes : ce qui plie en premier
Quand on industrialise une plateforme RAG pour plusieurs clients, ce n'est pas le LLM qui pose problème — c'est l'isolation, les quotas et l'observabilité par tenant.
J’ai construit une plateforme RAG multi-tenant pour Conexia. Tout le monde parle de RAG comme si le sujet, c’était de choisir un LLM et de coller un vector store derrière. En vrai, dès qu’on dépasse le POC mono-client, le LLM est le composant le moins intéressant. Voici les trois choses qui plient en premier, et ce que j’ai fait pour les rendre opérables.
1. L’isolation, c’est partout ou nulle part
La tentation, quand on démarre, c’est de séparer les tenants par “namespace logique” : un préfixe sur les clés, un tag sur les documents, et basta. Ça tient jusqu’à la première fuite. Et la première fuite arrive vite, parce qu’il y a au moins six surfaces où l’isolation peut casser :
- La vector DB (un mauvais filtre
whereet le tenant A reçoit le contexte du tenant B) - Les secrets (clés LLM, credentials de scraping, webhooks par client)
- Les quotas (le tenant A ne doit pas saturer le pool LLM pour le tenant B)
- L’observabilité (les logs et les métriques doivent être taggés par tenant pour permettre le débogage par client)
- Le cache (un cache de prompt mal scopé fuite des infos métier d’un tenant à l’autre)
- La configuration (les prompts système, les sources, les workflows métier)
Ma règle : un tenant = un identifiant qui se propage dans toutes les couches, et on échoue par défaut si l’identifiant n’est pas présent. Pas de “valeur par défaut” silencieuse. Si une requête arrive sans tenant ID, elle est rejetée, pas bestialement attribuée au tenant zéro.
Concrètement, sur K8s, ça se traduit par :
- Un middleware d’auth qui injecte le tenant ID dans le contexte de la requête
- Un wrapper sur la vector DB qui refuse les queries sans
tenant_id - Des secrets Kubernetes scopés par namespace ou par
External Secretssynchronisés depuis un vault avec un chemin tenant-aware - Des labels Prometheus systématiques sur toutes les métriques applicatives
# Extrait : labels obligatoires sur les métriques RAG
- name: rag_query_latency_seconds
labels:
- tenant_id
- source_type # web, gmail, messenger
- llm_provider
- cache_hit
Si vous ne pouvez pas répondre en cinq secondes à la question “combien de tokens a consommé le tenant X cette semaine et sur quels modèles”, votre observabilité multi-tenant n’existe pas encore.
2. Les pipelines d’ingestion sont la vraie source de pannes
Le LLM tombe rarement. Vos pipelines de scraping et d’indexation, eux, tombent tout le temps : le site source change son HTML, l’API source rate-limit, un PDF arrive corrompu, un lot de documents fait exploser le coût d’embedding parce que quelqu’un a uploadé un dump de logs.
Ce qui m’a sauvé :
- Idempotence sur tout : un document indexé deux fois ne crée pas deux entrées. Hash de contenu en clé.
- Quarantaine : tout document qui échoue va dans une queue séparée, pas dans la queue principale qui se remplit silencieusement.
- Cap budgétaire par tenant sur les embeddings : un client ne peut pas brûler le budget mensuel en une nuit en uploadant 50 Go de PDF.
- Workflow d’indexation découpé en étapes observables (fetch → parse → chunk → embed → upsert), avec métriques à chaque étape.
C’est moins sexy qu’un benchmark de LLM, mais c’est ça qui garde la plateforme en vie un dimanche matin.
3. Le routing LLM, c’est de l’ops, pas du ML
Tout le monde rêve d’un router intelligent qui choisit le meilleur modèle. En pratique, le routing utile est ennuyeux :
- Une règle par criticité (les requêtes “test interne” ne vont pas sur GPT-4)
- Un fallback par disponibilité (si le provider primaire timeout, on bascule)
- Un circuit breaker par tenant pour ne pas qu’un client en panne entraîne les autres
- Un budget alert par tenant et par jour
Le “ML routing” qui choisit dynamiquement le meilleur modèle pour chaque prompt, c’est intéressant en research. En production, vous voulez d’abord que le routing soit déterministe, observable et débogable. La sophistication vient après.
Ce que je ferais en premier sur un nouveau projet
Si je redémarrais demain :
- Tenant ID partout, échec par défaut, dès la première ligne de code
- Métriques par tenant dès le jour un, même si on n’a qu’un tenant
- Caps budgétaires LLM et embedding avant la première intégration client
- Pipeline d’ingestion avec quarantaine et idempotence avant d’optimiser quoi que ce soit
- Le “vrai” routing LLM en dernier, et le plus simple possible
Le RAG, ce n’est pas un problème d’IA. C’est un problème de plateforme. Et les plateformes, ça se construit par les bords (isolation, quotas, observabilité), pas par le centre (le modèle).