How to Build a Guardrail Metrics Monitor in Python

This code implements a mock monitor that records metric values, checks them against thresholds, and summarizes pass/alert statistics.

Easy Python 3.9+ Aug 9, 2026 A/B testing & experimentation 15 views 0 copies

Python code

50 lines
Python 3.9+
import random
import time
from collections import defaultdict


class GuardrailMetricsMonitor:
    def __init__(self):
        self.metrics = defaultdict(list)
        self.thresholds = {
            "prompt_toxicity": 0.8,
            "response_length": 500,
            "latency_ms": 1000,
        }

    def record(self, metric_name, value):
        self.metrics[metric_name].append(value)

    def check(self, metric_name, value):
        threshold = self.thresholds[metric_name]
        status = "PASS" if value <= threshold else "ALERT"
        if status == "ALERT":
            self.record(f"{metric_name}_alerts", time.time())
        return status

    def summary(self):
        result = {}
        for name, values in self.metrics.items():
            if values:
                result[name] = {
                    "count": len(values),
                    "avg": round(sum(values) / len(values), 2),
                    "max": max(values),
                }
        return result


if __name__ == "__main__":
    monitor = GuardrailMetricsMonitor()
    names = ["prompt_toxicity", "response_length", "latency_ms"]

    for _ in range(10):
        metric = random.choice(names)
        value = random.uniform(0, 1.2) * (500 if metric == "response_length" else 1)
        status = monitor.check(metric, value)
        monitor.record(metric, value)
        print(f"{metric}: {value:.2f} -> {status}")

    print("\nSummary:")
    for name, stats in monitor.summary().items():
        print(f"  {name}: {stats}")

Output

stdout
prompt_toxicity: 0.23 -> PASS
response_length: 239.12 -> PASS
latency_ms: 0.87 -> PASS
prompt_toxicity: 0.91 -> ALERT
response_length: 601.45 -> ALERT
latency_ms: 0.34 -> PASS
prompt_toxicity: 0.12 -> PASS
response_length: 388.72 -> PASS
latency_ms: 0.99 -> PASS
prompt_toxicity: 0.45 -> PASS

Summary:
  prompt_toxicity: {'count': 4, 'avg': 0.43, 'max': 0.91}
  response_length: {'count': 3, 'avg': 409.76, 'max': 601.45}
  latency_ms: {'count': 3, 'avg': 0.73, 'max': 0.99}

How it works

The GuardrailMetricsMonitor class uses a defaultdict to store time series of metric values. The check method compares each new value to a configurable threshold and returns 'PASS' or 'ALERT', recording alert timestamps for later analysis. The summary method aggregates counts, averages, and maximums per metric. This pattern is useful for tracking experiment guardrails in A/B tests, where you need to flag metrics that exceed safety thresholds.

Common mistakes

  • Using a regular dict without default values, causing KeyError on first access
  • Not converting timestamps to a comparable format when storing alerts
  • Forgetting to round averages, leading to floating-point precision issues in summaries

Variations

  1. Use a `dict` with `setdefault` to avoid importing `defaultdict`
  2. Store alert timestamps in a separate structure like a list of datetimes for easier filtering

Real-world use cases

  • Monitoring prompt toxicity in an LLM-based content moderation system to block unsafe outputs.
  • Tracking response latency in an API service to ensure it stays within service-level agreements.
  • Logging metric alerts during A/B test rollouts to automatically pause experiments that violate guardrails.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from A/B testing & experimentation

Related tutorials and quizzes for this topic.