Zum Hauptinhalt springen
Lektion 7 von 12 · KI-Moderation und Sicherheit mit Mistral

Moderation Scores and Thresholds

Lektion 7 von 12 Aktualisiert am 3. November 2026 Entwickler
Auf dieser Seite
  1. Interpretation von Moderation Scores
  2. Definition Ihrer Schwellenwerte: Die Entscheidungsmatrix
  3. Mehrstufiges Klassifizierungssystem
  4. Arbeitsbeispiel: Analysieren und Entscheiden
  5. Dynamische Anpassung von Schwellenwerten
  6. Zu vermeidende Fallstricke
  7. Kernaussagen

Aktualisiert am 3. November 2026. Die zuvor verwendeten Profilreferenzen bezogen sich auf nicht existierende Kategorien (hate, violence, unpredictable); sie stimmen nun mit den elf Schlüsseln von mistral-moderation-2603 überein, einschließlich dangerous. Die Anleitung zur Interpretation der Scores dient als Trainingsreferenz, da Mistral diese nicht veröffentlicht. Der Monitor hob zuvor für jede Kategorie an, die im Profil fehlte, eine KeyError auf und verwendete datetime.utcnow(), was seit Python 3.12 veraltet ist. Quellen: Moderation & Guardrailing · datetime.utcnow.

Interpretation von Moderation Scores

Jede Kategorie liefert einen Score zwischen 0,0 und 1,0. Was bedeuten diese Zahlen jedoch wirklich? Und wie setzen Sie Entscheidungsschwellen für Ihre Anwendung? Diese Lektion gibt Ihnen die Schlüssel, um aus rohen Scores automatisierte Entscheidungen zu ableiten – vom Messen zur Politik.

Verstehen Sie zunächst, dass Mistral diese Scores nicht als kalibrierte Wahrscheinlichkeiten darstellt. Ein Score von 0,6 bedeutet nicht „eine Sechs-zu-Zehn-Chance, dass dieser Text gefährlich ist”; es ist ein starkes Signal des Klassifizierers. Die Dokumentation hebt zwei nützliche Punkte hervor. Die booleschen categories in der Antwort wenden Schwellenwerte an, die Mistral für optimale Leistung auf seinem internen Testdatensatz gewählt hat; Sie können diese verwenden oder von den rohen Scores ausgehend Ihre eigenen festlegen. Auf diesem Testdatensatz liegt die Kategorie-Präzision zwischen 0,8 und 1,0 und die Recall zwischen 0,7 und 1,0: Falsch-Positivs und übersehene Inhalte treten auf, weshalb manuell justierte Schwellenwerte von Bedeutung sind.

Das untenstehende Raster wurde nicht von Mistral veröffentlicht: Es dient als Ausgangspunkt, um es gegen Ihre eigenen Metriken zu validieren.

BereichInterpretation
0,0 - 0,1Offensichtlich sicherer Inhalt, kein Signal erkannt
0,1 - 0,3Schwaches Signal, möglicherweise harmlos, aber mehrdeutig
0,3 - 0,5Mäßiges Signal, potenziell problematischer Inhalt
0,5 - 0,7Starkes Signal, sehr wahrscheinlich problematischer Inhalt
0,7 - 1,0Sehr starkes Signal, offensichtlich gefährlicher Inhalt

Definition Ihrer Schwellenwerte: Die Entscheidungsmatrix

Die Wahl einer Schwelle ist ein Kompromiss zwischen Sicherheit (so viel wie möglich blockieren) und Benutzbarkeit (Minimierung von Falsch-Positivs). Keine Einstellung gewinnt auf beiden Fronten, und Behauptungen, dies zu tun, führen zu endlosem Hin- und Her. Die Arbeitsmethode besteht darin, drei explizite Profile zu definieren und jede Anwendung einem dieser zuzuordnen.

Das strenge Profil zielt auf eine Konsumenten-Anwendung ab, bei der Minderjährige anwesend sein können; das ausgewogene Profil passt zu einer B2B-professionellen Anwendung mit identifizierten Nutzern; das nachsichtige Profil ist für ein internes Werkzeug vorbehalten, das von Experten verwaltet wird, die wissen, wonach sie suchen.

# Drei Schwellenwertprofile
PROFILES = {
    "strict": {
        # Konsumenten-Anwendung, Kinder möglich
        "sexual": 0.1,
        "hate_and_discrimination": 0.1,
        "violence_and_threats": 0.1,
        "dangerous": 0.1,
        "criminal": 0.1,
        "selfharm": 0.1,
        "health": 0.2,
        "financial": 0.2,
        "law": 0.2,
        "pii": 0.1,
        "jailbreaking": 0.1,
    },
    "balanced": {
        # B2B-professionelle Anwendung
        "sexual": 0.2,
        "hate_and_discrimination": 0.15,
        "violence_and_threats": 0.25,
        "dangerous": 0.15,
        "criminal": 0.15,
        "selfharm": 0.15,
        "health": 0.4,
        "financial": 0.4,
        "law": 0.4,
        "pii": 0.2,
        "jailbreaking": 0.15,
    },
    "permissive": {
        # Internes Werkzeug für Experten
        "sexual": 0.3,
        "hate_and_discrimination": 0.2,
        "violence_and_threats": 0.4,
        "dangerous": 0.2,
        "criminal": 0.2,
        "selfharm": 0.2,
        "health": 0.7,
        "financial": 0.7,
        "law": 0.7,
        "pii": 0.3,
        "jailbreaking": 0.2,
    },
}

Vergleichen Sie die health-Spalte über die Profile hinweg: 0,2, dann 0,4, dann 0,7. Der gleiche Austausch über Dosierung wird im ersten Fall blockiert und im letzten akzeptiert. Der Nutzungskontext entscheidet, nicht die Natur des Textes.

Mehrstufiges Klassifizierungssystem

Blockieren oder Akzeptieren ist eine vereinfachte Sicht auf die Realität. Zwischen offensichtlich sicherem Inhalt und offensichtlich verletzendem Inhalt liegt eine Grauzone, in der die richtige Entscheidung besteht, den Inhalt anzuzeigen, aber zu markieren. Die folgende Funktion führt diesen dritten Zustand ein: oberhalb der Schwelle blockieren; oberhalb von 60 % der Schwelle warnen und protokollieren; darunter durchlassen.

from enum import Enum

class RiskLevel(Enum):
    SAFE = "safe"          # Grün: sicherer Inhalt
    WARNING = "warning"    # Orange: Inhalt zur Überwachung
    BLOCKED = "blocked"    # Rot: blockierter Inhalt

def classify_content(scores: dict, thresholds: dict) -> dict:
    """Klassifiziert Inhalte in drei Risikostufen."""
    blocking_violations = []
    warnings = []

    for category, threshold in thresholds.items():
        score = scores.get(category, 0)

        if score > threshold:
            blocking_violations.append({
                "category": category,
                "score": round(score, 3)
            })
        elif score > threshold * 0.6:
            # Warnzone: 60 % der Schwelle
            warnings.append({
                "category": category,
                "score": round(score, 3)
            })

    if blocking_violations:
        return {
            "level": RiskLevel.BLOCKED,
            "violations": blocking_violations,
            "action": "block_and_log"
        }
    elif warnings:
        return {
            "level": RiskLevel.WARNING,
            "warnings": warnings,
            "action": "display_and_log"
        }
    else:
        return {
            "level": RiskLevel.SAFE,
            "action": "display"
        }

Der Wert der orangen Zone ist sowohl operativ als auch lehrreich: Sie zeigt Ihnen, was an Ihren Schwellenwerten vorbeizieht. Wenn eine Kategorie viele Warnungen generiert, ohne die Linie zu überschreiten, wissen Sie, dass eine Anpassung um einige Hundertstel einen erheblichen Teil des Verkehrs verschieben würde.

Arbeitsbeispiel: Analysieren und Entscheiden

Die Zusammenfassung reduziert sich auf eine Funktion: den Klassifizierer aufrufen, das Profil anwenden und die Entscheidung treffen. Der folgende Vergleich dient als Demonstration – eine Paracetamol-Dosierung wird im strengen Profil unter health blockiert und im nachsichtigen Profil akzeptiert, ohne dass sich eine einzige Zeile Text ändert.

from mistralai.client import Mistral
import os

client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])

def moderate_and_decide(text: str, profile: str = "balanced") -> dict:
    """Moderiert Text und trifft eine Entscheidung basierend auf dem Profil."""
    # Aufruf der Moderations-API
    response = client.classifiers.moderate(
        model="mistral-moderation-2603",
        inputs=[text]
    )
    scores = response.results[0].category_scores or {}

    # Anwendung der Profil-Schwellenwerte
    thresholds = PROFILES[profile]
    classification = classify_content(scores, thresholds)

    return {
        "text": text[:80],
        "profile": profile,
        "raw_scores": {k: round(v, 3) for k, v in scores.items()},
        "decision": classification
    }

# Test mit verschiedenen Profilen
text = "Take 2 paracetamol tablets every 6 hours"

# Strenges Profil: wahrscheinlich blockiert (health)
result_strict = moderate_and_decide(text, "strict")

# Nachsichtiges Profil: wahrscheinlich akzeptiert
result_permissive = moderate_and_decide(text, "permissive")

Dynamische Anpassung von Schwellenwerten

In der Produktion müssen Ihre Schwellenwerte sich entwickeln, und Sie steuern diese Entwicklung mit Daten. Der Monitor unten schreibt jede Entscheidung in eine JSONL-Datei und hält Zähler für Blockierungen, Warnungen und Durchläufe pro Kategorie aufrecht. Der resultierende Bericht gibt Ihnen die Blockquote pro Kategorie – die einzige Metrik, die Ihnen sagt, ob eine Schwelle zu niedrig ist.

import json
from datetime import datetime, timezone

class ModerationMonitor:
    """Sammelt Moderationsmetriken zur Anpassung von Schwellenwerten."""

    def __init__(self, log_file: str = "moderation_logs.jsonl"):
        self.log_file = log_file
        self.stats = {cat: {"blocked": 0, "warned": 0, "passed": 0}
                     for cat in PROFILES["balanced"].keys()}

    def log_decision(self, scores: dict, thresholds: dict, decision: str):
        """Protokolliert eine Moderationsentscheidung."""
        entry = {
            "timestamp": datetime.now(timezone.utc).isoformat(),
            "scores": scores,
            "thresholds": thresholds,
            "decision": decision
        }
        with open(self.log_file, "a") as f:
            f.write(json.dumps(entry) + "\n")

        # Aktualisiere Zähler
        for cat, threshold in thresholds.items():
            score = scores.get(cat, 0.0)
            self.stats.setdefault(cat, {"blocked": 0, "warned": 0, "passed": 0})
            if score > threshold:
                self.stats[cat]["blocked"] += 1
            elif score > threshold * 0.6:
                self.stats[cat]["warned"] += 1
            else:
                self.stats[cat]["passed"] += 1

    def report(self) -> dict:
        """Generiert einen Bericht zur Anpassung von Schwellenwerten."""
        report = {}
        for cat, stats in self.stats.items():
            total = sum(stats.values())
            if total > 0:
                report[cat] = {
                    "block_rate": round(stats["blocked"] / total, 3),
                    "warning_rate": round(stats["warned"] / total, 3),
                    "total": total
                }
        return report

Zu vermeidende Fallstricke

Der erste Fallstrick ist eine einzelne Schwelle, die auf alle Kategorien angewendet wird. Jede Kategorie hat ihre eigene Score-Verteilung: Eine Schwelle von 0,3 für hate_and_discrimination bedeutet nicht dasselbe wie 0,3 für health, wo legitimer Inhalt natürlicherweise höher auf der Skala liegt. Passen Sie jede Kategorie einzeln an, auch wenn das bedeutet, elf Entscheidungen statt einer zu treffen.

Der zweite ist das Ignorieren von Falsch-Positivs. Eine hohe Blockquote untergräbt das Nutzervertrauen viel schneller als ein isolierter Vorfall, da sie Menschen betrifft, die in gutem Glauben handeln. Verfolgen Sie die Blockquote pro Kategorie und erhöhen Sie die Schwellenwerte, wenn die Daten dies rechtfertigen.

Der dritte, heimtückischere, ist das Versäumnis, Entscheidungen zu protokollieren. Ohne Protokolle können Sie Ihre Schwellenwerte nicht informiert anpassen und fallen auf Meinungsbesprechungen zurück. Protokollieren Sie systematisch Scores, angewandte Schwellenwerte und getroffene Entscheidungen – dieser Korpus ist es, der die nächste Revision schnell und unanfechtbar macht.

Kernaussagen

  • Scores reichen von 0,0 bis 1,0; sie sind keine kalibrierten Wahrscheinlichkeiten, und Mistral empfiehlt, Ihre eigenen Schwellenwerte festzulegen
  • Definieren Sie Schwellenwertprofile, die an Ihren Kontext angepasst sind (streng, ausgewogen, nachsichtig)
  • Implementieren Sie ein 3-Stufen-System: sicher, Warnung, blockiert
  • Protokollieren Sie alle Entscheidungen, um Ihre Schwellenwerte kontinuierlich anzupassen
  • Jede Kategorie erfordert ihren eigenen Schwellenwert – kein einzelner Wert passt allen