Aller au contenu principal

Architecture de sécurité complète

Assembler toutes les pièces

Au fil de cette formation, vous avez découvert les guardrails, l’API de modération, les 11 catégories, les seuils, la détection de jailbreak, la conformité RGPD et les politiques de contenu. Cette dernière leçon assemble toutes ces briques dans une architecture de sécurité complète, prête pour la production.

Vue d’ensemble de l’architecture

L’architecture de sécurité se compose de cinq couches successives :

Utilisateur

[1. Validation d'entrée] → Regex, patterns, rate limiting

[2. Guardrails Mistral]  → Blocage pré-génération (403)

[3. Génération LLM]      → safe_prompt + instructions sécurisées

[4. Modération sortie]   → API Moderation post-génération

[5. Logging & Audit]     → Scores, décisions, audit trail RGPD

Réponse utilisateur

Implémentation complète

from mistralai import Mistral
from mistralai.models import SDKError
import os
import re
import json
import logging
from datetime import datetime
from enum import Enum

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

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("moderation")


class Decision(Enum):
    ALLOWED = "allowed"
    BLOCKED_INPUT = "blocked_input"
    BLOCKED_GUARDRAIL = "blocked_guardrail"
    BLOCKED_OUTPUT = "blocked_output"
    ERROR = "error"


class ArchitectureSecurisee:
    """Architecture de sécurité complète pour applications IA."""

    def __init__(self, politique: dict, model: str = "mistral-large-latest"):
        self.politique = politique
        self.model = model
        self.stats = {d.value: 0 for d in Decision}

    # --- Couche 1 : Validation d'entrée ---

    def valider_entree(self, texte: str) -> dict:
        """Validation rapide avant toute API."""
        # Longueur maximale
        if len(texte) > 10000:
            return {"valide": False, "raison": "Message trop long"}

        # Caractères suspects (injections Unicode)
        if re.search(r"[\x00-\x08\x0b\x0c\x0e-\x1f]", texte):
            return {"valide": False, "raison": "Caractères invalides"}

        # Patterns de jailbreak évidents
        patterns = [
            r"ignore\s+(all\s+)?(previous|prior|above)",
            r"you\s+are\s+now\s+(DAN|unfiltered)",
            r"oublie\s+(toutes?\s+)?(tes|vos)\s+instructions",
            r"system\s*prompt",
        ]
        for pattern in patterns:
            if re.search(pattern, texte, re.IGNORECASE):
                return {
                    "valide": False,
                    "raison": "Pattern injection détecté"
                }

        return {"valide": True}

    # --- Couche 2 : Modération entrée ---

    def moderer_entree(self, texte: str) -> dict:
        """Modération du prompt via API."""
        response = client.classifiers.moderate(
            model="mistral-moderation-2603",
            inputs=[texte]
        )
        scores = response.results[0].category_scores
        violations = self._verifier_seuils(scores)

        return {
            "autorise": len(violations) == 0,
            "scores": scores,
            "violations": violations
        }

    # --- Couche 3 : Génération sécurisée ---

    def generer(self, messages: list) -> str:
        """Génération avec guardrails et safe_prompt."""
        response = client.chat.complete(
            model=self.model,
            messages=messages,
            safe_prompt=True,
            guardrails={
                "enabled": True,
                "custom_category_thresholds":
                    self.politique["seuils"],
                "action": "block",
                "block_on_error": True
            }
        )
        return response.choices[0].message.content

    # --- Couche 4 : Modération sortie ---

    def moderer_sortie(self, prompt: str, reponse: str) -> dict:
        """Modération de la réponse en contexte."""
        response = client.classifiers.moderate_chat(
            model="mistral-moderation-2603",
            inputs=[[
                {"role": "user", "content": prompt},
                {"role": "assistant", "content": reponse}
            ]]
        )
        scores = response.results[0].category_scores
        violations = self._verifier_seuils(scores)

        return {
            "autorise": len(violations) == 0,
            "scores": scores,
            "violations": violations
        }

    # --- Couche 5 : Logging ---

    def log_decision(self, decision: Decision, data: dict):
        """Enregistre la décision pour audit."""
        self.stats[decision.value] += 1
        entry = {
            "timestamp": datetime.utcnow().isoformat(),
            "decision": decision.value,
            "politique": self.politique["nom"],
            **data
        }
        logger.info(json.dumps(entry, ensure_ascii=False))

    # --- Pipeline principal ---

    def traiter(self, user_message: str,
                system_prompt: str = None) -> dict:
        """Pipeline complet de traitement sécurisé."""

        # Couche 1 : Validation
        validation = self.valider_entree(user_message)
        if not validation["valide"]:
            self.log_decision(Decision.BLOCKED_INPUT, {
                "raison": validation["raison"]
            })
            return {
                "status": Decision.BLOCKED_INPUT.value,
                "message": "Votre message ne peut pas être traité."
            }

        # Couche 2 : Modération entrée
        check_input = self.moderer_entree(user_message)
        if not check_input["autorise"]:
            self.log_decision(Decision.BLOCKED_INPUT, {
                "violations": check_input["violations"]
            })
            return {
                "status": Decision.BLOCKED_INPUT.value,
                "message": "Ce contenu enfreint notre politique."
            }

        # Couche 3 : Génération
        messages = []
        if system_prompt:
            messages.append({"role": "system",
                           "content": system_prompt})
        messages.append({"role": "user",
                        "content": user_message})

        try:
            reponse = self.generer(messages)
        except SDKError as e:
            if e.status_code == 403:
                self.log_decision(Decision.BLOCKED_GUARDRAIL, {})
                return {
                    "status": Decision.BLOCKED_GUARDRAIL.value,
                    "message": "Requête bloquée par les guardrails."
                }
            raise

        # Couche 4 : Modération sortie
        check_output = self.moderer_sortie(user_message, reponse)
        if not check_output["autorise"]:
            self.log_decision(Decision.BLOCKED_OUTPUT, {
                "violations": check_output["violations"]
            })
            return {
                "status": Decision.BLOCKED_OUTPUT.value,
                "message": "La réponse a été filtrée."
            }

        # Succès
        self.log_decision(Decision.ALLOWED, {
            "input_max_score": max(
                check_input["scores"].values()
            ),
            "output_max_score": max(
                check_output["scores"].values()
            )
        })

        return {
            "status": Decision.ALLOWED.value,
            "content": reponse,
            "moderation": {
                "input": check_input["scores"],
                "output": check_output["scores"]
            }
        }

    # --- Utilitaires ---

    def _verifier_seuils(self, scores: dict) -> list:
        """Vérifie les scores contre les seuils de la politique."""
        violations = []
        for cat, seuil in self.politique["seuils"].items():
            score = scores.get(cat, 0)
            if score > seuil:
                violations.append({
                    "categorie": cat,
                    "score": round(score, 3),
                    "seuil": seuil
                })
        return violations

    def rapport(self) -> dict:
        """Génère un rapport de statistiques."""
        total = sum(self.stats.values())
        return {
            "politique": self.politique["nom"],
            "total_requetes": total,
            "decisions": self.stats,
            "taux_blocage": round(
                (self.stats["blocked_input"] +
                 self.stats["blocked_guardrail"] +
                 self.stats["blocked_output"]) / max(total, 1),
                3
            )
        }

Utilisation en production

# Définir la politique
politique_prod = {
    "nom": "Production v1.2",
    "seuils": {
        "sexual": 0.15, "hate": 0.1, "violence": 0.2,
        "criminal": 0.1, "selfharm": 0.1, "health": 0.4,
        "financial": 0.4, "law": 0.4, "pii": 0.15,
        "jailbreaking": 0.1, "unpredictable": 0.3
    }
}

# Instancier l'architecture
archi = ArchitectureSecurisee(politique_prod)

# Traiter des requêtes
resultat = archi.traiter(
    "Expliquez-moi le fonctionnement des transformers",
    system_prompt="Vous êtes un formateur en IA."
)
print(resultat["status"])   # → "allowed"
print(resultat["content"])  # → Explication des transformers

# Consulter les statistiques
print(archi.rapport())

Monitoring et alertes

En production, connectez votre architecture à votre stack de monitoring :

def configurer_alertes(archi: ArchitectureSecurisee):
    """Configure les alertes pour le monitoring."""
    rapport = archi.rapport()

    # Alerte si taux de blocage anormal
    if rapport["taux_blocage"] > 0.15:
        logger.warning(
            f"Taux de blocage élevé : "
            f"{rapport['taux_blocage']:.1%}"
        )

    # Alerte si pics de jailbreak
    # Intégrez avec Prometheus, Grafana, Datadog, etc.

Récapitulatif de la formation

Au terme de cette formation, vous maîtrisez :

  • Custom Guardrails : bloquer les prompts dangereux avant la génération, configurer les seuils par catégorie, appliquer aux agents
  • API Moderation : classifier le contenu avec Mistral Moderation 2, interpréter les scores des 11 catégories, prendre des décisions automatisées
  • Sécurité en production : définir des politiques de contenu, détecter les prompt injections, assurer la conformité RGPD
  • Architecture complète : assembler guardrails + modération + monitoring dans un pipeline robuste

Vous disposez de tout le code nécessaire pour déployer un système de modération IA complet avec l’API Mistral.

Points clés à retenir

  • L’architecture de sécurité comprend 5 couches : validation, guardrails, génération, modération, logging
  • Chaque couche compense les faiblesses des autres — c’est la défense en profondeur
  • Monitorez le taux de blocage et les scores en production
  • Maintenez votre politique à jour avec des révisions régulières
  • Le code complet de cette leçon est un point de départ — adaptez-le à votre contexte