Alerter en cas de latence, de coût ou de dégradation de la qualité
Définissez des seuils d’alerte pour la latence p99, le coût par requête et les scores de qualité automatisés, puis acheminez les alertes vers Slack ou PagerDuty lorsque votre pipeline LLM se dégrade.
Alerter en cas de latence, de coût ou de dégradation de la qualité est une leçon AI Engineering Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Engineering Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Engineering Academy comprend 4 leçons au total.
Pourquoi les alertes sont importantes pour les systèmes LLM
Les applications LLM échouent de manière subtile et progressive. Une modification de prompt peut augmenter la latence moyenne de 30 %, une amélioration de la récupération peut réduire légèrement la qualité des réponses, ou une hausse de l’utilisation peut multiplier par cinq les coûts quotidiens par rapport au budget. Sans alertes proactives, vous ne découvrez ces problèmes que lorsque les utilisateurs se plaignent ou que la facture mensuelle arrive. Les alertes transforment la gestion réactive des incidents en exploitation proactive.
Les trois catégories d’alertes
Les alertes des applications LLM se répartissent en trois catégories. Les alertes de latence se déclenchent lorsque le temps de réponse dépasse un seuil d’expérience utilisateur (par exemple, p99 > 10 secondes). Les alertes de coût se déclenchent lorsque le coût par requête ou les dépenses quotidiennes dépassent les seuils budgétaires, afin d’éviter les mauvaises surprises sur la facture. Les alertes de qualité se déclenchent lorsque les indicateurs de qualité automatisés (scores d’un LLM comme juge, taux de satisfaction des utilisateurs, scores de fidélité) passent sous un niveau acceptable. Chaque catégorie nécessite une instrumentation et des canaux d’alerte différents.
from dataclasses import dataclass
@dataclass
class AlertThresholds:
# Latency (milliseconds)
p50_latency_ms: int = 2000 # median should be under 2s
p99_latency_ms: int = 10000 # 99th percentile under 10s
# Cost (USD)
max_cost_per_request: float = 0.05 # alert if one request costs > 5 cents
max_daily_spend: float = 50.00 # alert if daily spend exceeds $50
# Quality (0.0 to 1.0 scale)
min_quality_score: float = 0.75 # alert if rolling avg drops below 75%
min_faithfulness: float = 0.80 # alert if RAGAS faithfulness drops below 80%
DEFAULT_THRESHOLDS = AlertThresholds()Collecte des indicateurs de latence
Pour déclencher des alertes sur la latence, vous devez d’abord la mesurer de manière cohérente. Mesurez séparément les trois composantes de la latence : le temps jusqu’au premier jeton (TTFT, essentiel pour l’expérience utilisateur en diffusion), le temps de réponse total et les latences de chaque étape pour la récupération et la génération. Stockez ces données sous forme de séries temporelles (un point de données par requête) afin de pouvoir calculer des percentiles et des moyennes glissantes sur les N dernières minutes ou heures.
import time
from collections import deque
from statistics import quantiles
class LatencyTracker:
def __init__(self, window_size=100):
self.window = deque(maxlen=window_size) # rolling window of latencies
def record(self, latency_ms: float):
self.window.append(latency_ms)
def p50(self) -> float:
if not self.window:
return 0
return quantiles(self.window, n=100)[49]
def p99(self) -> float:
if not self.window:
return 0
return quantiles(self.window, n=100)[98]
def check_alert(self, thresholds: AlertThresholds) -> list[str]:
alerts = []
if self.p99() > thresholds.p99_latency_ms:
alerts.append(f'p99 latency {self.p99():.0f}ms exceeds {thresholds.p99_latency_ms}ms')
if self.p50() > thresholds.p50_latency_ms:
alerts.append(f'p50 latency {self.p50():.0f}ms exceeds {thresholds.p50_latency_ms}ms')
return alerts
latency_tracker = LatencyTracker()Suivi des coûts et déclenchement d’alertes
La surveillance des coûts nécessite de suivre les dépenses à plusieurs niveaux de granularité : le coût par requête (pour détecter les requêtes exceptionnellement coûteuses), les totaux horaires et quotidiens (pour détecter les pics d’utilisation) et le coût par fonctionnalité (pour déterminer quelle partie de votre application est la plus coûteuse). Déclenchez immédiatement une alerte en cas d’anomalie du coût par requête et utilisez des vérifications planifiées pour les limites budgétaires quotidiennes.
from datetime import datetime, date
import threading
class CostTracker:
def __init__(self):
self._lock = threading.Lock()
self._daily_spend = {} # date -> total USD
self._per_request = [] # list of (timestamp, cost)
def record(self, cost_usd: float) -> list[str]:
today = date.today().isoformat()
alerts = []
with self._lock:
# Track daily spend
self._daily_spend[today] = self._daily_spend.get(today, 0) + cost_usd
self._per_request.append((datetime.now(), cost_usd))
# Alert on expensive single requests
if cost_usd > DEFAULT_THRESHOLDS.max_cost_per_request:
alerts.append(f'Expensive request: ${cost_usd:.4f} (threshold: ${DEFAULT_THRESHOLDS.max_cost_per_request})')
# Alert on daily budget exceeded
daily_total = self._daily_spend[today]
if daily_total > DEFAULT_THRESHOLDS.max_daily_spend:
alerts.append(f'Daily budget exceeded: ${daily_total:.2f} > ${DEFAULT_THRESHOLDS.max_daily_spend}')
return alerts
cost_tracker = CostTracker()Alertes sur les scores de qualité
Les alertes de qualité sont la catégorie la plus complexe, car la qualité ne peut pas être mesurée uniquement à partir des indicateurs d’infrastructure : elle nécessite une évaluation sémantique. L’approche la plus évolutive est l’évaluation automatisée sur échantillon : pour un échantillon aléatoire des requêtes de production (5 à 10 %), exécutez de manière asynchrone un évaluateur utilisant un LLM comme juge, stockez les scores et calculez une moyenne glissante. Déclenchez une alerte lorsque la moyenne glissante passe sous votre seuil minimal de qualité.
import random
from openai import OpenAI
client = OpenAI()
def evaluate_response_quality(question: str, answer: str) -> float:
judge_prompt = f'''Rate the quality of this AI assistant response on a scale from 0 to 1.
Question: {question}
Answer: {answer}
Return only a JSON object: {{"score": 0.85, "reason": "brief reason"}}
Scoring guide:
1.0 = Perfect, accurate, helpful
0.75 = Good, minor issues
0.5 = Acceptable but incomplete
0.25 = Poor, major gaps
0.0 = Completely wrong or harmful'''
response = client.chat.completions.create(
model='gpt-4o-mini', # cheaper model for evaluation
messages=[{'role': 'user', 'content': judge_prompt}],
response_format={'type': 'json_object'}
)
import json
result = json.loads(response.choices[0].message.content)
return float(result['score'])
def maybe_evaluate(question: str, answer: str, sample_rate=0.1):
if random.random() < sample_rate:
score = evaluate_response_quality(question, answer)
quality_tracker.record(score)
return score
return NoneMoyennes glissantes pour détecter les tendances
Une seule mauvaise réponse n’indique pas un problème systémique. Utilisez des moyennes glissantes sur une fenêtre temporelle (par exemple, la dernière heure ou les 100 dernières requêtes) pour détecter les tendances. Une moyenne glissante qui franchit un seuil et y reste pendant plus de 10 minutes indique un problème réel, tandis qu’un bref pic peut n’être que du bruit. Les moyennes mobiles pondérées exponentiellement (EWMA) réagissent plus rapidement aux changements récents que les simples moyennes glissantes.
class RollingQualityMonitor:
def __init__(self, window=50, alert_threshold=0.75, ewma_alpha=0.1):
self.scores = []
self.window = window
self.alert_threshold = alert_threshold
self.alpha = ewma_alpha # EWMA decay factor
self.ewma_score = None
def record(self, score: float):
self.scores.append(score)
if len(self.scores) > self.window:
self.scores.pop(0)
# Update exponentially weighted moving average
if self.ewma_score is None:
self.ewma_score = score
else:
self.ewma_score = self.alpha * score + (1 - self.alpha) * self.ewma_score
def should_alert(self) -> bool:
if len(self.scores) < 10: # not enough data yet
return False
return self.ewma_score < self.alert_threshold
def summary(self) -> dict:
if not self.scores:
return {}
return {
'rolling_avg': sum(self.scores) / len(self.scores),
'ewma': self.ewma_score,
'sample_count': len(self.scores),
'alert': self.should_alert()
}
quality_tracker = RollingQualityMonitor()Routage des alertes : Slack et PagerDuty
Les alertes ne sont utiles que si elles parviennent à la bonne personne par le bon canal. Acheminez les alertes selon leur gravité : les alertes de dégradation de la qualité et de dépassement du budget de coûts vont dans un canal Slack surveillé par votre équipe pendant les heures ouvrées. Les alertes de latence dépassant les seuils critiques (par exemple, p99 > 30 secondes) et les pics soudains de coûts (par exemple, 10 fois le niveau normal en 5 minutes) sont envoyés à PagerDuty pour une escalade immédiate vers la personne d’astreinte.
import requests
def send_slack_alert(message: str, severity: str, webhook_url: str):
color = {'critical': '#ff0000', 'warning': '#ff9900', 'info': '#36a64f'}[severity]
payload = {
'attachments': [{
'color': color,
'title': f'LLM Alert [{severity.upper()}]',
'text': message,
'footer': 'AI Pipeline Monitor'
}]
}
requests.post(webhook_url, json=payload)
def send_pagerduty_alert(title: str, details: str, routing_key: str):
payload = {
'routing_key': routing_key,
'event_action': 'trigger',
'payload': {
'summary': title,
'severity': 'critical',
'source': 'ai-pipeline-monitor',
'custom_details': {'details': details}
}
}
requests.post('https://events.pagerduty.com/v2/enqueue', json=payload)
def route_alert(alert_text: str, severity: str):
send_slack_alert(alert_text, severity, SLACK_WEBHOOK_URL)
if severity == 'critical':
send_pagerduty_alert(alert_text, alert_text, PAGERDUTY_ROUTING_KEY)La boucle d’évaluation des alertes
La logique d’alerte doit s’exécuter dans une boucle planifiée, et non pendant le traitement des requêtes. L’exécution asynchrone des vérifications d’alerte évite d’ajouter de la latence aux requêtes de production. Un thread en arrière-plan ou une tâche planifiée exécutée toutes les 60 secondes suffit pour la plupart des besoins d’alerte. Collectez les indicateurs dans le chemin de traitement des requêtes et évaluez les seuils dans la boucle en arrière-plan.
import threading
import time
def alert_evaluation_loop(interval_seconds=60):
while True:
try:
# Check latency
latency_alerts = latency_tracker.check_alert(DEFAULT_THRESHOLDS)
for alert in latency_alerts:
route_alert(f'LATENCY: {alert}', 'warning')
# Check quality
quality_summary = quality_tracker.summary()
if quality_summary.get('alert'):
msg = f'QUALITY DEGRADATION: Rolling avg {quality_summary["ewma"]:.2f} below threshold {DEFAULT_THRESHOLDS.min_quality_score}'
route_alert(msg, 'warning')
print(f'Alert check complete. Quality: {quality_summary.get("ewma", "N/A")}')
except Exception as e:
print(f'Alert evaluation error: {e}')
time.sleep(interval_seconds)
# Start in background thread
alert_thread = threading.Thread(target=alert_evaluation_loop, daemon=True)
alert_thread.start()Fatigue liée aux alertes et ajustement des seuils
La fatigue liée aux alertes survient lorsque les alertes se déclenchent si fréquemment que l’équipe commence à les ignorer. Pour l’éviter : commencez par des seuils prudents (élevés) et resserrez-les à mesure que vous comprenez votre niveau de référence ; exigez que les conditions persistent pendant plusieurs cycles d’évaluation avant de déclencher une alerte ; regroupez les alertes associées dans des notifications uniques ; et examinez régulièrement les alertes qui ne donnent jamais lieu à une action utile afin de les désactiver.
class AlertDebouncer:
def __init__(self, required_consecutive_fires=3):
self.required = required_consecutive_fires
self.fire_counts = {} # alert_name -> consecutive fires
self.already_firing = set() # alert_names currently active
def should_fire(self, alert_name: str, condition: bool) -> bool:
if condition:
self.fire_counts[alert_name] = self.fire_counts.get(alert_name, 0) + 1
if self.fire_counts[alert_name] >= self.required and alert_name not in self.already_firing:
self.already_firing.add(alert_name)
return True # fire the alert (first time condition sustained)
else:
if self.fire_counts.get(alert_name, 0) > 0:
self.fire_counts[alert_name] = 0
self.already_firing.discard(alert_name) # condition cleared
return False # either not sustained or already firing (no duplicate alert)
debouncer = AlertDebouncer(required_consecutive_fires=3)Surveillance des anomalies de coût par des méthodes statistiques
Les alertes fondées sur de simples seuils ne détectent pas les anomalies de coût nuancées, comme une hausse progressive de 50 % sur deux jours. Utilisez une détection statistique des anomalies : calculez la moyenne glissante et l’écart type de vos coûts horaires, puis déclenchez une alerte lorsque le coût de l’heure en cours dépasse la moyenne de plus de N écarts types (alerte fondée sur le score Z). Cette méthode s’adapte automatiquement aux habitudes naturelles d’utilisation, comme la différence entre le trafic en semaine et le trafic du week-end.
import statistics
def compute_z_score(recent_value: float, historical_values: list[float]) -> float:
if len(historical_values) < 5:
return 0 # not enough data
mean = statistics.mean(historical_values)
stdev = statistics.stdev(historical_values)
if stdev == 0:
return 0
return (recent_value - mean) / stdev
def check_cost_anomaly(current_hour_cost: float, historical_hourly_costs: list[float]) -> str | None:
z = compute_z_score(current_hour_cost, historical_hourly_costs)
if z > 3.0: # more than 3 standard deviations above mean
mean = statistics.mean(historical_hourly_costs)
return f'Cost anomaly: ${current_hour_cost:.2f} this hour (normal: ${mean:.2f}, z={z:.1f})'
return NoneCréer un tableau de bord d’exploitation
Les alertes constituent la couche réactive ; un tableau de bord d’exploitation en direct constitue la couche proactive. Créez un tableau de bord simple affichant les indicateurs en temps réel : la latence p50/p99 actuelle, le nombre de requêtes par minute, le score de qualité actuel (EWMA glissante), le coût quotidien à ce jour par rapport au budget et les cinq requêtes les plus coûteuses de la dernière heure. Votre équipe dispose ainsi d’une vue immédiate de l’état du système, sans attendre le déclenchement d’une alerte.
Vérification rapide
Vérifiez votre compréhension des alertes sur les indicateurs des applications LLM à partir de cette leçon.
Récapitulatif de la leçon
Dans cette leçon, vous avez appris que trois catégories d’alertes couvrent les systèmes LLM — la latence, le coût et la qualité — et que chacune nécessite une instrumentation différente ; les moyennes glissantes et l’EWMA détectent mieux la dégradation progressive de la qualité que les vérifications de seuil sur des requêtes individuelles ; enfin, le débouçage des alertes évite la lassitude face aux alertes en exigeant que les conditions persistent pendant plusieurs cycles d’évaluation avant de déclencher une alerte. Nous allons maintenant nous intéresser aux attaques par injection de prompt et à la sécurité de l’IA.
Questions Fréquemment Posées
La leçon « Alerter en cas de latence, de coût ou de dégradation de la qualité » est-elle gratuite ?
Oui — le texte complet de « Alerter en cas de latence, de coût ou de dégradation de la qualité » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Engineering Academy, passe à CoddyKit PRO. Le cours AI Engineering Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Alerter en cas de latence, de coût ou de dégradation de la qualité » ?
Définissez des seuils d’alerte pour la latence p99, le coût par requête et les scores de qualité automatisés, puis acheminez les alertes vers Slack ou PagerDuty lorsque votre pipeline LLM se dégrade. Tu pratiques AI Engineering Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer AI Engineering Academy ?
Aucune expérience préalable n'est requise. AI Engineering Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Alerter en cas de latence, de coût ou de dégradation de la qualité » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon AI Engineering Academy ?
Oui. Chaque leçon AI Engineering Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Pourquoi les applications LLM sont difficiles à déboguer
- Tracer avec LangSmith
- Langfuse pour une observabilité indépendante des modèles
- Alerter en cas de latence, de coût ou de dégradation de la qualité