Skip to content

Monitoring RAI in Production

Beyond Accuracy Monitoring

Standard model monitoring tracks accuracy. RAI monitoring must also track fairness, explainability, and privacy metrics.

graph TD
    A[Production Model] --> B[Accuracy Metrics]
    A --> C[Fairness Metrics]
    A --> D[Explainability Stability]
    A --> E[Privacy Parameters]

    B --> F{Threshold Breached?}
    C --> F
    D --> F
    E --> F

    F -->|Yes| G[🚨 Alert]
    F -->|No| H[✅ Continue]
    G --> I{Severity?}
    I -->|Low| J[Recalibrate]
    I -->|Medium| K[Retrain]
    I -->|High| L[Replace Model]

What to Monitor

Dimension Metrics Frequency
Accuracy AUC, precision, recall, F1 Daily
Fairness SPD, DI, equalized odds per group Weekly
Explainability Top-10 feature importance stability Weekly
Drift PSI per feature, KS tests Daily
Privacy Differential privacy budget (\(\epsilon\)) Monthly

Fairness Monitoring Pipeline

import pandas as pd
import numpy as np
from datetime import datetime

class RAIMonitor:
    """Production monitoring for Responsible AI metrics."""

    def __init__(self, protected_config, target_col, fav_val):
        self.protected_config = protected_config
        self.target_col = target_col
        self.fav_val = fav_val
        self.history = []

    def evaluate(self, df, y_pred, timestamp=None):
        """Compute all RAI metrics for a batch of predictions."""
        timestamp = timestamp or datetime.now()
        metrics = {'timestamp': timestamp}

        # Overall accuracy
        metrics['accuracy'] = (df[self.target_col].values == y_pred).mean()

        # Per-feature fairness
        for feat, priv_val in self.protected_config.items():
            priv_mask = df[feat] == priv_val

            p_fav_priv = (y_pred[priv_mask] == self.fav_val).mean()
            p_fav_unpriv = (y_pred[~priv_mask] == self.fav_val).mean()

            metrics[f'{feat}_spd'] = p_fav_unpriv - p_fav_priv
            metrics[f'{feat}_di'] = (
                p_fav_unpriv / p_fav_priv if p_fav_priv > 0 else np.inf
            )

        self.history.append(metrics)
        return metrics

    def check_alerts(self, spd_threshold=0.1, di_threshold=0.8):
        """Check latest metrics against thresholds."""
        latest = self.history[-1]
        alerts = []

        for feat in self.protected_config:
            if abs(latest[f'{feat}_spd']) > spd_threshold:
                alerts.append(f"⚠️ {feat} SPD = {latest[f'{feat}_spd']:.4f}")
            if latest[f'{feat}_di'] < di_threshold:
                alerts.append(f"⚠️ {feat} DI = {latest[f'{feat}_di']:.4f}")

        return alerts if alerts else ["✅ All metrics within thresholds"]

Alerting Thresholds

Metric Green Yellow Red
SPD |SPD| < 0.05 0.05–0.10 > 0.10
DI DI > 0.9 0.8–0.9 < 0.8
PSI < 0.1 0.1–0.2 > 0.2
Accuracy drop < 2% 2–5% > 5%

Back to: Chapter 7 Overview ←