Bonnes pratiques de production
De la preuve de concept au déploiement
Vous maîtrisez maintenant tous les paramètres de l’API Chat Completions. Cette dernière leçon consolide tout ce que vous avez appris en une checklist de production actionnable, et ouvre la voie vers les formations suivantes.
Checklist de déploiement en production
1. Authentification et sécurité
import os
# TOUJOURS : clé API en variable d'environnement
api_key = os.getenv("MISTRAL_API_KEY")
assert api_key, "MISTRAL_API_KEY non définie"
# JAMAIS : clé en dur dans le code
# api_key = "sk-abc123..." # INTERDIT en production
# TOUJOURS : rotation régulière des clés
# Créez une nouvelle clé, déployez-la, puis révoquez l'ancienne
2. Modèle versionné
# DÉVELOPPEMENT — dernière version
model = "mistral-large-latest"
# PRODUCTION — version fixe pour la reproductibilité
model = "mistral-large-2501"
# Pourquoi ? Un changement de "latest" peut modifier le comportement
# de votre application sans avertissement.
3. Gestion d’erreurs complète
from mistralai import Mistral
from mistralai.exceptions import MistralAPIException
import time
import logging
logger = logging.getLogger(__name__)
class MistralClient:
"""Client de production avec retry, timeout et logging."""
def __init__(self, api_key: str, max_retries: int = 3):
self.client = Mistral(api_key=api_key)
self.max_retries = max_retries
def complete(self, messages: list, **kwargs) -> dict:
for attempt in range(self.max_retries):
try:
response = self.client.chat.complete(
messages=messages,
**kwargs
)
result = {
"content": response.choices[0].message.content,
"finish_reason": response.choices[0].finish_reason,
"usage": {
"prompt": response.usage.prompt_tokens,
"completion": response.usage.completion_tokens,
"total": response.usage.total_tokens,
},
"model": response.model,
"id": response.id,
}
# Alerter si réponse tronquée
if result["finish_reason"] == "length":
logger.warning(f"Réponse tronquée — req_id={response.id}")
return result
except MistralAPIException as e:
if e.status_code == 429:
wait = 2 ** attempt
logger.warning(f"Rate limit, retry {attempt+1}/{self.max_retries} dans {wait}s")
time.sleep(wait)
elif e.status_code >= 500:
logger.error(f"Erreur serveur {e.status_code}, retry {attempt+1}")
time.sleep(1)
else:
logger.error(f"Erreur client {e.status_code}: {e.message}")
raise
raise Exception(f"Échec après {self.max_retries} tentatives")
4. Monitoring des coûts
import json
from datetime import datetime, timezone
class CostTracker:
"""Suivi des coûts API en temps réel."""
def __init__(self, log_path: str = "api_costs.jsonl"):
self.log_path = log_path
self.session_tokens = {"prompt": 0, "completion": 0}
def log(self, response_data: dict):
usage = response_data["usage"]
self.session_tokens["prompt"] += usage["prompt"]
self.session_tokens["completion"] += usage["completion"]
entry = {
"ts": datetime.now(timezone.utc).isoformat(),
"model": response_data["model"],
"prompt_tokens": usage["prompt"],
"completion_tokens": usage["completion"],
"finish_reason": response_data["finish_reason"],
"id": response_data["id"],
}
with open(self.log_path, "a") as f:
f.write(json.dumps(entry) + "\n")
def report(self) -> str:
total = self.session_tokens["prompt"] + self.session_tokens["completion"]
return (
f"Session — Prompt: {self.session_tokens['prompt']:,} | "
f"Completion: {self.session_tokens['completion']:,} | "
f"Total: {total:,} tokens"
)
5. Validation des entrées et sorties
def validate_input(user_message: str) -> str:
"""Valide et nettoie l'entrée utilisateur."""
if not user_message or not user_message.strip():
raise ValueError("Message vide")
if len(user_message) > 10_000:
raise ValueError("Message trop long (max 10 000 caractères)")
# Nettoyer les caractères de contrôle
cleaned = "".join(c for c in user_message if c.isprintable() or c in "\n\t")
return cleaned.strip()
def validate_output(content: str, finish_reason: str) -> dict:
"""Valide la sortie de l'API."""
warnings = []
if finish_reason == "length":
warnings.append("Réponse potentiellement tronquée")
if not content or len(content.strip()) < 5:
warnings.append("Réponse anormalement courte")
if len(content) > 50_000:
warnings.append("Réponse anormalement longue")
return {"content": content, "warnings": warnings, "valid": len(warnings) == 0}
6. Gestion de la fenêtre de contexte
def manage_context(messages: list, max_tokens: int = 100_000) -> list:
"""Garde les messages dans la limite de tokens du modèle."""
# Estimation : 1 token ~ 4 caractères en français
total_chars = sum(len(m["content"]) for m in messages)
estimated_tokens = total_chars // 4
if estimated_tokens < max_tokens * 0.8:
return messages # Tout rentre
# Garder system + premiers et derniers messages
system = [m for m in messages if m["role"] == "system"]
history = [m for m in messages if m["role"] != "system"]
# Couper les messages les plus anciens
while estimated_tokens > max_tokens * 0.7 and len(history) > 2:
removed = history.pop(0)
estimated_tokens -= len(removed["content"]) // 4
return system + history
Récapitulatif de la formation
Voici ce que vous avez appris dans ce cours :
Fondamentaux — L’endpoint, les rôles, les paramètres de base, la structure de la réponse.
Streaming — SSE, implémentation Python, stop sequences, sécurisation avec safe_prompt et guardrails.
Prompting — System prompts de production, few-shot, structuration XML/Markdown, anti-patterns.
Paramètres avancés — Température et Top P en détail, pénalités de présence et fréquence, N completions, et cette checklist de production.
Prochaines étapes
Pour aller plus loin avec l’API Mistral, explorez ces formations complémentaires sur Corsen Academy :
- Embeddings et RAG — Recherche sémantique avec
nomic-embed-textet bases vectorielles - Function calling — Connecter le modèle à vos outils et APIs externes
- Fine-tuning — Adapter un modèle à votre domaine spécifique
- Production et évaluation — Métriques, évals automatisées, optimisation des coûts
Configuration de production recommandée
# Configuration type pour une application en production
PRODUCTION_CONFIG = {
"model": "mistral-large-2501", # Version fixe
"max_tokens": 2000, # Adapté au cas d'usage
"temperature": 0.3, # Cohérent et factuel
"top_p": 1.0, # Pas touché si temperature ajustée
"presence_penalty": 0.0, # Par défaut sauf besoin spécifique
"frequency_penalty": 0.0, # Par défaut sauf besoin spécifique
"safe_prompt": True, # Sécurité activée
}
Points clés à retenir
- Utilisez des modèles versionnés en production, jamais
-latest - Implémentez retry + backoff + logging dès le premier déploiement
- Validez les entrées ET les sorties de chaque appel API
- Suivez les coûts en temps réel avec un tracker de tokens
- Gérez la fenêtre de contexte pour les conversations longues
- Activez
safe_promptcomme filet de sécurité minimal - Testez vos prompts avec des cas limites avant chaque mise en production