Bonnes pratiques de production
Bonnes pratiques de production
Cette leçon rassemble les bonnes pratiques essentielles pour déployer une application basée sur l’API OpenAI en production. C’est votre checklist avant de mettre en service.
1. Architecture du client
Singleton avec configuration centralisée
from openai import OpenAI
from functools import lru_cache
@lru_cache(maxsize=1)
def get_client() -> OpenAI:
"""Client singleton avec configuration de production."""
return OpenAI(
max_retries=3,
timeout=30.0,
)
# Partout dans votre code :
client = get_client()
Variables d’environnement
import os
# OBLIGATOIRE : ne jamais mettre de clés en dur
REQUIRED_ENV = ["OPENAI_API_KEY"]
for var in REQUIRED_ENV:
if not os.environ.get(var):
raise RuntimeError(f"Variable {var} manquante")
# Configuration par environnement
MODEL = os.environ.get("OPENAI_MODEL", "gpt-5.3")
MAX_TOKENS = int(os.environ.get("OPENAI_MAX_TOKENS", "4096"))
TEMPERATURE = float(os.environ.get("OPENAI_TEMPERATURE", "0.7"))
2. Gestion des prompts
Séparer les prompts du code
# prompts/classification.txt
PROMPT_CLASSIFICATION = """Vous êtes un classifieur de texte.
Classifiez le texte suivant dans une des catégories :
{categories}
Texte : {texte}
Répondez uniquement avec le nom de la catégorie."""
def classifier(texte: str, categories: list[str]) -> str:
prompt = PROMPT_CLASSIFICATION.format(
categories=", ".join(categories),
texte=texte
)
response = get_client().responses.create(
model=MODEL,
input=prompt,
temperature=0.0
)
return response.output_text.strip()
Versionner les prompts
PROMPTS = {
"classification_v1": "Classifiez : {texte}",
"classification_v2": "Analysez et classifiez précisément : {texte}",
}
# En production, utilisez une version spécifique
ACTIVE_PROMPT = os.environ.get("PROMPT_VERSION", "classification_v2")
3. Timeouts et limites
def appel_avec_garde_fous(prompt: str) -> str:
"""Appel API avec toutes les protections."""
# Limite la taille du prompt
MAX_PROMPT_CHARS = 50000
if len(prompt) > MAX_PROMPT_CHARS:
prompt = prompt[:MAX_PROMPT_CHARS]
print(f"Prompt tronqué a {MAX_PROMPT_CHARS} caractères")
response = get_client().responses.create(
model=MODEL,
input=prompt,
max_output_tokens=MAX_TOKENS,
temperature=TEMPERATURE,
)
return response.output_text
4. Fallback entre modèles
from openai import RateLimitError, InternalServerError
def appel_avec_fallback(prompt: str) -> str:
"""Essaie GPT-5.3 puis tombe sur o4-mini si erreur."""
modeles = ["gpt-5.3", "o4-mini"]
for modele in modeles:
try:
response = get_client().responses.create(
model=modele,
input=prompt
)
return response.output_text
except (RateLimitError, InternalServerError) as e:
print(f"{modele} indisponible : {e}")
continue
raise RuntimeError("Tous les modèles sont indisponibles")
5. Traitement par lots (batch)
import asyncio
from openai import AsyncOpenAI
async def traiter_batch(prompts: list[str], max_concurrent: int = 5) -> list:
"""Traite un lot de prompts avec concurrence limitée."""
client = AsyncOpenAI()
semaphore = asyncio.Semaphore(max_concurrent)
resultats = []
async def traiter_un(index: int, prompt: str):
async with semaphore:
response = await client.responses.create(
model="gpt-5.3",
input=prompt
)
return index, response.output_text
tasks = [traiter_un(i, p) for i, p in enumerate(prompts)]
results = await asyncio.gather(*tasks, return_exceptions=True)
# Trier par index pour maintenir l'ordre
sorted_results = sorted(
[(idx, res) for idx, res in results if not isinstance(res, Exception)],
key=lambda x: x[0]
)
return [res for _, res in sorted_results]
# prompts = ["Question 1", "Question 2", "Question 3"]
# resultats = asyncio.run(traiter_batch(prompts))
6. Tests et validation
def test_api_disponible():
"""Vérifie que l'API est accessible."""
try:
response = get_client().responses.create(
model="gpt-5.3",
input="test",
max_output_tokens=5
)
assert response.output_text is not None
print("API OK")
return True
except Exception as e:
print(f"API KO : {e}")
return False
def test_prompt_quality(prompt: str, attendu: str) -> bool:
"""Vérifie qu'un prompt retourne un résultat cohérent."""
response = get_client().responses.create(
model="gpt-5.3",
input=prompt,
temperature=0.0
)
resultat = response.output_text.lower()
return attendu.lower() in resultat
# Tests de régression des prompts
assert test_prompt_quality(
"Classifiez 'excellent produit' : positif ou négatif ?",
"positif"
)
7. Checklist de mise en production
Avant de déployer, vérifiez chaque point :
Infrastructure
- Variables d’environnement configurées (OPENAI_API_KEY, etc.)
- Timeouts et max_retries configurés
- Logging structuré en place
- Monitoring des coûts activé
Résilience
- Gestion d’erreurs complète (tous les codes HTTP)
- Backoff exponentiel pour les retries
- Circuit breaker pour les pannes prolongées
- Fallback vers un modèle alternatif
Sécurité
- Clé API jamais exposée dans le code ou les logs
- Validation des inputs utilisateur
- Rate limiting côté client
- Pas de données sensibles dans les prompts
Performance
- Streaming activé pour les interfaces utilisateur
- Batch processing pour les traitements en volume
- Cache pour les requêtes répétitives
- Choix du modèle adapté à chaque tâche
Coûts
- Budget quotidien défini
- Alertes configurées
- max_output_tokens fixé quand possible
- Modèle le plus économique sélectionné par tâche
Points clés à retenir
- Centralisez la configuration du client avec un singleton
- Séparez et versionnez vos prompts hors du code
- Implémentez un fallback entre modèles pour la haute disponibilité
- Utilisez le traitement par lots avec concurrence limitée pour le volume
- Testez vos prompts avec des assertions de qualité
- Suivez la checklist complète avant chaque mise en production