Aller au contenu principal

Ancrer les Réponses dans les Sources et Réduire les Hallucinations

Le problème des hallucinations en production

Les hallucinations — ces réponses factuellement incorrectes mais formulées avec assurance — représentent le risque principal des LLM en production. Un chatbot de support qui invente une procédure, un assistant juridique qui cite un article de loi inexistant, un outil médical qui recommande un mauvais dosage : les conséquences peuvent être graves.

Le grounding (ancrage) consiste à contraindre le modèle à fonder ses réponses exclusivement sur des sources vérifiées. Combiné au système de citations de Mistral, il crée un filet de sécurité robuste.

Stratégie 1 : System prompt strict

Le system prompt est votre première ligne de défense. Soyez explicite sur ce que le modèle doit et ne doit pas faire :

system_prompt = """
Vous êtes un assistant documentaire spécialisé.

RÈGLES ABSOLUES :
1. Répondez UNIQUEMENT à partir des sources fournies via les références.
2. Si l'information n'est pas dans les sources, répondez :
   "Cette information ne figure pas dans les sources disponibles."
3. Ne complétez JAMAIS avec vos connaissances générales.
4. Citez chaque affirmation avec la référence correspondante.
5. Si deux sources se contredisent, mentionnez les deux versions.
"""

Ce prompt ne garantit pas l’absence d’hallucinations, mais réduit considérablement leur fréquence. Le modèle Mistral, entraîné pour le grounding, respecte ces consignes avec un taux de conformité élevé.

Stratégie 2 : Validation post-génération

Même avec un bon prompt, vérifiez programmatiquement que la réponse s’appuie sur les sources :

from mistralai.models import TextChunk, ReferenceChunk


def validate_grounding(response, min_citations=1):
    """Vérifie que la réponse est ancrée dans les sources."""
    content = response.choices[0].message.content

    text_length = 0
    citation_count = 0
    cited_refs = set()

    for chunk in content:
        if isinstance(chunk, TextChunk):
            text_length += len(chunk.text)
        elif isinstance(chunk, ReferenceChunk):
            citation_count += 1
            cited_refs.update(chunk.reference_ids)

    # Vérifications
    checks = {
        "has_citations": citation_count >= min_citations,
        "citation_count": citation_count,
        "unique_sources": len(cited_refs),
        "text_length": text_length,
        "citations_per_1000_chars": round(
            citation_count / max(text_length / 1000, 1), 1
        )
    }

    checks["is_grounded"] = checks["has_citations"]
    return checks


result = validate_grounding(final_response, min_citations=2)
if not result["is_grounded"]:
    print("ALERTE : Réponse potentiellement non ancrée !")
    print(f"  Citations trouvées : {result['citation_count']}")

Stratégie 3 : Détection de réponses hors périmètre

Identifiez les cas où le modèle a dépassé les sources fournies :

def detect_ungrounded_claims(response_text, source_snippets):
    """Détecte les phrases qui ne correspondent à aucun snippet."""
    import re

    # Découper la réponse en phrases
    sentences = re.split(r'[.!?]+', response_text)
    sentences = [s.strip() for s in sentences if len(s.strip()) > 20]

    # Concaténer tous les snippets en un seul texte
    all_sources = " ".join(source_snippets).lower()

    suspicious = []
    for sentence in sentences:
        # Extraire les mots-clés significatifs (> 5 chars)
        keywords = [
            w.lower() for w in sentence.split()
            if len(w) > 5
        ]
        # Vérifier la couverture
        matches = sum(1 for kw in keywords if kw in all_sources)
        coverage = matches / max(len(keywords), 1)

        if coverage < 0.3:  # Moins de 30 % de mots-clés trouvés
            suspicious.append({
                "sentence": sentence,
                "coverage": round(coverage, 2)
            })

    return suspicious

Stratégie 4 : Pipeline de confiance à plusieurs niveaux

En production, combinez les approches dans un pipeline cohérent :

class GroundedRAG:
    """Pipeline RAG avec ancrage et validation."""

    def __init__(self, client, model="mistral-large-latest"):
        self.client = client
        self.model = model

    def query(self, question, references, strict=True):
        """Exécute une requête RAG avec validation d'ancrage."""

        # 1. Générer la réponse avec citations
        response = self._generate_with_citations(
            question, references
        )

        # 2. Valider l'ancrage
        grounding = validate_grounding(response, min_citations=1)

        # 3. En mode strict, rejeter les réponses non ancrées
        if strict and not grounding["is_grounded"]:
            return {
                "status": "rejected",
                "reason": "Réponse insuffisamment ancrée dans les sources",
                "grounding_score": grounding
            }

        # 4. Retourner la réponse validée
        return {
            "status": "ok",
            "response": response,
            "grounding_score": grounding,
            "confidence": self._compute_confidence(grounding)
        }

    def _compute_confidence(self, grounding):
        """Calcule un score de confiance basé sur l'ancrage."""
        score = 0.0
        if grounding["has_citations"]:
            score += 0.4
        if grounding["unique_sources"] >= 2:
            score += 0.3
        if grounding["citations_per_1000_chars"] >= 1.0:
            score += 0.3
        return round(score, 2)

Métriques de grounding à monitorer

En production, suivez ces indicateurs :

  • Taux de citations — Pourcentage de réponses contenant au moins une citation
  • Densité de citations — Nombre moyen de citations par 1000 caractères
  • Diversité des sources — Nombre moyen de sources distinctes par réponse
  • Taux de rejet — Pourcentage de réponses rejetées pour ancrage insuffisant
  • Score de confiance moyen — Évolution du score de confiance dans le temps

Points clés à retenir

  • Le grounding contraint le modèle à répondre uniquement à partir de sources vérifiées
  • Le system prompt strict est la première ligne de défense contre les hallucinations
  • La validation post-génération vérifie programmatiquement l’ancrage de chaque réponse
  • Combinez ces stratégies dans un pipeline de confiance à plusieurs niveaux
  • Monitorez les métriques de grounding en continu pour détecter les dégradations