0Pricing
AI Agents · Leçon

Vérification des faits et prévention des hallucinations

Vérification fondée sur l’ancrage : chaque affirmation doit être reliée à une source récupérée.

Vérification des faits et prévention des hallucinations est une leçon AI Agents gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Agents, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Agents comprend 4 leçons au total.

Le problème des hallucinations dans les agents de recherche

Les LLM peuvent générer des affirmations plausibles, mais sans fondement dans les sources récupérées. Dans un agent de recherche, cela est particulièrement dangereux, car le résultat semble faire autorité et est présenté avec des citations qui n’étayent peut-être pas réellement l’affirmation.

La prévention des hallucinations doit être une priorité fondamentale.

Ancrage : chaque affirmation renvoie à une source

Le principe fondamental de l’ancrage est le suivant : chaque affirmation factuelle de la sortie finale doit pouvoir être rattachée à au moins un document récupéré. Les affirmations impossibles à rattacher sont soit des hallucinations, soit des affirmations non étayées — les deux sont inacceptables dans un rapport de recherche.

def check_grounding(claim: str, retrieved_docs: list[dict]) -> dict:
    doc_texts = '\n\n'.join(
        f'[DOC {i+1}] ({d["url"]})\n{d["text"][:800]}'
        for i, d in enumerate(retrieved_docs[:5])
    )
    return {
        'claim': claim,
        'docs':  doc_texts,
        'grounded': None   # to be filled by LLM verifier
    }

if __name__ == '__main__':
    docs = [{'url': 'https://example.com/geo', 'text': 'Paris is the capital of France.'}]
    result = check_grounding('Paris is the capital of France.', docs)
    print('Claim:', result['claim'])
    print('Supporting docs used:')
    print(result['docs'])

Modèle du LLM comme vérificateur

Utilisez un appel distinct du LLM — le « vérificateur » — pour déterminer si une affirmation est étayée par les sources fournies. Vous créez ainsi un mécanisme de contrôle mutuel dans lequel le générateur et le vérificateur sont des appels indépendants.

import openai, json

client = openai.OpenAI(api_key='YOUR_OPENAI_KEY')

def verify_claim(claim: str, source_texts: list[str]) -> dict:
    sources_block = '\n---\n'.join(source_texts[:3])
    prompt = (
        f'Is the following claim directly supported by the provided sources?\n'
        f'Claim: "{claim}"\n\n'
        f'Sources:\n{sources_block}\n\n'
        f'Return JSON: {{\n'
        f'  "supported": true/false,\n'
        f'  "confidence": 0.0-1.0,\n'
        f'  "reason": "one sentence explanation"\n'
        f'}}'
    )
    resp = client.chat.completions.create(
        model='gpt-4o',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'}
    )
    return json.loads(resp.choices[0].message.content)

Sortie filtrée selon la confiance

Définissez des seuils pour le score de confiance du vérificateur. Les affirmations dont le score dépasse 0,85 sont publiées. Entre 0,5 et 0,85, elles sont publiées avec une clause de non-responsabilité. En dessous de 0,5, elles sont exclues.

INCLUDE_THRESHOLD  = 0.85
DISCLAIMER_THRESHOLD = 0.50

def gate_claim(claim: str, source_texts: list[str]) -> dict:
    result = verify_claim(claim, source_texts)
    conf = result.get('confidence', 0.0)
    supported = result.get('supported', False)

    if not supported or conf < DISCLAIMER_THRESHOLD:
        return {'action': 'exclude', 'claim': claim, 'reason': result.get('reason')}
    elif conf < INCLUDE_THRESHOLD:
        return {
            'action': 'include_with_disclaimer',
            'claim': f'[LOW CONFIDENCE] {claim}',
            'reason': result.get('reason')
        }
    else:
        return {'action': 'include', 'claim': claim}

Détecter des schémas d’hallucination précis

Certains schémas d’affirmation présentent un risque élevé d’hallucination : statistiques exactes (pourcentages, montants en dollars), dates précises, personnes nommées et liens de causalité. Examinez-les avec une attention particulière.

import re

def is_high_risk_claim(claim: str) -> bool:
    patterns = [
        r'\d+\.?\d*\s*%',            # percentages: 9.1%
        r'\$\s*\d+',                  # dollar amounts
        r'\b(January|February|March|April|May|June|July|August|September|October|November|December)\s+\d{4}',  # dates
        r'\b[A-Z][a-z]+\s+[A-Z][a-z]+\s+(said|stated|argued|claimed)',  # named quotes
        r'(caused?|led to|resulted in)',                                  # causal claims
    ]
    return any(re.search(p, claim) for p in patterns)

print(is_high_risk_claim('Inflation hit 9.1% in June 2022'))  # True
print(is_high_risk_claim('Inflation was elevated'))            # False

Boucle de vérification par décomposition

Pour les longues sections, décomposez le texte en affirmations individuelles, vérifiez chaque affirmation indépendamment, puis reconstruisez la section en ne conservant que les affirmations vérifiées.

def decompose_into_claims(section_text: str) -> list[str]:
    prompt = (
        f'Break this text into individual verifiable factual claims.\n'
        f'Each claim should be a single sentence containing exactly one fact.\n'
        f'Return JSON: {{"claims": ["..."]}}\n\n'
        f'TEXT:\n{section_text}'
    )
    resp = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'}
    )
    return json.loads(resp.choices[0].message.content).get('claims', [])

Reconstruire un texte vérifié

Après avoir filtré chaque affirmation selon son niveau de confiance, reconstruisez une section claire et cohérente à partir des seules affirmations vérifiées. Excluez celles qui présentent une faible confiance et réécrivez le texte pour en améliorer la lisibilité.

def reconstruct_section(verified_claims: list[str],
                        section_name: str) -> str:
    claims_text = '\n'.join(f'- {c}' for c in verified_claims)
    prompt = (
        f'Rewrite these verified facts as a coherent {section_name} section.\n'
        f'Do NOT add any new information not present in the claims.\n'
        f'Only use the facts provided.\n\n'
        f'VERIFIED CLAIMS:\n{claims_text}'
    )
    resp = client.chat.completions.create(
        model='gpt-4o',
        messages=[{'role': 'user', 'content': prompt}]
    )
    return resp.choices[0].message.content

Détecter la dérive numérique

Les LLM modifient parfois subtilement les nombres de la source (par exemple, 9,1 % devient 9,2 %). Extrayez les nombres de l’affirmation et du texte source, puis comparez-les explicitement.

import re

def extract_numbers(text: str) -> list[float]:
    matches = re.findall(r'[-+]?\d*\.?\d+', text)
    return [float(m) for m in matches]

def check_numeric_drift(claim: str, source_text: str,
                        tolerance: float = 0.01) -> bool:
    claim_nums  = extract_numbers(claim)
    source_nums = extract_numbers(source_text)

    for cn in claim_nums:
        found_match = any(abs(cn - sn) <= tolerance for sn in source_nums)
        if not found_match:
            return True  # numeric drift detected
    return False

print(check_numeric_drift(
    'Inflation reached 9.2% in June 2022',
    'The CPI rose 9.1 percent in June 2022'
))  # True — 9.2 vs 9.1

Audit d’attribution

Après avoir généré un rapport complet, effectuez un audit d’attribution : pour chaque phrase du rapport, vérifiez qu’elle peut être attribuée à l’une des sources. Signalez toute phrase qui ne possède aucun extrait de source correspondant.

def attribution_audit(report_text: str, sources: list[dict]) -> list[str]:
    sentences = [s.strip() for s in report_text.split('.') if len(s.strip()) > 20]
    unattributed = []

    for sentence in sentences:
        found = False
        for src in sources:
            if any(word in src.get('text', '') for word in sentence.split()[:5]):
                found = True
                break
        if not found:
            unattributed.append(sentence)

    return unattributed

# Flag unattributed sentences for manual review or re-verification

if __name__ == '__main__':
    report = ("Water boils at 100 degrees Celsius at sea level. "
              "The moon is made primarily of green cheese according to this document.")
    sources = [{'text': 'Water boils at 100C (212F) at standard atmospheric pressure.'}]
    unattributed = attribution_audit(report, sources)
    print('Unattributed sentences (need manual review):')
    for s in unattributed:
        print(' -', s)

Nuancer les affirmations incertaines

Tout ne peut pas être vérifié avec un niveau de confiance élevé. Au lieu d’exclure entièrement les affirmations limites, utilisez une formulation nuancée : « Certains analystes avancent que… », « Selon X… », « Il a été rapporté que… ». Vous préservez ainsi l’information tout en signalant l’incertitude.

def hedge_claim(claim: str, confidence: float) -> str:
    if confidence >= 0.85:
        return claim  # state as fact
    elif confidence >= 0.65:
        hedges = ['Some sources suggest', 'According to available evidence',
                  'Analysts have noted']
        return f'{hedges[hash(claim) % len(hedges)]}, {claim.lower()}'
    else:
        return f'It has been reported (with low confidence) that {claim.lower()}'

print(hedge_claim('Inflation peaked at 9.1%', 0.90))
print(hedge_claim('Supply chain disruptions contributed to inflation', 0.72))
print(hedge_claim('Specific policy caused inflation', 0.45))

Suivre le taux d’hallucination

Suivez le taux d’hallucination au fil du temps : quel pourcentage des affirmations générées échoue à la vérification ? Définissez un seuil d’alerte. S’il augmente brusquement, c’est que la conception de vos instructions ou la qualité de la récupération s’est dégradée.

verification_log = []  # In production: a database

def log_verification(claim: str, supported: bool, confidence: float):
    verification_log.append({
        'claim':      claim[:100],
        'supported':  supported,
        'confidence': confidence
    })

def hallucination_rate() -> float:
    if not verification_log:
        return 0.0
    failed = sum(1 for v in verification_log if not v['supported'])
    return failed / len(verification_log)

def check_hallucination_alert(threshold: float = 0.15):
    rate = hallucination_rate()
    if rate > threshold:
        print(f'ALERT: Hallucination rate {rate:.1%} exceeds threshold {threshold:.1%}')
    return rate

if __name__ == '__main__':
    log_verification('The sky is blue', True, 0.95)
    log_verification('The moon is made of cheese', False, 0.2)
    log_verification('Water boils at 100C at sea level', True, 0.99)
    rate = check_hallucination_alert(threshold=0.15)
    print(f'Hallucination rate so far: {rate:.1%}')

Quel est l’objectif principal du modèle du LLM comme vérificateur ?

Le modèle du LLM comme vérificateur est un modèle architectural essentiel pour prévenir les hallucinations. Il est indispensable de comprendre ce qu’il vérifie et pourquoi cette vérification est effectuée lors d’un appel distinct.

Récapitulatif de la prévention des hallucinations

Prévenez les hallucinations grâce aux éléments suivants : vérifications d’ancrage (chaque affirmation renvoie à une source), LLM comme vérificateur (un appel distinct évalue l’étayage), filtrage selon la confiance (exclusion des affirmations sous le seuil), détection de la dérive numérique, formulation nuancée pour les cas limites et suivi du taux d’hallucination pour détecter les régressions.

Questions Fréquemment Posées

La leçon « Vérification des faits et prévention des hallucinations » est-elle gratuite ?

Oui — le texte complet de « Vérification des faits et prévention des hallucinations » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Agents, passe à CoddyKit PRO. Le cours AI Agents comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Vérification des faits et prévention des hallucinations » ?

Vérification fondée sur l’ancrage : chaque affirmation doit être reliée à une source récupérée. Tu pratiques AI Agents avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer AI Agents ?

Aucune expérience préalable n'est requise. AI Agents sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « Vérification des faits et prévention des hallucinations » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon AI Agents ?

Oui. Chaque leçon AI Agents inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Conception d’une boucle de recherche en plusieurs étapes
  2. Vérification des sources et citations
  3. Génération de rapports structurés
  4. Vérification des faits et prévention des hallucinations
← Retour à AI Agents