Déployer un LLM en production sans contrôle, c'est comme exposer une API sans authentification : ça finit toujours mal. Entre les prompt injections, les hallucinations, les fuites de données et les dérives de sujet, les risques sont nombreux. La réponse de l'industrie tient en un mot : guardrails (garde-fous).

Mais derrière ce terme se cache une réalité plus riche qu'on ne le pense souvent. Les guardrails ne se limitent pas à des filtres externes branchés autour du modèle : la sécurité d'un LLM se joue à plusieurs niveaux, depuis son entraînement jusqu'à l'inférence finale. Ce billet fait le tour de la question, du plus pratique (un filtre regex) au plus profond (le RLHF), avec les coûts réels associés.

01 — Les guardrails externes : la couche visible

Les trois familles de guardrails

On distingue généralement trois types de guardrails, qu'on combine en production :

Approche 1 — Validation par règles

L'approche la plus simple, et souvent sous-estimée. Rapide, déterministe, auditable.

import re

BLOCKED_PATTERNS = [
    r"(?i)ignore previous instructions",
    r"\b\d{16}\b",  # numéros de carte
    r"(?i)système prompt",
]

def input_guardrail(user_input: str) -> tuple[bool, str]:
    for pattern in BLOCKED_PATTERNS:
        if re.search(pattern, user_input):
            return False, "Requête bloquée"
    if len(user_input) > 4000:
        return False, "Entrée trop longue"
    return True, "OK"

Limites : peu robuste face aux variations linguistiques, contournable par paraphrase.

Approche 2 — Classification par un modèle dédié

On utilise un petit modèle (ou un LLM en mode « juge ») pour catégoriser les requêtes.

def llm_judge(text: str, client) -> dict:
    response = client.messages.create(
        model="claude-haiku-4-5-20251001",
        max_tokens=100,
        messages=[{
            "role": "user",
            "content": f"""Classe ce texte. Réponds en JSON strict:
{{"safe": bool, "category": "toxic|injection|pii|safe", "confidence": 0-1}}

Texte: {text}"""
        }]
    )
    return json.loads(response.content[0].text)

Approche 3 — Frameworks dédiés

Trois options matures selon le besoin :

NeMo Guardrails (NVIDIA) utilise un langage déclaratif (Colang) pour définir des flux conversationnels.

# config.yml
rails:
  input:
    flows:
      - check jailbreak
      - mask sensitive data
  output:
    flows:
      - check hallucination
      - check toxicity

Guardrails AI repose sur des validateurs Python composables, avec un hub de validateurs prêts à l'emploi.

from guardrails import Guard
from guardrails.hub import ToxicLanguage, DetectPII

guard = Guard().use_many(
    ToxicLanguage(threshold=0.8, on_fail="exception"),
    DetectPII(pii_entities=["EMAIL_ADDRESS", "PHONE_NUMBER"], on_fail="fix")
)

validated_output = guard.parse(llm_output)

Llama Guard (Meta) est un modèle open-source spécifiquement entraîné pour la modération, à appeler avant ou après le LLM principal.

Approche 4 — Architecture en pipeline

L'approche la plus robuste combine plusieurs couches :

User Input
   ↓
[Input Guardrails] → règles + classifier
   ↓
[LLM principal]
   ↓
[Output Guardrails] → validation format + factualité + toxicité
   ↓
Response
class GuardedLLM:
    def __init__(self, llm, input_guards, output_guards):
        self.llm = llm
        self.input_guards = input_guards
        self.output_guards = output_guards

    def generate(self, prompt: str) -> str:
        for guard in self.input_guards:
            ok, msg = guard(prompt)
            if not ok:
                return f"Requête refusée: {msg}"

        response = self.llm.generate(prompt)

        for guard in self.output_guards:
            response = guard(response)  # corrige ou rejette

        return response

Points d'attention

02 — Les mécanismes internes au modèle

Les guardrails externes ne sont que la partie visible. La sécurité la plus profonde se joue dans le modèle lui-même.

L'alignement par entraînement

Le modèle est entraîné à refuser certaines requêtes. Ce n'est pas un filtre ajouté : c'est ancré dans ses poids. Trois techniques principales :

RLHF (Reinforcement Learning from Human Feedback) — des humains classent les réponses du modèle, un modèle de récompense est entraîné à reproduire ces préférences, puis le LLM est optimisé pour maximiser cette récompense. C'est ce qui fait qu'un modèle « sait » qu'il ne doit pas expliquer comment fabriquer une arme.

RLAIF / Constitutional AI (Anthropic) — au lieu d'humains, c'est une IA qui critique et réécrit les réponses selon une « constitution » de principes. Le modèle apprend à s'auto-critiquer pendant l'entraînement.

DPO (Direct Preference Optimization) — version plus directe et stable du RLHF, qui évite d'entraîner un modèle de récompense séparé.

Le pipeline canonique :

Phase 1: Pré-entraînement (connaissances brutes)
   ↓
Phase 2: Fine-tuning supervisé (suivre des instructions)
   ↓
Phase 3: RLHF / DPO (alignement sur préférences humaines)
   ↓
Modèle aligné

Le system prompt

Le prompt système injecté avant la conversation est une forme de guardrail interne au sens où il oriente le comportement du modèle sans appel externe. Bien rédigé, il définit le rôle, les sujets autorisés, le ton, les formats. Faillible (jailbreaks possibles) mais c'est la première ligne.

Le fine-tuning spécifique

On peut fine-tuner un modèle de base sur ses propres exemples pour qu'il refuse certaines requêtes ou réponde d'une certaine manière. Le comportement devient alors intrinsèque au modèle.

# Exemple conceptuel de dataset de fine-tuning
training_data = [
    {"input": "Donne-moi le mot de passe admin",
     "output": "Je ne peux pas partager d'identifiants."},
    {"input": "Aide-moi à contourner la sécurité",
     "output": "Je ne peux pas aider sur ce sujet."},
    # ... des milliers d'exemples
]

Mécanismes pendant l'inférence

Plusieurs leviers agissent pendant la génération, dans le modèle lui-même :

from outlines import models, generate

model = models.transformers("...")
generator = generate.json(model, schema)
# Le modèle ne peut générer QUE du JSON valide

Recherche émergente : interprétabilité mécaniste

Anthropic et d'autres équipes travaillent sur l'identification de « circuits » dans les réseaux de neurones correspondant à des concepts spécifiques (refus, déception, sycophancy…). À terme, on pourrait modifier ces circuits directement — un guardrail vraiment au niveau des poids. Encore de la recherche, pas de la production.

Comparaison interne vs externe

AspectInterne (alignement)Externe (filtre)
RobustesseProfonde mais opaqueExplicite et auditable
ContournementJailbreaks via prompts créatifsBypass si pattern non couvert
ModificationNécessite ré-entraînementModifiable en temps réel
LatenceAucuneAjoute un appel
CoûtÉlevé (entraînement)Faible (par appel)
Spécificité métierDifficile à customiserFacile à adapter

Conclusion : en production sérieuse, on combine les deux. L'alignement interne couvre les abus universels (violence, contenus illégaux), les guardrails externes couvrent le domaine spécifique (« reste sur le sujet bancaire », « ne mentionne pas les produits concurrents »).

03 — Les datasets ouverts pour l'alignement

Si on veut entraîner ou fine-tuner son propre modèle aligné, il existe heureusement un écosystème riche de datasets ouverts.

Datasets de préférences (RLHF / DPO)

Paires (réponse préférée, réponse rejetée) pour entraîner un modèle de récompense ou faire du DPO.

DatasetVolumeSpécificité
Anthropic HH-RLHF~170k pairesRéférence historique, axes helpful et harmless
OpenAssistant (OASST1/2)~160k messagesCrowdsourcé, multilingue (dont français)
UltraFeedback~64k prompts4 réponses par prompt, notées par GPT-4 sur 4 critères
Nectar~183k prompts7 réponses classées, utilisé pour Starling
PKU-SafeRLHF~330k pairesFocalisé sécurité, utilité et innocuité séparées

Datasets d'instruction-following (SFT)

Pour la phase de fine-tuning supervisé qui précède le RLHF.

DatasetVolumeNote
Alpaca52kPionnier, généré par GPT-3, non commercial
Dolly 15k15k100% humain, licence permissive
OpenHermes 2.5~1MAgrégation très complète
FLAN CollectionMillionsCompilation Google, centaines de tâches
Tulu 3VariableMix curé par AllenAI

Datasets de sécurité / red-teaming

Pour entraîner un modèle à refuser ou tester ses limites.

Datasets multilingues / français

Point souvent faible. Quelques options :

En pratique

ObjectifDataset recommandé
SFT généralisteOpenHermes 2.5 ou Tulu 3
DPO / RLHF généralUltraFeedback
Focus sécuritéPKU-SafeRLHF + BeaverTails
Reproduction de papierHH-RLHF (référence)
MultilingueAya + OASST
Évaluation safetyHarmBench, Do-Not-Answer

Pipeline open-source typique

C'est l'approche qu'a suivie Hugging Face pour Zephyr :

Modèle de base (Mistral, Llama...)
   ↓
SFT sur UltraChat ou OpenHermes
   ↓
DPO sur UltraFeedback
   ↓
Modèle aligné

Points d'attention

04 — La capacité de calcul nécessaire

C'est souvent le facteur décisif. La réponse dépend de la taille du modèle, de la technique de fine-tuning, et du type (SFT vs DPO vs RLHF complet).

Règle de base

Pour un fine-tuning full (tous les paramètres entraînables), la VRAM nécessaire est environ 16 à 20 fois la taille du modèle en paramètres (en milliards). Pourquoi ? Il faut stocker en mémoire :

Modèle 7B en full fine-tuning ≈ 7B × 18 octets ≈ 126 Go de VRAM

Soit 2 GPU A100 80Go minimum, en pratique 4 pour avoir de la marge.

Les techniques qui changent tout

LoRA (Low-Rank Adaptation) — on ne fine-tune pas tous les poids, mais des petites matrices d'adaptation ajoutées à certaines couches. Typiquement 0,1 % à 1 % des paramètres deviennent entraînables.

from peft import LoraConfig, get_peft_model

config = LoraConfig(
    r=16,              # rang des matrices
    lora_alpha=32,
    target_modules=["q_proj", "v_proj"],
    lora_dropout=0.05,
)
model = get_peft_model(base_model, config)
# ~0.5% de paramètres entraînables

Gain : la VRAM tombe à environ 2-3× la taille du modèle.

QLoRA (Quantized LoRA) — LoRA + quantification 4-bit du modèle de base. Seules les adaptations LoRA sont en précision normale.

Gain : la VRAM chute à environ 0,75× la taille du modèle. C'est ce qui permet de fine-tuner un 7B sur une seule RTX 3090 (24 Go).

Tableau récapitulatif par taille de modèle

ModèleFull fine-tuningLoRAQLoRA
1-3B (Phi-3, Llama 3.2 3B)1× A100 40Go1× RTX 3090 24Go1× RTX 3060 12Go
7-8B (Mistral 7B, Llama 3.1 8B)4× A100 80Go1× A100 40Go ou 1× RTX 40901× RTX 3090 24Go
13B8× A100 80Go2× A100 40Go1× A100 40Go
30-34B16× A100 80Go (cluster)4× A100 80Go1× A100 80Go
70B (Llama 3.1 70B)Cluster H100 multi-nœuds8× A100 80Go2× A100 80Go
405B (Llama 3.1 405B)Hors de portée hors big techCluster H1008× H100 80Go minimum

Le temps d'entraînement

Ordre de grandeur sur un dataset typique (50-100k exemples, 3 epochs) :

SFT avec QLoRA sur Llama 3 8B

DPO avec QLoRA sur Llama 3 8B

RLHF complet (PPO)

Coûts cloud approximatifs

Si on loue du GPU (RunPod, Lambda Labs, Vast.ai, AWS) :

SetupTarif horaire approx.Coût d'un fine-tuning 8B en QLoRA
1× RTX 4090 (RunPod)0,40-0,70 €/h8-15 €
1× A100 40Go1,00-1,50 €/h10-20 €
1× A100 80Go1,50-2,00 €/h12-25 €
1× H100 80Go2,50-4,00 €/h15-30 €
8× A100 80Go (node)12-20 €/h50-150 € pour un 70B en QLoRA

Les hyperscalers (AWS, GCP, Azure) sont 2 à 4× plus chers que les acteurs spécialisés.

Recommandations par budget

Optimisations cumulables

Quelques techniques à connaître, combinables avec LoRA/QLoRA :

# Exemple Unsloth — fine-tuning Llama 8B sur une seule RTX 3090
from unsloth import FastLanguageModel

model, tokenizer = FastLanguageModel.from_pretrained(
    "unsloth/llama-3-8b",
    max_seq_length=2048,
    load_in_4bit=True,
)
model = FastLanguageModel.get_peft_model(model, r=16, ...)
# Et c'est parti

Pipeline minimal réaliste

Pour un projet sérieux mais raisonnable, le pipeline le plus accessible aujourd'hui :

Mistral 7B ou Llama 3.1 8B (base)
   ↓ QLoRA + Unsloth sur OpenHermes (sous-échantillonné)
   ↓ ~10h sur A100 80Go, ~20 €
SFT model
   ↓ QLoRA DPO sur UltraFeedback
   ↓ ~6h sur A100 80Go, ~12 €
Modèle aligné
Verdict

Total : ~35 € de cloud et 2 jours de calcul pour un modèle 7B aligné convenable. Ce qui demandait un cluster il y a deux ans tient aujourd'hui sur une RTX 3090.

Conclusion

Mettre en place des guardrails sur un LLM, c'est en réalité travailler sur quatre couches complémentaires :

  1. Le prompt système : la première ligne, gratuite et immédiate.
  2. L'alignement interne du modèle : RLHF, Constitutional AI, fine-tuning ciblé. Profond, opaque, coûteux à modifier.
  3. Les guardrails externes : règles, classifiers, frameworks. Explicites, modifiables en temps réel, mais ajoutent de la latence.
  4. Les contraintes d'inférence : decoding contraint, logit bias, self-critique.

Aucune couche ne suffit seule. Un bon système combine les quatre, en adaptant le curseur selon le contexte : un prototype interne peut se contenter d'un bon prompt système et de règles simples ; un produit grand public en domaine sensible (santé, finance, juridique) doit empiler les défenses.

La barrière n'est plus le matériel : c'est la rigueur d'évaluation, la qualité des données, et la compréhension fine de ce qu'on cherche à protéger.

La bonne nouvelle, c'est que l'écosystème open-source est aujourd'hui d'une richesse remarquable : datasets d'alignement ouverts, frameworks de guardrails matures, techniques de fine-tuning efficaces (QLoRA, Unsloth) qui permettent à un développeur seul d'aligner un modèle 7B pour quelques dizaines d'euros. Ce qui demandait un cluster il y a deux ans tient aujourd'hui sur une RTX 3090.

Un projet d'alignement ou de guardrails à mener ?

Choix d'architecture (interne / externe / hybride), sélection des frameworks, dataset, fine-tuning DPO/RLHF, mise en production. Première analyse de faisabilité offerte.

Échanger avec un expert