Aller au contenu

TechniquePratique

Alertes, règles d'enregistrement et SLO

Pour : ingénieurs et SRE · architectesPrérequis : Avoir lu la leçon 4 du parcours sur MetricsQL.

Module 9 : vmalert, règles d’alerte de production

Section intitulée « Module 9 : vmalert, règles d’alerte de production »
alerts/llm-quality.yml
groups:
- name: llm_quality
interval: 1m
rules:
# Dérive d'un index RAG
- alert: RAGIndexDrift
expr: |
avg by (index_id, pipeline_id) (
avg_over_time(rag_retrieval_score_avg[1h])
) < 0.70
for: 15m
labels: { severity: warning, team: ai-platform }
annotations:
summary: 'Dérive de l''index RAG {{ $labels.index_id }}'
description: |
Score de recherche moyen = {{ $value | printf "%.2f" }} < seuil 0.70
depuis 15 min sur le pipeline {{ $labels.pipeline_id }}.
Action : vérifier les mises à jour de documents sans réindexation.
runbook_url: 'https://wiki.internal/runbooks/rag-index-drift'
# Pression de contexte critique
- alert: RAGContextPressureHigh
expr: |
histogram_quantile(0.95,
sum by (le, pipeline_id) (
rate(rag_context_pressure_ratio_bucket[10m])
)
) > 0.85
for: 5m
labels: { severity: warning, team: ai-platform }
annotations:
summary: 'Pression de contexte P95 élevée : {{ $labels.pipeline_id }}'
description: 'P95 = {{ $value | printf "%.2f" }}. Réduire le prompt système ou agrandir la fenêtre de contexte.'
# Taux d'erreur LLM élevé
- alert: LLMHighErrorRate
expr: |
sum by (model, provider) (rate(llm_errors_total[5m]))
/
sum by (model, provider) (rate(llm_requests_total[5m]))
> 0.01
for: 3m
labels: { severity: critical, team: ai-platform }
annotations:
summary: 'Taux d''erreur > 1 % sur {{ $labels.model }} / {{ $labels.provider }}'
description: 'Taux actuel : {{ $value | humanizePercentage }}. Vérifier la disponibilité du fournisseur.'
# Dépassement du SLO de latence
- alert: LLMLatencySLOBreach
expr: |
histogram_quantile(0.99,
sum by (le, model, pipeline_id) (
rate(llm_request_duration_ms_bucket[5m])
)
) > 5000
for: 5m
labels: { severity: critical, team: ai-platform }
annotations:
summary: 'SLO de latence P99 dépassé sur {{ $labels.model }}'
description: 'P99 = {{ $value | printf "%.0f" }} ms > SLO 5000 ms. Pipeline {{ $labels.pipeline_id }}'
# Saturation de la mémoire GPU
- alert: GPUMemorySaturation
expr: DCGM_FI_DEV_FB_USED / (DCGM_FI_DEV_FB_USED + DCGM_FI_DEV_FB_FREE) * 100 > 90
for: 2m
labels: { severity: warning, team: mlops }
annotations:
summary: 'Mémoire du GPU {{ $labels.gpu }} saturée ({{ $value | printf "%.0f" }} %)'
description: 'Risque d''OOM. Réduire la taille de lot ou la fenêtre de contexte du modèle.'
# Budget LLM quotidien (budget de l'exemple : 100 USD par jour, à remplacer par le vôtre).
# llm_cost_usd_total n'existe que si une grille de prix est fournie (module 6.3).
- alert: LLMDailyBudgetWarning
expr: |
sum by (tenant_id) (
increase(llm_cost_usd_total[24h])
) > 80
labels: { severity: warning, team: billing }
annotations:
summary: 'Budget LLM à 80 % pour le tenant {{ $labels.tenant_id }}'
description: 'Coût sur 24 h = {{ $value | printf "%.2f" }} USD. Seuil : 100 USD par jour.'
alertmanager.yml
global:
slack_api_url: 'https://hooks.slack.com/services/REPLACE_ME'
route:
group_by: ['alertname', 'model', 'pipeline_id']
group_wait: 30s
repeat_interval: 12h
receiver: 'default'
routes:
- matchers: ['severity="critical"']
receiver: pagerduty
- matchers: ['team="ai-platform"']
receiver: slack-ai-platform
- matchers: ['team="billing"']
receiver: slack-billing
receivers:
- name: 'default'
slack_configs:
- channel: '#llm-ops-alerts'
title: '{{ .CommonAnnotations.summary }}'
text: '{{ .CommonAnnotations.description }}'
- name: 'slack-ai-platform'
slack_configs:
- channel: '#ai-platform-alerts'
- name: 'slack-billing'
slack_configs:
- channel: '#billing-alerts'
- name: 'pagerduty'
pagerduty_configs:
- routing_key: 'YOUR_PAGERDUTY_KEY'

Module 10 : règles d’enregistrement, pré-agréger les métriques de coût

Section intitulée « Module 10 : règles d’enregistrement, pré-agréger les métriques de coût »

Les métriques de coût sont interrogées très souvent par les tableaux de bord. Recalculer increase(llm_cost_usd_total[24h]) à chaque rafraîchissement consomme beaucoup de CPU. Les règles d’enregistrement (recording rules) précalculent ces agrégations en tâche de fond : le tableau de bord lit alors une seule série par combinaison de labels au lieu de recalculer l’agrégation sur toutes les séries brutes. Le gain dépend du nombre de séries et de la fenêtre interrogée ; mesurez-le sur votre instance (c’est l’objet du Lab 4).

alerts/recording-rules.yml
groups:
- name: llm_recording_rules
interval: 1m
rules:
- record: llm:cost_usd:increase1h
expr: |
sum by (model, provider, tenant_id) (
increase(llm_cost_usd_total[1h])
)
- record: llm:cost_usd:increase24h
expr: |
sum by (model, provider, tenant_id) (
increase(llm_cost_usd_total[24h])
)
- record: llm:error_rate:ratio5m
expr: |
sum by (model, provider) (rate(llm_errors_total[5m]))
/
sum by (model, provider) (rate(llm_requests_total[5m]))
- record: llm:request_duration_ms:p99_5m
expr: |
histogram_quantile(0.99,
sum by (le, model, pipeline_id) (
rate(llm_request_duration_ms_bucket[5m])
)
)
- record: llm:ttft_ms:p95_5m
expr: |
histogram_quantile(0.95,
sum by (le, model) (rate(llm_ttft_ms_bucket[5m]))
)
- record: rag:retrieval_score:avg30m
expr: |
avg by (index_id, pipeline_id) (
avg_over_time(rag_retrieval_score_avg[30m])
)
- record: rag:context_pressure:p95_10m
expr: |
histogram_quantile(0.95,
sum by (le, pipeline_id) (
rate(rag_context_pressure_ratio_bucket[10m])
)
)
- record: gpu:memory_utilization:ratio
expr: DCGM_FI_DEV_FB_USED / (DCGM_FI_DEV_FB_USED + DCGM_FI_DEV_FB_FREE)

Utiliser les règles d’enregistrement dans les alertes et les tableaux de bord

Section intitulée « Utiliser les règles d’enregistrement dans les alertes et les tableaux de bord »

Une fois les règles définies, utilisez les séries enregistrées plutôt que la requête complète. Au lieu de :

histogram_quantile(0.99, sum by (le, model, pipeline_id) (rate(llm_request_duration_ms_bucket[5m])))

utilisez :

llm:request_duration_ms:p99_5m

La requête est beaucoup plus rapide. Le résultat est équivalent, à la résolution de l’intervalle d’évaluation de la règle près (ici une minute) et avec les labels d’agrégation choisis dans la règle.

Un objectif de niveau de service (Service Level Objective, SLO) traduit une exigence métier en cible mesurable. Pour les LLM, les SLO classiques (disponibilité, latence) restent valables mais ne suffisent pas : ajoutez la qualité et le coût.

CatégorieIndicateur (SLI)SLO (exemple à adapter)Fenêtre
Disponibilité1 - rate(llm_errors_total[5m]) / rate(llm_requests_total[5m])99,5 %30 jours
Latence interactivehistogram_quantile(0.95, ...llm_ttft_ms...)< 1 200 ms7 jours
Latence batchhistogram_quantile(0.99, ...llm_request_duration_ms...)< 8 000 ms30 jours
Qualité de rechercheavg(rag_retrieval_score_avg)> 0,7824 h
Consommation par requêtesum(increase(llm_tokens_total[1h])) / sum(increase(llm_requests_total[1h]))< 2 000 tokens (exemple à adapter)Mois calendaire
Coût par requête (avec une grille de prix)sum(increase(llm_cost_usd_total[1h])) / sum(increase(llm_requests_total[1h]))votre cible, dans la devise de la métriqueMois calendaire

Le budget d’erreur (error budget) est le complément du SLO à 100 %. Pour une disponibilité de 99,5 % sur 30 jours, le budget d’erreur vaut 0,5 %, soit 3 h 36 min d’indisponibilité tolérée par mois.

# Budget d'erreur consommé sur la fenêtre du SLO (en %)
(
1
-
(
sum(increase(llm_requests_total[30d]))
-
sum(increase(llm_errors_total[30d]))
)
/
sum(increase(llm_requests_total[30d]))
) / 0.005 * 100

11.3 Alertes sur le taux de consommation (motif Google SRE)

Section intitulée « 11.3 Alertes sur le taux de consommation (motif Google SRE) »

Alertez quand le budget d’erreur se consomme trop vite (burn rate). Chaque alerte combine une fenêtre longue et une fenêtre courte : la fenêtre longue confirme la tendance, la fenêtre courte fait retomber l’alerte rapidement une fois le problème corrigé.

- alert: LLMFastBurn
expr: |
(
sum(rate(llm_errors_total[1h])) / sum(rate(llm_requests_total[1h]))
) > (14.4 * 0.005)
and
(
sum(rate(llm_errors_total[5m])) / sum(rate(llm_requests_total[5m]))
) > (14.4 * 0.005)
for: 2m
labels:
severity: critical
annotations:
summary: "Consommation du budget d'erreur 14,4 fois la normale (épuisé en 2 jours environ)"
- alert: LLMSlowBurn
expr: |
(
sum(rate(llm_errors_total[6h])) / sum(rate(llm_requests_total[6h]))
) > (6 * 0.005)
and
(
sum(rate(llm_errors_total[30m])) / sum(rate(llm_requests_total[30m]))
) > (6 * 0.005)
for: 15m
labels:
severity: warning
annotations:
summary: "Consommation du budget d'erreur 6 fois la normale (épuisé en 5 jours)"

Révisé le 2 octobre 2026 : prix retirés ; la cible chiffrée de coût par requête est remplacée par une cible en tokens par requête, la cible de coût étant laissée à votre grille de prix.