Guide de serving LoRAX : adapters LoRA sur Kubernetes à grande échelle
Traduction automatique Cet article a été traduit automatiquement depuis la version originale en anglais.
Un modèle de base et de nombreux adapters LoRA créent un problème de serving inhabituel. Les poids de base sont partagés, mais chaque requête peut nécessiter un ensemble différent de poids d’adapter. Une architecture conventionnelle avec un déploiement par variante gaspille de la mémoire GPU lorsque la plupart des variantes sont inactives.
LoRAX répond à cette longue traîne. Il charge les adapters à la demande, regroupe dans des batches les requêtes associées à différents adapters et déplace les poids des adapters entre la mémoire GPU et la mémoire CPU. La promesse séduisante est de servir « des milliers de modèles fine-tunés sur un seul GPU ». La question d’ingénierie est plus précise : compte tenu de votre ensemble d’adapters actifs, de votre profil d’arrivée et de votre objectif de latence, la planification des échanges apporte-t-elle un gain suffisant pour justifier un runtime de serving supplémentaire ?
Ce guide s’adresse aux ingénieurs inference et plateforme qui doivent servir de nombreuses variantes LoRA à partir d’un seul modèle de base. Il montre comment tester les APIs documentées, dimensionner le working set et transformer le chart Helm de démarrage en plan de production explicite.
Résumé. Choisissez LoRAX lorsque de nombreux adapters LoRA compatibles partagent un même modèle de base et que le trafic est clairsemé ou à longue traîne. La capacité dépend du working set actif, et non de la taille du catalogue. Épinglez le runtime, authentifiez et allowlistez les IDs d’adapters, ajoutez un cache durable pour les artifacts ainsi que des probes, routez en tenant compte de la localité du cache et mesurez séparément les chemins cold et warm.
Le problème de serving est celui du working set
LoRA gèle un modèle de base et apprend des mises à jour low-rank pour certaines matrices de poids. L’adapter obtenu est généralement bien plus petit qu’un checkpoint complet, mais sa taille dépend toujours du rank, des modules ciblés, du nombre de couches et du dtype. Des affirmations fixes telles que « chaque adapter fait 100 Mo » constituent de mauvaises données d’entrée pour le dimensionnement.
Pour le serving, distinguez trois quantités :
- Taille du catalogue : tous les adapters qu’une plateforme peut résoudre depuis le stockage
- Working set actif : adapters recevant des requêtes pendant la fenêtre de rétention du cache
- Ensemble concurrent : adapters représentés dans des batches au même instant
Un catalogue peut contenir des milliers d’adapters sans que des milliers d’entre eux puissent tenir en VRAM. Ce qui compte, c’est la fréquence de renouvellement de l’ensemble actif, la taille de ces adapters et la possibilité de regrouper utilement dans des batches les requêtes associées à différents adapters.
LoRAX combine quatre mécanismes :
- Le modèle de base reste résident pour tous les adapters compatibles.
- Une requête nomme un adapter, qui peut être résolu depuis Hugging Face, Predibase ou un système de fichiers.
- La planification des échanges d’adapters précharge et décharge les poids entre la mémoire GPU et la mémoire CPU.
- Le continuous batching hétérogène regroupe les requêtes ciblant différents adapters.
Le projet LoRAX indique que le batching hétérogène maintient le throughput et la latence presque constants lorsque le nombre d’adapters concurrents augmente dans ses benchmarks. Considérez ce résultat du fournisseur comme une hypothèse à vérifier sur votre workload. La longueur des prompts, la longueur des sorties, le rank, les modules ciblés, l’occupation des batches, le churn du cache et la génération du GPU peuvent modifier le résultat.
Le graphique restauré ci-dessous provient du rapport de lancement de LoRAX de Predibase, publié en novembre 2023. Predibase a benchmarké Llama 2 7B avec des requêtes réparties sur 1 à 128 adapters, sur un seul NVIDIA A10G. Ce graphique présente la comparaison des coûts pour 1 à 32 adapters, afin de traiter un million de tokens, répartis équitablement entre les adapters.

Comparaison archivée du projet, reproduite à partir du rapport LoRAX 2023 de Predibase. Les coûts LoRAX et dédiés utilisent les heures GPU de cette expérience. Au niveau de détail fourni par la source, la courbe GPT-3.5 Turbo utilise le coût par token du modèle fine-tuné.
Interprétez les barres orange plates comme le résultat de ce protocole de benchmark, et non comme une promesse de prix actuelle. Le test envoyait un total fixe d’un million de tokens et permettait à différents adapters de partager un batch. La référence dédiée supposait un compute hébergé séparé pour chaque modèle ; son coût augmentait donc avec le nombre de modèles.
Predibase n’a pas publié les paramètres de benchmark suivants :
- répartition des tokens entre prompt et sortie
- longueurs des requêtes
- taille des batches
- rank des adapters
- prix de l’heure GPU
- modèle exact d’utilisation des déploiements dédiés
- prix historiques exacts des tokens d’entrée et de sortie de GPT-3.5
Le rapport ne contient donc pas suffisamment d’informations pour reproduire indépendamment les valeurs en dollars du graphique.
Le graphique ne couvre pas non plus le trafic clairsemé, les téléchargements cold, les prix actuels du cloud, les GPU plus récents, les autres modèles de base ni les adapters utilisant des ranks différents. Il justifie la mise en place d’un replay du workload, mais ne peut pas le remplacer.
Quand LoRAX est un choix plausible
LoRAX mérite un benchmark lorsque toutes les conditions suivantes sont réunies :
- les adapters ont été entraînés sur le même modèle de base supporté et avec le même contrat de tokenizer
- le trafic couvre de nombreux adapters, avec une longue traîne significative
- le chargement à la demande d’un adapter cold est préférable à la réservation d’un déploiement dédié
- le routage par tenant ou par tâche existe déjà à la frontière applicative
- l’équipe sait exploiter un runtime d’inference spécialisé et le comportement de son cache
Les cas courants incluent les assistants spécifiques à chaque tenant, de nombreuses variantes par domaine et les expérimentations en ligne partageant un même checkpoint de base.
LoRAX est moins adapté lorsque quelques adapters concentrent l’essentiel du trafic ou lorsque les modèles ne partagent pas de base commune. Il l’est également lorsque des objectifs de latence stricts ne tolèrent pas les chargements cold, ou lorsque la plateforme ne peut pas contrôler de manière sûre les artifacts chargés par le serveur. Dans ces situations, un déploiement vLLM ou TGI standard avec un ensemble fixe d’adapters peut être plus simple.
N’utilisez pas Kubernetes uniquement parce que le catalogue est volumineux. Validez d’abord le runtime et la compatibilité des adapters sur un seul GPU.
Tester localement un modèle de base et un adapter
Le README de LoRAX recommande son conteneur préconstruit. Dans un environnement réel, utilisez un digest d’image immuable. main n’apparaît ici que parce qu’il s’agit du tag de quick start documenté dans le dépôt. Ces exemples sont illustratifs et n’ont pas été vérifiés localement dans ce checkout. Validez-les avec les versions de l’image et des dépendances que vous déployez.
mkdir -p data
docker run --rm --gpus all --shm-size 1g \
-p 8080:80 \
-v "$PWD/data:/data" \
ghcr.io/predibase/lorax:main \
--model-id mistralai/Mistral-7B-Instruct-v0.1
Le minimum documenté est Linux, Docker, un GPU NVIDIA Ampere ou plus récent, ainsi que des drivers compatibles avec CUDA 11.8. Les licences des modèles et les dépôts gated peuvent également nécessiter un token Hugging Face.
Commencez par le modèle de base :
curl http://127.0.0.1:8080/generate \
-H 'Content-Type: application/json' \
-d '{
"inputs": "[INST] Give one reason to measure cold-adapter latency. [/INST]",
"parameters": {"max_new_tokens": 64}
}'
Envoyez ensuite un adapter compatible :
curl http://127.0.0.1:8080/generate \
-H 'Content-Type: application/json' \
-d '{
"inputs": "[INST] Solve: Natalia sold 48 clips in April and half as many in May. What is the total? [/INST]",
"parameters": {
"max_new_tokens": 64,
"adapter_id": "vineetsharma/qlora-adapter-Mistral-7B-Instruct-v0.1-gsm8k"
}
}'
La première requête peut télécharger et charger l’adapter. Les requêtes suivantes peuvent utiliser les artifacts en cache et les poids résidents. Mesurez les deux chemins. Une seule requête warm ne dit pas grand-chose sur le comportement en longue traîne.
Utiliser un client compatible OpenAI
LoRAX expose un endpoint de chat compatible OpenAI. Le champ model identifie l’adapter :
from openai import OpenAI
client = OpenAI(
api_key="EMPTY",
base_url="http://127.0.0.1:8080/v1",
)
response = client.chat.completions.create(
model="alignment-handbook/zephyr-7b-dpo-lora",
messages=[
{"role": "user", "content": "Explain cache locality in two sentences."},
],
max_tokens=100,
)
print(response.choices[0].message.content)
Par défaut, le serveur n’exige pas de clé API. C’est pratique pour localhost, mais dangereux pour une configuration exposée sur Internet. Placez devant lui une couche d’authentification, d’autorisation par tenant, de quotas et d’allowlisting des adapters.
Définir une gate de compatibilité
Avant qu’un adapter n’entre dans le catalogue, vérifiez au minimum :
- le modèle de base et la révision déclarés
- la compatibilité du tokenizer et du chat-template
- le rank LoRA et les modules ciblés supportés par le runtime
- le format des artifacts et les formes des tenseurs
- la licence, la provenance et le digest d’intégrité
- une petite suite de tests comportementaux et de régression
Rejetez les artifacts incompatibles lors de leur enregistrement, plutôt qu’à la première requête d’un utilisateur.
Comprendre la résidence avant le déploiement
Le modèle de base consomme la plus grande part fixe de la mémoire GPU. Les poids des adapters, le KV cache, l’espace de travail des batches et les kernels du runtime se disputent le reste. La RAM CPU peut contenir les adapters déchargés, tandis que /data stocke les artifacts téléchargés.
Ces niveaux ne sont pas interchangeables. Un artifact provenant du disque ou du Hub doit être lu et matérialisé avant de devenir un adapter résident en CPU ou en GPU. Mesurez séparément les transitions :
| Chemin | Ce qu’il comprend | Métrique à relever |
|---|---|---|
| GPU hit | Adapter déjà résident | temps en file et time to first token |
| CPU hit | Transfert ou rematérialisation vers le GPU | délai de chargement de l’adapter et latence end-to-end |
| Artifact hit | Lecture depuis le cache local /data | délai de lecture/chargement et octets du cache |
| Remote miss | Téléchargement, validation et chargement | durée du téléchargement, erreurs et latence cold totale |
Le capacity planning doit rejouer la distribution réelle de popularité des adapters. Des IDs d’adapters tirés uniformément au hasard créent un problème de cache différent de celui d’un workload de tenants suivant une distribution de type Zipf.
Déployer le chart du dépôt avec précaution
Le dépôt contient charts/lorax ; le point de départ reproductible est donc une révision épinglée du dépôt et un chart local :
git clone https://github.com/predibase/lorax.git
cd lorax
git checkout <reviewed-commit-or-release>
helm dependency update charts/lorax
helm template lorax charts/lorax -f values.production.yaml
helm upgrade --install lorax charts/lorax \
--namespace inference \
--create-namespace \
-f values.production.yaml
Au 15 juillet 2026, les values du chart et le template du Deployment présentent des valeurs par défaut qui méritent votre attention :
- le tag de l’image est
latest /dataest unemptyDir; le remplacement du pod supprime donc les artifacts téléchargés- les probes de liveness et de readiness sont vides
- le token Hugging Face est modélisé comme une valeur d’environnement littérale
- un GPU est demandé par défaut
Le chart constitue une bonne base de travail. Ce n’est pas une politique de production.
Partir de la structure réelle des values du chart
Le chart imbrique la configuration du runtime sous deployment, et les arguments du launcher sont une liste de paires nom/valeur. Un overlay minimal ressemble à ceci :
deployment:
replicas: 1
image:
repository: ghcr.io/predibase/lorax
tag: "<tested-release-tag>"
args:
- name: "--model-id"
value: "mistralai/Mistral-7B-Instruct-v0.1"
- name: "--max-input-length"
value: "2048"
- name: "--max-total-tokens"
value: "3072"
- name: "--max-batch-total-tokens"
value: "8192"
- name: "--max-batch-prefill-tokens"
value: "4096"
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
env:
- name: HUGGING_FACE_HUB_TOKEN
valueFrom:
secretKeyRef:
name: lorax-hub
key: token
readinessProbe:
httpGet:
path: /health
port: http
periodSeconds: 5
failureThreshold: 600
service:
serviceType: ClusterIP
port: 80
Les limites de tokens ci-dessus sont des valeurs initiales d’exemple, et non des recommandations de dimensionnement. Déduisez-les de prompts représentatifs, de la concurrence attendue, de la mémoire GPU et de load tests.
Corriger explicitement les lacunes
Le template actuel du chart transmet deployment.env via toYaml ; un overlay values normal peut donc utiliser valueFrom.secretKeyRef pour les credentials du Hub, comme ci-dessus. Il encode en dur les volumes emptyDir, ne possède aucun hook startupProbe et formate toujours l’image sous la forme repository:tag. Un fichier values seul ne peut donc pas fournir un /data durable, une startup probe ou l’épinglage d’un digest d’image ; utilisez pour ces changements un fork du chart révisé, un patch post-render ou une couche de manifests de niveau supérieur. Cette couche de production doit inclure :
- un PersistentVolumeClaim ou un cache d’artifacts local au nœud monté sur
/data - une startup probe avant une liveness probe agressive
- une politique de disruption des pods et une répartition topologique pour plusieurs replicas
- une NetworkPolicy, des restrictions sur le service account et une gateway authentifiée
- l’épinglage du digest de l’image et des contrôles d’intégrité des artifacts
Ne placez jamais un token Hub directement dans un fichier values versionné. Deux replicas n’offrent une haute disponibilité utile que si tous deux peuvent charger le modèle de base. Le routeur doit également éviter d’envoyer chaque adapter cold aux deux pods.
Router en privilégiant la localité du cache
Un équilibrage round-robin peut transformer chaque replica en cache cold. Un routeur utile associe un ID d’adapter autorisé à un replica par hash ou selon une autre règle stable. Il conserve un chemin de failover lorsque ce replica est indisponible.
La clé de routage doit provenir de l’état applicatif authentifié, et non d’un paramètre arbitraire d’URL publique. Dans le cas contraire, un appelant peut forcer des téléchargements distants, provoquer du churn dans les caches ou sonder des noms d’adapters privés.
LoRAX ou vLLM ?
La documentation actuelle de vLLM décrit des modules LoRA déclarés au démarrage ainsi que leur chargement dynamique via des endpoints ou des plugins de resolver. Elle avertit que la mise à jour des adapters à chaud comporte des risques de sécurité et ne doit pas être utilisée en production en dehors d’un environnement isolé et de confiance.
La comparaison utile est opérationnelle plutôt que numérique :
| Question | LoRAX | vLLM |
|---|---|---|
| Comment les adapters de la longue traîne sont-ils découverts ? | L’ID de l’adapter peut résoudre à la demande des artifacts Hugging Face, Predibase ou du système de fichiers | Modules statiques, endpoints de gestion dynamiques ou plugins de resolver |
| Comment la résidence est-elle gérée ? | Planification explicite des échanges d’adapters entre GPU et CPU | Limites configurées pour les LoRA actifs et CPU, plus comportement du resolver |
| Quelle est l’interface de requête ? | /generate de style TGI, client Python et chat compatible OpenAI | Serving compatible OpenAI et APIs Python natives |
| Qu’est-ce qui doit guider le choix ? | Latence cold/warm, churn du cache, throughput du batching hétérogène et adéquation opérationnelle | Le même replay du workload et les mêmes critères opérationnels |
Évitez les règles telles que « LoRAX pour 1 000 adapters, vLLM pour dix ». La taille du catalogue ne détermine pas à elle seule les performances. Benchmarkez les deux solutions avec la même base, les mêmes adapters, prompts, ranks, trace d’arrivée et hardware.
Test d’acceptation pour la production
Avant d’élargir le catalogue, exécutez un replay comprenant :
- Un ensemble hot fixe pour établir le throughput et la latence warm.
- Une distribution à longue traîne pour mesurer les hits CPU et les hits du cache d’artifacts.
- Un burst d’adapters jusque-là inconnus mais allowlistés.
- Le remplacement d’un pod pour mesurer la récupération du modèle de base et des adapters.
- Un adapter indisponible ou corrompu pour vérifier l’isolation et le fallback.
- Des tenants concurrents pour vérifier l’authentification, les quotas et les labels des métriques.
Suivez ces métriques :
- taux de requêtes
- temps en file
- time to first token
- latence inter-tokens
- latence totale
- temps de chargement de l’adapter
- catégorie de cache hit
- mémoire GPU
- mémoire CPU
- octets téléchargés
- erreurs par motif
N’utilisez pas les IDs d’adapters dans des labels de métriques non bornés. Associez-les à des dimensions contrôlées ou à des traces échantillonnées.
Définissez les seuils d’acceptation avant le test. Fixez un taux maximal d’erreurs sur le chemin cold et une cible P99 warm. Définissez également une cible de cache hit pour la distribution de popularité observée, ainsi qu’un objectif de temps de récupération après la perte d’un pod.
Conclusion
LoRAX transforme le problème de nombreux fine-tunes compatibles : au lieu d’une flotte de copies du modèle de base, on obtient un problème de placement des adapters. Cela peut constituer une excellente architecture pour les workloads à longue traîne, mais ne rend pas par définition les coûts ou la latence constants. Le working set actif, le chemin d’échange, la composition des batches et la couche de stockage déterminent toujours le résultat.
Prouvez d’abord ces mécanismes sur un seul GPU. Prenez ensuite Kubernetes au sérieux : épinglez les artifacts, préservez le cache, protégez les credentials, autorisez les adapters, routez en privilégiant la localité et mesurez chaque chemin de résidence. Si LoRAX surpasse une configuration vLLM actuelle lors du même replay, la décision de déploiement reposera sur des éléments probants.
Références
- Dépôt et README de LoRAX — fonctionnalités supportées, prérequis, APIs et chart Helm
- Rapport de lancement de LoRAX et benchmark 2023 — source et conditions du graphique de coûts restauré
- Values du chart LoRAX et template du Deployment — valeurs par défaut actuelles et comportement des volumes
- Adapters LoRA de vLLM — serving statique et dynamique des adapters
- Article sur LoRA — méthode d’adaptation low-rank
- Documentation PEFT de Hugging Face — formats d’adapters et intégration de l’entraînement