Le deep-dive sécurité a posé le principe : un agent qui agit exige une défense en profondeur. Sur AWS, l’une de ces couches est managée et indépendante du modèle : Bedrock Guardrails. Ce chapitre la décortique — ses cinq politiques, ses deux modes d’usage, et son intégration dans un graphe LangGraph.

Les cinq politiques

Un guardrail combine jusqu’à cinq politiques, appliquées à l’entrée (prompt) et à la sortie (réponse).

Fig.01 · Les politiques d'un guardrail
01 Contenu haine, violence…
02 Sujets déni de thèmes
03 Mots liste noire
04 PII caviarde/bloque
05 Ancrage anti-hallu
Cinq filtres composables, appliqués en entrée et en sortie. On active ceux dont le cas a besoin, avec des seuils ajustables.
  1. Filtres de contenu — catégories (haine, insultes, violence, sexuel, conduite répréhensible, attaque de prompt) avec un seuil réglable (low/medium/high).
  2. Déni de sujets — des thèmes interdits décrits en langage naturel (« ne parle jamais de conseil en investissement »).
  3. Filtres de mots — une liste noire (jurons, noms de concurrents, termes internes) et des profanités prédéfinies.
  4. Informations sensibles (PII) — détection d’e-mails, numéros, IBAN… avec action bloquer ou caviarder (anonymiser).
  5. Vérification d’ancrage contextuel — mesure si la réponse est fondée sur la source fournie (grounding) et pertinente (relevance) : un anti-hallucination managé, précieux pour le RAG.

Créer un guardrail

On définit ces politiques par l’API (ou la console / l’IaC). Exemple resserré pour un agent de support.

import boto3
bedrock = boto3.client("bedrock", region_name="eu-west-1")

g = bedrock.create_guardrail(
    name="support-guardrail",
    blockedInputMessaging="Désolé, je ne peux pas traiter cette demande.",
    blockedOutputsMessaging="Réponse bloquée par la politique de sécurité.",
    contentPolicyConfig={"filtersConfig": [
        {"type": "PROMPT_ATTACK", "inputStrength": "HIGH", "outputStrength": "NONE"},
        {"type": "HATE", "inputStrength": "HIGH", "outputStrength": "HIGH"},
    ]},
    topicPolicyConfig={"topicsConfig": [{
        "name": "conseil-financier", "type": "DENY",
        "definition": "Tout conseil d'investissement ou recommandation financière.",
        "examples": ["Dois-je acheter cette action ?"],
    }]},
    sensitiveInformationPolicyConfig={"piiEntitiesConfig": [
        {"type": "EMAIL", "action": "ANONYMIZE"},
        {"type": "CREDIT_DEBIT_CARD_NUMBER", "action": "BLOCK"},
    ]},
)
guardrail_id, version = g["guardrailId"], g["version"]

Deux façons d’appliquer un guardrail

1. Attaché à l’inférence

Le plus simple : on passe l’identifiant au modèle, et la protection s’applique à chaque appel — comme vu dans le deep-dive Bedrock.

from langchain_aws import ChatBedrockConverse

modele = ChatBedrockConverse(
    model="eu.anthropic.claude-sonnet-4-5-20250929-v1:0",
    region_name="eu-west-1",
    guardrail_config={"guardrailIdentifier": guardrail_id,
                      "guardrailVersion": version, "trace": "enabled"},
)

2. Autonome, via ApplyGuardrail

L’API ApplyGuardrail évalue un texte sans appeler de modèle. C’est l’option puissante pour un agent : on en fait un nœud de garde explicite dans le graphe, qui filtre l’entrée avant l’agent et la sortie avant l’utilisateur — y compris autour de modèles non-Bedrock (un endpoint SageMaker, par exemple).

runtime = boto3.client("bedrock-runtime", region_name="eu-west-1")

def guardrail_ok(texte: str, source: str) -> tuple[bool, str]:
    """Évalue un texte ; renvoie (autorisé, texte éventuellement caviardé)."""
    res = runtime.apply_guardrail(
        guardrailIdentifier=guardrail_id, guardrailVersion=version,
        source=source,                      # 'INPUT' ou 'OUTPUT'
        content=[{"text": {"text": texte}}],
    )
    if res["action"] == "GUARDRAIL_INTERVENED":
        # Si caviardage de PII, le texte modifié est renvoyé ; sinon, blocage.
        sortie = res.get("outputs", [{}])[0].get("text", "")
        return (bool(sortie), sortie or "")
    return (True, texte)

Intégrer comme nœuds de garde dans LangGraph

On encadre l’agent de deux nœuds, réalisant les couches 1 et 4 de la défense en profondeur du deep-dive sécurité.

from typing import Literal
from langgraph.types import Command

def garde_entree(state) -> Command[Literal["agent", "refus"]]:
    ok, _ = guardrail_ok(state["messages"][-1].content, source="INPUT")
    if not ok:
        return Command(goto="refus", update={"messages": [
            {"role": "assistant", "content": "Demande non autorisée."}]})
    return Command(goto="agent")

def garde_sortie(state) -> dict:
    ok, texte = guardrail_ok(state["messages"][-1].content, source="OUTPUT")
    contenu = texte if ok else "[réponse bloquée par la politique de sécurité]"
    return {"messages": [{"role": "assistant", "content": contenu}]}

L’ancrage contextuel pour le RAG

La vérification d’ancrage mérite une mention spéciale : elle compare la réponse à la source fournie et bloque si la réponse n’est pas suffisamment fondée. C’est un anti-hallucination managé qui complète le juge applicatif du RAG correctif — la ceinture et les bretelles, là où la confiance est critique.

Coût, latence et observabilité

Un guardrail ajoute un appel et donc de la latence et un coût (facturé à l’unité de texte). Activez trace: enabled pour voir, dans la réponse et dans LangFuse/CloudWatch, quelle politique est intervenue — indispensable pour calibrer les seuils sans sur-bloquer.

Bonnes pratiques & pièges

Bonnes pratiques
  • Activez chaque politique là où elle agit : PROMPT_ATTACK en entrée, ancrage en sortie.
  • Versionnez vos guardrails (IaC) et testez les seuils sur des cas réels avant de durcir.
  • Pour un agent, préférez ApplyGuardrail en nœud explicite : visible dans le graphe et la trace.
  • PII : caviardez (ANONYMIZE) quand c'est possible, bloquez (BLOCK) pour le critique.
  • Combinez l'ancrage contextuel (managé) avec le juge applicatif du RAG correctif.
  • Activez trace: enabled pour calibrer sans sur-bloquer.
Pièges à éviter
  • Croire qu'un guardrail suffit : il ne connaît pas votre métier ni vos droits d'accès.
  • Régler tous les filtres sur HIGH : sur-blocage et faux positifs qui dégradent l'UX.
  • Oublier la latence/coût ajoutés à chaque appel : mesurez-les dans LangFuse.
  • N'appliquer le guardrail qu'en sortie : l'injection passe alors en entrée sans filtre.
  • Ne pas tracer les interventions : impossible de calibrer les seuils à l'aveugle.

Ce qu’il faut retenir

  • Bedrock Guardrails combine cinq politiques (contenu, sujets, mots, PII, ancrage), en entrée et en sortie.
  • Deux usages : attaché à l’inférence (simple) ou autonome via ApplyGuardrail (nœud de garde explicite, visible dans le graphe).
  • L’ancrage contextuel est un anti-hallucination managé, complément du juge du RAG correctif.
  • C’est une couche de la défense en profondeur — jamais un substitut aux garde-fous applicatifs et au HITL.
  • Tracez les interventions pour calibrer les seuils sans sur-bloquer.

Filtres de contenu et PII protègent le texte. Pour la récupération sur des données reliées, AWS offre une autre arme : le GraphRAG sur Neptune.

#aws#bedrock#guardrails#securite#pii