Monitoring coûts et usage
Monitoring coûts et usage
Les coûts API peuvent exploser rapidement si vous ne les surveillez pas. Cette leçon vous apprend à suivre, estimer et contrôler vos dépenses en production.
Comprendre la facturation
Les coûts sont calculés par million de tokens, avec des prix différents pour l’input et l’output :
from openai import OpenAI
client = OpenAI()
# Chaque réponse inclut les métriques d'usage
response = client.responses.create(
model="gpt-5.3",
input="Expliquez la facturation de l'API OpenAI."
)
usage = response.usage
print(f"Input tokens : {usage.input_tokens}")
print(f"Output tokens : {usage.output_tokens}")
print(f"Total tokens : {usage.total_tokens}")
# L'output coûte plus cher que l'input !
Calculateur de coûts
from dataclasses import dataclass
@dataclass
class TarifModele:
input_par_million: float
output_par_million: float
# Prix approximatifs en USD par million de tokens
# Vérifiez toujours les prix actuels sur platform.openai.com/pricing
TARIFS = {
"gpt-5.3": TarifModele(input_par_million=2.0, output_par_million=8.0),
"gpt-5.4": TarifModele(input_par_million=10.0, output_par_million=30.0),
"o3-pro": TarifModele(input_par_million=15.0, output_par_million=60.0),
"o4-mini": TarifModele(input_par_million=0.5, output_par_million=2.0),
}
def calculer_cout(modele: str, input_tokens: int,
output_tokens: int) -> float:
"""Calcule le coût d'un appel en USD."""
tarif = TARIFS.get(modele)
if not tarif:
raise ValueError(f"Modèle inconnu : {modele}")
cout_input = (input_tokens / 1_000_000) * tarif.input_par_million
cout_output = (output_tokens / 1_000_000) * tarif.output_par_million
return cout_input + cout_output
# Exemple
cout = calculer_cout("gpt-5.3", input_tokens=1000, output_tokens=500)
print(f"Coût : ${cout:.6f}")
# Résultat : Coût : $0.006000
Tracker de coûts en temps réel
import json
from datetime import datetime, date
from collections import defaultdict
class CostTracker:
"""Suivi des coûts API en temps réel."""
def __init__(self, budget_quotidien_usd: float = 10.0):
self.budget_quotidien = budget_quotidien_usd
self.couts_par_jour: dict[str, float] = defaultdict(float)
self.couts_par_modele: dict[str, float] = defaultdict(float)
self.appels_par_jour: dict[str, int] = defaultdict(int)
self.total_tokens = 0
def enregistrer(self, modele: str, input_tokens: int,
output_tokens: int):
"""Enregistre les coûts d'un appel."""
cout = calculer_cout(modele, input_tokens, output_tokens)
aujourdhui = date.today().isoformat()
self.couts_par_jour[aujourdhui] += cout
self.couts_par_modele[modele] += cout
self.appels_par_jour[aujourdhui] += 1
self.total_tokens += input_tokens + output_tokens
return cout
def budget_restant(self) -> float:
"""Retourne le budget restant pour aujourd'hui."""
aujourdhui = date.today().isoformat()
return self.budget_quotidien - self.couts_par_jour[aujourdhui]
def alerte_budget(self) -> bool:
"""Vérifie si le budget est proche de la limite."""
restant = self.budget_restant()
if restant <= 0:
print("ALERTE : Budget quotidien dépassé !")
return True
elif restant < self.budget_quotidien * 0.2:
print(f"ATTENTION : Il reste ${restant:.2f} sur le budget quotidien")
return True
return False
def rapport(self) -> dict:
"""Génère un rapport de coûts."""
return {
"cout_total_usd": sum(self.couts_par_jour.values()),
"cout_aujourdhui_usd": self.couts_par_jour.get(
date.today().isoformat(), 0
),
"budget_restant_usd": self.budget_restant(),
"couts_par_modele": dict(self.couts_par_modele),
"total_tokens": self.total_tokens,
}
# Utilisation
tracker = CostTracker(budget_quotidien_usd=5.0)
response = client.responses.create(
model="gpt-5.3",
input="Bonjour !"
)
cout = tracker.enregistrer(
modele="gpt-5.3",
input_tokens=response.usage.input_tokens,
output_tokens=response.usage.output_tokens
)
print(f"Coût de cet appel : ${cout:.6f}")
print(json.dumps(tracker.rapport(), indent=2))
Client avec contrôle budgétaire
class BudgetControlledClient:
"""Client qui refuse les appels si le budget est dépassé."""
def __init__(self, budget_quotidien: float = 10.0):
self.client = OpenAI()
self.tracker = CostTracker(budget_quotidien_usd=budget_quotidien)
def create(self, model: str, input: str, **kwargs) -> object:
"""Appel API avec contrôle budgétaire."""
# Vérifier le budget avant l'appel
if self.tracker.budget_restant() <= 0:
raise RuntimeError(
"Budget quotidien épuisé. "
f"Dépensé : ${self.tracker.rapport()['cout_aujourdhui_usd']:.2f}"
)
response = self.client.responses.create(
model=model,
input=input,
**kwargs
)
cout = self.tracker.enregistrer(
modele=model,
input_tokens=response.usage.input_tokens,
output_tokens=response.usage.output_tokens
)
# Alerte si budget faible
self.tracker.alerte_budget()
return response
# Utilisation
budget_client = BudgetControlledClient(budget_quotidien=2.0)
try:
response = budget_client.create("gpt-5.3", "Bonjour !")
print(response.output_text)
except RuntimeError as e:
print(f"Bloqué : {e}")
Optimiser les coûts
1. Choisir le bon modèle
# Coût relatif par tâche (approximatif) :
# Classification simple : o4-mini ~$0.0005 vs GPT-5.4 ~$0.01
# Le bon modèle fait une différence de 20x sur les coûts !
def appel_optimise(prompt: str, complexite: str) -> str:
"""Choisit le modèle le plus économique adapté."""
model = {
"simple": "o4-mini",
"standard": "gpt-5.3",
"complexe": "gpt-5.4",
}.get(complexite, "gpt-5.3")
response = client.responses.create(model=model, input=prompt)
return response.output_text
2. Caching des réponses
import hashlib
class CachedClient:
"""Client avec cache pour éviter les appels redondants."""
def __init__(self):
self.client = OpenAI()
self.cache: dict[str, str] = {}
def create(self, model: str, input: str, **kwargs) -> str:
# Créer une clé de cache
cache_key = hashlib.md5(
f"{model}:{input}:{json.dumps(kwargs, sort_keys=True)}".encode()
).hexdigest()
if cache_key in self.cache:
print("Cache hit !")
return self.cache[cache_key]
response = self.client.responses.create(
model=model, input=input, **kwargs
)
self.cache[cache_key] = response.output_text
return response.output_text
3. Limiter les tokens de sortie
# Toujours fixer max_output_tokens pour les tâches prévisibles
response = client.responses.create(
model="gpt-5.3",
input="Classifiez ce texte : positif, négatif ou neutre.",
max_output_tokens=10 # On attend un seul mot
)
Points clés à retenir
- Les coûts dépendent du modèle ET de la direction (input vs output)
- Implémentez un tracker de coûts avec alertes budgétaires
- Utilisez le bon modèle pour chaque tâche : o4-mini pour le volume, GPT-5.3 par défaut
- Le caching peut réduire drastiquement les coûts pour les requêtes répétitives
- Fixez
max_output_tokensquand la longueur de réponse est prévisible - Consultez le dashboard OpenAI pour le suivi officiel de votre consommation