Aller au contenu

Calculer le coût d’un LLM local à grande échelle

Calculer le coût d’un LLM local à grande échelle

Section intitulée « Calculer le coût d’un LLM local à grande échelle »

Un modèle de langage de grande taille (LLM, Large Language Model) local ne devient pas rentable parce qu’une carte graphique est déjà branchée dans la baie. Le compromis central est brutal : acheter de la capacité fixe réduit le coût marginal par requête à charge soutenue, mais transforme chaque période creuse en amortissement qui regarde le plafond.

→ Lire l’explication complète de la marmotte

Le nombre de requêtes ne dimensionne rien à lui seul. Une requête peut contenir 100 unités de texte et produire une réponse de 50 unités, ou injecter 20 000 unités de contexte pour générer trois lignes. Ces unités sont les jetons, fragments de texte traités par le modèle. Le coût de calcul dépend principalement des jetons d’entrée et de sortie, avec une pénalité particulière sur les sorties : générer un jeton impose une étape séquentielle, donc limite le débit.

La métrique de capacité à suivre est le débit en jetons de sortie par seconde, puis le débit total en jetons par seconde. Pour une charge stable, calculer :

débit requis = requêtes par seconde × jetons de sortie moyens
capacité utile = débit mesuré par accélérateur × taux d'utilisation cible
nombre d'accélérateurs = débit requis / capacité utile

Le taux d’utilisation cible ne doit pas dépasser 65 à 75 %. Au-delà, la file d’attente absorbe toute variation de trafic et la latence explose sans prévenir. Dimensionner à 95 % parce que le benchmark a tenu cinq minutes, c’est traiter la production comme un concours de diapositives.

La moyenne est trompeuse. Retenir au minimum les percentiles 50, 95 et 99 de jetons d’entrée, de jetons de sortie et de requêtes simultanées. Un percentile 99 de contexte cinq fois supérieur à la médiane peut monopoliser la mémoire vidéo et évincer plusieurs requêtes courtes. Le service devient alors lent pour tout le monde, avec cette élégance particulière des incidents qui n’apparaissent que dans les métriques après coup.

La mémoire vidéo (VRAM, Video Random Access Memory) fixe souvent la capacité avant le calcul. Les poids du modèle, le contexte et le cache clé-valeur doivent y résider. Le cache clé-valeur conserve des calculs intermédiaires pour éviter de retraiter toute la conversation à chaque jeton produit. Sa taille augmente avec la longueur du contexte, le nombre de requêtes actives et la précision numérique. Réduire la précision des poids aide, mais ne fait pas disparaître le cache : une quantification à 4 bits ne transforme pas une carte de 48 Go en grange illimitée.

Les architectures de LLM locaux doivent donc séparer trois profils : conversation interactive à faible latence, traitement par lot tolérant l’attente, et enrichissement documentaire. Mélanger ces profils sur le même pool matériel sans ordonnanceur de priorité revient à laisser le traitement nocturne réserver la salle de réunion pendant l’incident de journée.

Modèle économique CAPEX, OPEX et seuil de bascule

Section intitulée « Modèle économique CAPEX, OPEX et seuil de bascule »

Le coût total de possession (TCO, Total Cost of Ownership) doit couvrir l’investissement matériel (CAPEX, Capital Expenditure) et l’exploitation récurrente (OPEX, Operational Expenditure). Comparer seulement le prix d’une accélératrice graphique (GPU, Graphics Processing Unit) au tarif d’une interface distante est une méthode efficace pour produire un tableur faux avec des couleurs rassurantes.

Pour chaque serveur, intégrer :

  • acquisition des GPU, processeurs, mémoire vive, stockage local et réseau ;
  • amortissement sur trois à cinq ans, selon politique comptable et durée de support ;
  • énergie IT et refroidissement, via le facteur d’efficacité énergétique du site (PUE, Power Usage Effectiveness) ;
  • maintenance matérielle, pièces de rechange et contrat de support ;
  • licences de virtualisation, d’observabilité ou de support logiciel ;
  • exploitation humaine : mises à jour de pilotes, gestion des incidents, capacité et sécurité ;
  • capacité inactive imposée par la haute disponibilité.

Le coût horaire interne s’écrit ainsi :

coût horaire = (CAPEX / heures d'amortissement)
+ puissance électrique moyenne × PUE × prix du kWh
+ OPEX horaire

Le coût par million de jetons doit être calculé sur les jetons effectivement servis, pas sur la capacité théorique. Une machine qui peut produire 1 000 jetons par seconde mais qui n’en produit que 150 en moyenne porte un coût réel près de sept fois supérieur à son rendement de benchmark. Les GPU détestent le vide, même si le vide est présenté comme une « réserve stratégique ».

La recommandation est nette : réserver le local aux flux récurrents, prévisibles, sensibles ou volumineux, dont le taux d’occupation dépasse durablement 50 % de la capacité installée. Pour les pics rares, les expérimentations et les modèles dont le besoin varie chaque semaine, conserver une capacité externe plafonnée et contrôlée coûte généralement moins cher que surprovisionner le matériel interne.

Le seuil de bascule dépend de quatre variables : tarif externe par million de jetons, coût horaire interne complet, débit réellement mesuré et taux d’occupation. Il ne dépend pas du prix catalogue d’un GPU. Une décision d’achat sans mesure de charge sur au moins plusieurs cycles métier reste un pari, pas une stratégie.

Un GPU ne fournit pas un débit unique. Le débit varie avec le modèle, sa quantification, la longueur du contexte, la taille des lots et le moteur d’inférence. Une quantification représente les paramètres numériques avec moins de bits afin de réduire mémoire et bande passante. Elle peut diminuer le coût par jeton, mais elle modifie aussi la qualité de réponse et la stabilité de certains usages structurés. Mesurer les taux d’erreur métier avant de déclarer victoire : économiser 30 % de calcul pour doubler les corrections humaines est un classique du genre.

Le regroupement de requêtes, ou batching, augmente le débit en calculant plusieurs demandes ensemble. Il augmente aussi le délai avant traitement, car le serveur attend d’avoir un lot suffisamment rempli. Fixer une fenêtre maximale d’attente, par exemple 20 à 100 millisecondes selon l’objectif de latence, puis mesurer la latence de bout en bout au percentile 95. Le débit maximal sans contrainte de délai n’est pas une capacité de production pour un assistant interactif.

Le dimensionnement doit séparer :

  1. la capacité nominale pour le trafic médian ;
  2. une marge pour le percentile 95 et les opérations de maintenance ;
  3. une capacité de secours pour la perte d’un serveur ou d’un GPU ;
  4. un mécanisme de délestage pour les demandes longues ou non prioritaires.

La redondance active-active peut réduire la capacité inutilisée, à condition que le répartiteur de charge connaisse la mémoire consommée par chaque requête. Répartir seulement au nombre de connexions est insuffisant : une conversation avec un contexte long coûte davantage qu’une requête de classification de quelques mots.

Pour les recherches sémantiques, découpler l’indexation et la génération réduit souvent le coût global. Les représentations vectorielles, détaillées dans la page sur les embeddings, sont moins coûteuses à produire qu’une réponse générative et permettent d’écarter des documents avant d’occuper le modèle principal. Il faut toutefois budgéter le stockage, les réindexations et les GPU nécessaires aux traitements par lot.

Le calcul suivant part d’une mesure réelle du moteur d’inférence. Il ne remplace pas un test de charge : il force seulement à exposer les hypothèses avant que le budget ne devienne un animal mythologique.

# calcule le nombre de GPU nécessaire à partir de mesures de production
import math
requests_per_second = 6.0 # débit de pointe observé
output_tokens_per_request = 280 # percentile 95 des sorties
gpu_tokens_per_second = 950 # mesure avec le modèle, le contexte et le moteur visés
target_utilization = 0.70 # marge pour la file d'attente et les variations
high_availability_spare = 1 # perte tolérée d'un GPU
required_tokens_per_second = requests_per_second * output_tokens_per_request
usable_tokens_per_gpu = gpu_tokens_per_second * target_utilization
active_gpus = math.ceil(required_tokens_per_second / usable_tokens_per_gpu)
total_gpus = active_gpus + high_availability_spare
print(f"Débit requis : {required_tokens_per_second:.0f} jetons/s")
print(f"GPU actifs : {active_gpus}")
print(f"GPU avec réserve : {total_gpus}")

Ce script suppose que les requêtes ont déjà été séparées par classe de service. Ajouter les traitements par lot au même chiffre fausse le résultat. Les batchs doivent consommer la capacité résiduelle, être interrompus à l’approche du seuil de latence, puis reprendre. Cette préemption vaut plus qu’un second cluster acheté pour faire tourner des tâches non urgentes à deux heures du matin.

Un service local réduit l’exposition des données à un fournisseur externe, mais ne garantit ni confidentialité absolue ni contrôle des usages. Les invites, documents joints, réponses, journaux et caches peuvent contenir des données sensibles. Le modèle ne chiffre rien par magie, malgré la persistance de cette croyance dans certaines démonstrations commerciales.

L’attaque économique la plus directe est le déni de service par épuisement de jetons : longues entrées, contextes répétés, génération volontairement longue et concurrence élevée. Imposer des plafonds distincts sur la taille d’entrée, la taille de sortie, le nombre de requêtes simultanées et le budget de jetons par identité. Ces limites doivent être appliquées avant l’envoi au moteur, pas après avoir réservé la VRAM.

L’injection d’invite vise à faire ignorer les règles applicatives ou à extraire le contenu du contexte. Un filtrage de texte ne constitue pas une frontière de sécurité. Ne jamais donner au modèle des identifiants permettant d’agir sans contrôle serveur. Toute action sur un système tiers doit passer par une autorisation déterministe, liée à l’identité, à la ressource et à l’opération demandée. Les mécanismes d’identité et d’accès restent responsables de l’autorisation, même si le modèle formule une phrase très convaincante.

Les modèles téléchargés, conteneurs, pilotes GPU et dépendances Python constituent une chaîne logicielle à vérifier. Épingler les versions, vérifier les signatures ou hachages des artefacts, scanner les images et isoler les processus d’inférence. Un modèle compromis peut exfiltrer des données via les journaux, les appels d’outils ou un comportement dégradé difficile à diagnostiquer. La sécurité de la chaîne d’approvisionnement n’a rien de glamour, ce qui explique probablement pourquoi elle tombe souvent après le papier peint.

Les secrets d’accès aux sources documentaires, aux services d’authentification et aux éventuels fournisseurs de secours ne doivent jamais figurer dans l’image de conteneur ni dans les paramètres visibles du processus. Stocker les secrets dans un gestionnaire dédié, les injecter à l’exécution et les faire tourner selon une durée définie. La rotation doit être testée sans redémarrage global, sinon elle devient un exercice théorique avec sirène incluse.

Superviser au minimum : jetons par seconde, longueur des files, latence aux percentiles 50, 95 et 99, occupation VRAM, erreurs de mémoire, température, consommation électrique, taux de rejet par limite et coût par classe de trafic. Les alertes doivent porter sur la saturation durable et la dérive de coût, pas seulement sur l’indisponibilité. Un service qui répond en 40 secondes est techniquement vivant, au sens où une imprimante coincée est vivante.

Sauvegarder les configurations de routage, limites, modèles autorisés, index documentaires et métadonnées d’accès. Les poids de modèles volumineux peuvent être restaurés depuis un registre vérifié plutôt que sauvegardés à chaque cycle, si le délai de téléchargement respecte l’objectif de reprise. Définir l’objectif de temps de reprise et l’objectif de point de reprise avant de choisir cette économie. Une copie de 400 Go sur un lien saturé est une forme de méditation forcée.

Un système local de génération de texte reçoit des demandes contenant du texte, puis produit une réponse morceau par morceau. Chaque morceau demande du calcul et de la mémoire. Plus le texte fourni est long, plus la mémoire nécessaire augmente. Plus la réponse est longue, plus le temps de calcul augmente. Il faut donc mesurer les demandes réelles : combien arrivent chaque seconde, combien de texte elles contiennent, combien elles produisent et combien arrivent en même temps.

Les cartes de calcul servent à traiter ces demandes. Leur nombre dépend du débit attendu, mais aussi de la marge nécessaire quand le trafic augmente ou quand une machine tombe en panne. Une machine inutilisée coûte tout de même son achat, son électricité, son refroidissement et son entretien. À l’inverse, trop peu de machines créent une file d’attente et des réponses tardives.

Le coût doit comparer l’achat et l’exploitation des machines avec le prix d’un service externe. Garder localement les demandes fréquentes, prévisibles ou contenant des données sensibles peut réduire la facture. Garder une capacité externe pour les pics évite d’acheter du matériel qui dort.

Des limites doivent empêcher une personne ou un programme de demander des textes trop longs ou trop nombreux. Les accès aux documents et aux autres systèmes restent contrôlés par des règles séparées. Enfin, il faut surveiller les délais, la mémoire, l’énergie, les erreurs et les dépenses, puis pouvoir restaurer les réglages et les données si un serveur échoue.

À lire aussi

Pages voisines

: les deux pages se citent l’une l’autre.