RTX 3090: Energy Cost of Local LLMs Measured in Euros

Le brief IA que les pros lisent chaque soir
Les 7 actus IA du jour, décryptées en 5 min. Gratuit.
Inclus dès l'inscription : notre sélection des meilleurs guides & comparatifs IA.
Choisis ton rythme
Gratuit · Pas de spam · Désabonnement en 1 clic
RTX 3090 : Coût énergétique des LLM locaux mesuré en euros
Modèles de Langage
Combien coûte réellement l'exécution d'un LLM local ? (Euros par million de tokens, mesuré)
La consommation électrique réelle des GPU a été mesurée pour huit modèles locaux sur une seule RTX 3090 — et le moins cher n'était ni le plus petit, ni le plus cher le plus grand.
La machine utilisée est « ardi » — un ordinateur openSUSE avec une seule RTX 3090 (24 Go). Un benchmark contrôlé y a été exécuté : trois modèles locaux servis par ollama, chacun fonctionnant sous une charge de travail fixe identique, tandis qu'un tableau de bord évaluait chaque exécution en fonction de l'énergie GPU réelle consommée. Ce n'est pas une estimation de la puissance thermique, ni une supposition rapide — l'énergie a été échantillonnée à partir de nvidia-smi toutes les 10 secondes et intégrée sur la fenêtre exacte de début à fin de chaque exécution, selon le tarif d'électricité jour/nuit réel : 0,30 BGN le jour / 0,18 BGN la nuit (lev bulgare ; converti en EUR tout au long de cet article au taux fixe de la BCE, 1 BGN ≈ 0,5113 €).
Le résultat est un chiffre par modèle : euros par million de tokens de sortie. Cinq des huit modèles mesurés étaient moins chers qu'une API cloud hébergée. Trois ne l'étaient pas — et ce ne sont pas ceux que l'on devinerait uniquement en fonction du nombre de paramètres.
La revendication que l'on voulait tester
La sagesse populaire est que l'inférence locale est l'option la moins chère — le GPU a été acheté, le token marginal est gratuit, le cloud est celui qui fait tourner le compteur. Chaque partie mérite un chiffre, donc voici celui qui a été cherché : le coût énergétique marginal de génération d'un token localement, modèle par modèle, et comment cela se compare à ce qu'une API de classe « Flash » hébergée facture pour le même token.
Pour faire de cela une mesure et non un argument, trois choses ont été maintenues constantes : la même charge de travail pour chaque modèle, le même matériel, et un compteur de confiance lisant le GPU pendant chaque exécution. La troisième est la plus difficile à la maison — c'est là qu'intervient l'instrument.
Trois modèles ont été choisis pour couvrir la gamme de tailles gardée sur la machine : gemma3:1b (petit), gemma4:26b (Gemma 4 de Google — 25,8 milliards de paramètres sous le capot ; ollama l'arrondit simplement à « 26b » dans l'étiquette), et gemma3:27b (l'ancien grand modèle). Tous trois sont des poids GGUF quantifiés en Q4_K_M tirés via ollama, donc la comparaison est équivalente en termes de quantification. Chacun a reçu la même charge de travail fixe — une boucle de générations de 256 tokens tournant à travers cinq invites fixes — soutenue pendant environ 4 minutes (240 s) afin que le GPU atteigne un état stable plutôt que d'être jugé sur un premier appel à froid.
Pendant que chaque modèle fonctionnait, il a été suivi comme une expérience tarifée dans HomeLab Monitor — un tableau de bord open source, MIT, un conteneur. Il échantillonne la puissance GPU à partir de nvidia-smi toutes les 10 s, et pour une exécution suivie, il intègre la puissance sur la fenêtre de début à fin de l'exécution en kWh, puis multiplie par le tarif en vigueur (jour ou nuit) — dans la devise configurée, BGN. Cela convertit « quel a été le coût de ce modèle ? » d'une supposition en un chiffre mesuré ; il est ensuite converti en EUR pour plus de lisibilité.
Calcul du coût
Ensuite, l'arithmétique qui transforme une exécution de 4 minutes en un taux comparable :
€ par 1M tokens de sortie = (coût_exécution_BGN × 0,5113) ÷ (tokens_sortie / 1 000 000)
Le benchmark de génération de trois modèles ci-dessous est reproductible de bout en bout. Voici comment le mettre en place sur votre propre machine.
Étape 1 - Mettre en place le moniteur (un conteneur)
Sur la machine avec le GPU :
COMPOSE_URL=https://raw.githubusercontent.com/SikamikanikoBG/homelab-monitor/main/docker-compose.yml
curl -fsSLO "$COMPOSE_URL"
docker compose up -d
Ouvrez http://<hub>:9800. L'hôte sur lequel il fonctionne apparaît immédiatement — CPU, RAM, disques, et (s'il en voit un) le GPU avec VRAM par modèle et consommation d'énergie en direct. Pas de configuration. C'est le compteur. Vérifiez les paramètres pour la devise et le tarif avec lequel il est configuré avant de faire confiance à un chiffre en € qu'il vous montre.
Étape 2 - Générer une clé d'ingestion
Le script de benchmark doit pousser les exécutions dans le hub, donc il a besoin d'une clé. Paramètres → Intégrations → Créer une clé. La clé (une chaîne hlm_…) est affichée une seule fois — copiez-la alors, vous ne la reverrez plus. Gardez-la dans une variable d'environnement ; ne la collez pas dans le script.
export HOMELAB_KEY="hlm_xxxxxxxxxxxxxxxxxxxx"
Le même panneau a un lien pour télécharger le client Python que vous utiliserez à l'étape 3, et un guide de démarrage rapide à copier-coller — donc cet écran couvre les deux étapes suivantes.
Étape 3 - Récupérer le client léger
Le hub sert son propre client Python. Il est uniquement basé sur la bibliothèque standard — rien à installer avec pip :
CLIENT_URL=http://<hub>:9800/static/homelab_run.py
curl -O "$CLIENT_URL"
Ce fichier est l'ensemble de l'API de suivi. Le modèle est délibérément petit : configurez une fois, puis enveloppez n'importe quel bloc de travail dans un gestionnaire de contexte d'exécution et enregistrez les métriques à l'intérieur.
import homelab_run as homelab
homelab.configure(url="http://<hub>:9800", key="hlm_...")
with homelab.run("llm-cost-gemma3-1b",
params={"model": "gemma3:1b", "engine": "ollama",
"gpu": "RTX 3090 24GB", "num_predict": 256}) as r:
# ... effectuez le travail ...
r.log_metric("tokens_per_sec", tps, step=i)
Lorsque le bloc with s'ouvre, le hub marque le début de l'exécution ; lorsqu'il se ferme, il marque la fin et évalue l'énergie GPU consommée entre les deux. La fenêtre est la mesure.
Étape 4 - Écrire le benchmark
La charge de travail est simplement l'API ollama /api/generate dans une boucle, lisant les champs que ollama renvoie afin d'obtenir de véritables tokens par seconde plutôt qu'une approximation basée sur l'horloge. Les deux champs qui comptent sont eval_count (tokens générés) et eval_duration (nanosecondes passées à les générer) :
import json, time, urllib.request
OLLAMA = "http://localhost:11434"
def ollama_generate(model, [prompt](/glossaire/prompt)):
body = json.dumps({
"model": model, "prompt": prompt, "stream": False,
"options": {"num_predict": 256, "temperature": 0.7},
req = urllib.request.Request(OLLAMA + "/api/generate", data=body,
headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=600) as resp:
return json.loads(resp.read())
Ensuite, faites fonctionner chaque modèle sous charge pendant une durée fixe, enveloppée dans une exécution suivie :
def bench(model, duration_s=240):
ollama_generate(model, "Say hello.") # échauffement - exclure le démarrage à froid
run = homelab.run(f"llm-cost-{model.replace(':', '-')}",
params={"model": model, "engine": "ollama",
"gpu": "RTX 3090 24GB", "num_predict": 256,
"workload": "fixed-prompt-loop"},
tags=["llm-cost", "benchmark"])
t0 = time.time(); step = 0
while time.time() - t0 < duration_s:
res = ollama_generate(model, PROMPTS[step % len(PROMPTS)])
ec, ed = res.get("eval_count", 0), res.get("eval_duration", 1) # ed en ns
tps = ec / (ed / 1e9) if ed else 0.0
r.log_metric("tokens_per_sec", round(tps, 2), step=step)
return run.id, tot_out
Un appel d'échauffement avant la fenêtre chronométrée maintient la latence de démarrage à froid hors de la mesure. Le time.sleep(15) mis entre les modèles (non montré) garde chaque fenêtre tarifée proprement séparée afin que la queue d'un modèle ne déborde pas dans la facture du suivant.
Étape 5 - Lire l'exécution, tarifée
Exécutez le script pour tous les trois modèles et ouvrez l'onglet Expériences. Chaque exécution est maintenant une ligne portant son énergie et son coût réels :
Cliquez sur une exécution et vous obtenez la courbe de puissance GPU pour cette fenêtre exacte, avec la légende tarifée en dessous — la matière brute à partir de laquelle le chiffre en euros est calculé :
Le hub expose également le coût de chaque exécution de manière programmatique, donc la division finale peut se faire dans le script :
pulled = homelab.pull(run_id) # coût, énergie_kwh, avg_w, courbe de puissance - le coût est en BGN
eur_per_mtok = round((pulled["cost"] * 0.5113) / (tot_out / 1e6), 4)
Ensuite, cinq autres modèles ont été ajoutés — GLM-4.5-Air (106B), DeepSeek-R1-Distill (32.8B), Seed-OSS (36B), Devstral (24B), et Qwen3-Coder (30.5B) — tirés d'un benchmark d'agent de codage séparé déjà exécuté sur la même machine (même GPU, même tarif, même méthode coût÷tokens, mais de réelles tâches d'agent multi-étapes au lieu d'une boucle de génération dédiée de 240 secondes — noté là où cela compte, dans les avertissements ci-dessous). Huit modèles, une échelle :
Et la référence cloud mesurée (prix de liste, juin 2026) : un modèle de classe Flash hébergé — Gemini 2.5 Flash, GPT-4o-mini — coûte environ 0,60 $ par 1M de tokens de sortie (~0,55 €); le niveau le moins cher (Gemini 3.1 Flash-Lite) est autour de 0,40 $.
Cinq des huit modèles sont moins chers que la référence cloud. Trois ne le sont pas — et les trois qui ne le sont pas ne sont pas ceux que l'on choisirait en fonction du nombre de paramètres.
GLM-4.5-Air est le plus grand modèle de la liste, avec 106B paramètres, et il coûte 1,040 €/1M — réellement plus cher que l'API cloud, juste pour l'électricité, avant même de compter un centime du prix d'achat du GPU. Cette partie correspond à l'intuition originale : grand modèle, lent, coûteux.
Mais DeepSeek-R1-Distill est à peine un tiers de la taille de GLM — 32,8B paramètres — et c'est le modèle le plus cher de toute la liste, à 1,526 €/1M. Il consomme moins d'énergie que gemma3:27b (155 W contre 283 W) — et reste le plus cher par token de tous les modèles testés.
Remarque méthodologique
Une note méthodologique qui compte ici, en amont plutôt que cachée : les trois modèles gemma ont été mesurés sur un benchmark de génération soutenue de 240 secondes construit pour cet article. Les cinq autres — y compris DeepSeek-R1-Distill — proviennent d'un benchmark antérieur séparé de tâches réelles d'agent de codage multi-étapes (appels d'outils, raisonnement multi-tours) sur le même GPU et tarif, utilisant la formule identique coût÷tokens de sortie. Cette distinction est la raison pour laquelle DeepSeek apparaît comme il le fait : sa vitesse de génération brute lorsqu'il produit activement des tokens est respectable à 6,7 tokens/sec. Mais la vitesse de génération brute n'est pas ce pour quoi le compteur facture. Le compteur facture le temps sur la carte, et DeepSeek — un modèle distillé par raisonnement — passe la plupart de ce temps à délibérer entre les générations, pas à générer. Son taux de livraison effectif (tokens de sortie ÷ temps total d'exécution, délibération incluse) s'élève à 3,7 tokens/sec, le plus bas de tous les modèles testés — bien en dessous des 7,1 de Seed-OSS et des 5,0 de GLM. C'est ce que le prix suit réellement.
La taille n'a jamais été le mécanisme. La vitesse effective l'était — et la vitesse effective.
Brief IA — L'actualité IA en français
L'essentiel de l'actualité de l'intelligence artificielle, décrypté et expliqué chaque jour.