Configurer les guardrails en Python
Sur cette page
Leçon réécrite le 3 novembre 2026. Elle configurait les guardrails avec un dictionnaire inventé (
enabled), des catégories inexistantes (hate,violence,unpredictable), affirmait que les catégories non listées gardaient des « seuils par défaut », et testaite.status_code == 3201, alors que3201est un code d’erreur du corps de la réponse, pas un statut HTTP. La configuration suit désormais le format officiel, et le code a été vérifié contre les types du SDKmistralai3.7.0. Sources : Moderation & Guardrailing · SDK Python mistralai.
Passer de la théorie au code
Vous connaissez maintenant le principe des guardrails. Dans cette leçon, vous allez les configurer précisément : choisir vos catégories, définir vos seuils, et traiter les blocages dans votre code Python.
Le point de départ : le SDK Mistral installé (les guardrails demandent la version 2 ou plus), et une clé d’API lue depuis l’environnement plutôt qu’écrite dans le code.
pip install "mistralai>=2"
import os
from mistralai.client import Mistral
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
Le paramètre guardrails en détail
Le paramètre guardrails est une liste. Chaque élément associe l’option block_on_error à une configuration moderation_llm_v2, qui contient elle-même les seuils, l’option ignore_other_categories et l’action :
from mistralai.client.models import GuardrailConfigTypedDict
GUARDRAILS: list[GuardrailConfigTypedDict] = [
{
# Bloquer si l'évaluation elle-même échoue
"block_on_error": True,
"moderation_llm_v2": {
# Seuils par catégorie, de 0 à 1 (1 désactive la catégorie)
"custom_category_thresholds": {
"sexual": 0.2,
"hate_and_discrimination": 0.1,
"violence_and_threats": 0.3,
"dangerous": 0.2,
"criminal": 0.1,
"selfharm": 0.1,
"health": 0.5,
"financial": 0.5,
"law": 0.5,
"pii": 0.2,
"jailbreaking": 0.1,
},
"ignore_other_categories": False,
# Action en cas de dépassement
"action": "block",
},
}
]
Le modèle de modération par défaut est mistral-moderation-2603 ; la clé facultative model_name permet d’en désigner un autre.
L’annotation list[GuardrailConfigTypedDict] n’est pas obligatoire, mais elle vaut d’être prise : le SDK décrit chaque clé autorisée, et un vérificateur de types comme pyright ou mypy signale alors une catégorie mal orthographiée (violence au lieu de violence_and_threats), que l’API, elle, ne vous signalerait pas.
custom_category_thresholds
C’est le cœur de la configuration. Chaque catégorie reçoit un seuil entre 0 et 1, comparé au score que le classifieur attribue au prompt. Plus le seuil est bas, plus le filtre bloque, au risque d’écarter des requêtes légitimes. Un seuil à 1 désactive explicitement la catégorie. Mistral ne publie pas de grille de valeurs recommandées : c’est à vous de les calibrer sur vos propres cas (leçon 7).
Les valeurs n’ont de sens que rapportées à votre application. Un chatbot grand public verrouille les catégories sensibles au plus bas, alors qu’un outil interne destiné à des professionnels de santé doit laisser passer les questions médicales tout en restant strict sur les données personnelles.
# Chatbot grand public : seuils très bas
seuils_public = {
"sexual": 0.1,
"hate_and_discrimination": 0.1,
"violence_and_threats": 0.1,
"criminal": 0.1,
"selfharm": 0.1,
}
# Outil interne médical : la santé est désactivée, les données personnelles restent surveillées
seuils_medical = {
"sexual": 0.2,
"hate_and_discrimination": 0.1,
"violence_and_threats": 0.3,
"health": 1, # désactive la catégorie : les questions médicales sont le cœur de l'outil
"pii": 0.1,
}
Les catégories que vous ne listez pas
Que deviennent les catégories absentes de custom_category_thresholds ? La documentation ne le dit pas en toutes lettres, mais son exemple de blocage est parlant : les catégories non listées y figurent avec un seuil de 1.0, notées mais sans effet. Ne comptez donc pas sur un seuil par défaut : listez chaque catégorie qui doit pouvoir bloquer.
L’option ignore_other_categories règle seulement ce qui est évalué et renvoyé. À False, toutes les catégories évaluées apparaissent dans le résultat ; à True, seules celles que vous avez listées sont évaluées.
GUARDRAILS_CIBLES: list[GuardrailConfigTypedDict] = [
{
"block_on_error": True,
"moderation_llm_v2": {
"custom_category_thresholds": {
"hate_and_discrimination": 0.1,
"violence_and_threats": 0.2,
},
"ignore_other_categories": True, # n'évalue que ces deux catégories
"action": "block",
},
}
]
Attention : avec cette configuration, une tentative de jailbreak ou une demande de données personnelles passerait sans obstacle. Ne restreignez la liste que pour une raison précise.
Exemple complet : chatbot avec guardrails
Voici une fonction minimale : elle envoie le message avec la configuration complète et transforme un blocage en réponse lisible pour l’utilisateur.
from mistralai.client import errors
def chat_securise(message_utilisateur: str) -> str:
"""Envoie un message protégé par les guardrails."""
try:
response = client.chat.complete(
model="mistral-large-latest",
messages=[
{"role": "system", "content": "Vous êtes un assistant professionnel."},
{"role": "user", "content": message_utilisateur},
],
guardrails=GUARDRAILS,
)
except errors.SDKError as e:
if e.status_code == 403:
return "Désolé, cette requête ne peut pas être traitée."
raise
contenu = response.choices[0].message.content
return contenu if isinstance(contenu, str) else ""
print(chat_securise("Expliquez-moi le machine learning"))
Deux remarques. message.content peut être une chaîne ou une liste de morceaux selon le modèle, d’où le test isinstance. Et la réponse de chat.complete() n’expose pas les scores des guardrails dans le SDK 3.7.0 : pour les journaliser, passez par l’API Conversations, dont la réponse les porte dans guardrails.
Gérer les erreurs de blocage proprement
Il faut distinguer deux échecs qui n’appellent ni le même message ni la même alerte : un blocage par la politique de contenu, qui renvoie un statut HTTP 403, et une panne de l’évaluation avec block_on_error activé, que le corps de la réponse signale par le code 3201. Les deux arrivent sous forme d’errors.SDKError, dont body contient le JSON renvoyé par l’API :
import json
from typing import Any
from mistralai.client import errors
def chat_avec_gestion_erreurs(message_utilisateur: str) -> dict[str, Any]:
"""Chat qui distingue blocage par la politique et panne de la modération."""
try:
response = client.chat.complete(
model="mistral-large-latest",
messages=[{"role": "user", "content": message_utilisateur}],
guardrails=GUARDRAILS,
)
except errors.SDKError as e:
try:
corps = json.loads(e.body)
except json.JSONDecodeError:
raise e
if corps.get("code") == 3201:
return {
"status": "error",
"content": "Service de modération indisponible. Requête bloquée par précaution.",
}
if e.status_code == 403:
decisions = corps["guardrails"]["results"]["moderation_llm_v2"]["decisions"]
return {
"status": "blocked",
"content": "Votre message a été bloqué par notre politique de sécurité.",
"categories": [nom for nom, d in decisions.items() if d["violated"]],
}
raise
return {"status": "ok", "content": response.choices[0].message.content}
Le test du code 3201 vient en premier, car la documentation ne précise pas le statut HTTP de cette erreur. Les catégories violées sont tirées de decisions, où chaque entrée donne threshold, score et violated : c’est ce que vous journaliserez pour expliquer un blocage.
Bonnes pratiques de configuration
Démarrez restrictif, puis desserrez. Des seuils bas au lancement vous font découvrir vos faux positifs sur un volume encore maîtrisable, et chaque relèvement se décide sur des cas observés plutôt que sur une intuition :
# Phase 1 : lancement (très restrictif)
phase1 = {"hate_and_discrimination": 0.1, "violence_and_threats": 0.1, "criminal": 0.1}
# Phase 2 : après analyse des faux positifs
phase2 = {"hate_and_discrimination": 0.15, "violence_and_threats": 0.25, "criminal": 0.1}
# Phase 3 : production stable
phase3 = {"hate_and_discrimination": 0.2, "violence_and_threats": 0.3, "criminal": 0.15}
Ces valeurs illustrent la démarche ; les vôtres sortiront de vos propres mesures. Gardez block_on_error à True en production : sa valeur par défaut dans le SDK est False, et une panne de la modération laisserait alors passer du contenu non vérifié. Enfin, la documentation prévient que le modèle de modération évolue : des politiques fondées sur les scores peuvent demander un recalibrage.
Points clés à retenir
guardrailsest une liste d’objets{"block_on_error": ..., "moderation_llm_v2": {...}}- Dans
moderation_llm_v2:custom_category_thresholds,ignore_other_categories,actionet, en option,model_name - Seuils de
0à1; plus bas, plus strict ;1désactive une catégorie. Listez chaque catégorie qui doit bloquer - Un blocage lève
errors.SDKErroravecstatus_code == 403; une panne avecblock_on_errorporte le code3201dans le corps - Gardez
block_on_error=Trueen production, la valeur par défaut étantFalse