Verifica dei fatti e prevenzione delle allucinazioni
Verifica basata sul grounding: ogni affermazione deve poter essere ricondotta a una fonte recuperata.
Verifica dei fatti e prevenzione delle allucinazioni è una lezione AI Agents gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento AI Agents, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso AI Agents include 4 lezioni in totale.
Il problema delle allucinazioni negli agenti di ricerca
Gli LLM possono generare affermazioni plausibili ma prive di fondamento nelle fonti recuperate. In un agente di ricerca, questo è particolarmente pericoloso perché l'output appare autorevole e viene presentato con citazioni che potrebbero in realtà non supportare l'affermazione.
La prevenzione delle allucinazioni deve essere una priorità fondamentale.
Grounding: ogni asserzione è riconducibile a una fonte
Il principio fondamentale del grounding è il seguente: ogni asserzione fattuale nell'output finale deve essere riconducibile ad almeno un documento recuperato. Le asserzioni che non possono essere ricondotte a una fonte sono allucinazioni oppure non supportate da prove: entrambe le situazioni sono inaccettabili in un report di ricerca.
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'])
Pattern LLM come verificatore
Utilizzi una chiamata separata a un LLM, il «verificatore», per stabilire se un'asserzione è supportata dalle fonti fornite. In questo modo si crea un sistema di controllo e bilanciamento in cui il generatore e il verificatore sono chiamate indipendenti.
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)Output soggetto a soglie di confidenza
Imposti delle soglie sul punteggio di confidenza del verificatore. Le asserzioni superiori a 0.85 vengono pubblicate. Quelle comprese tra 0.5 e 0.85 vengono pubblicate con una limitazione di responsabilità. Quelle inferiori a 0.5 vengono escluse.
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}Individuare specifici schemi di allucinazione
Alcuni schemi di asserzione presentano un rischio elevato di allucinazione: statistiche esatte (percentuali, importi in denaro), date specifiche, persone nominate e relazioni causali. Li sottoponga a un controllo aggiuntivo.
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')) # FalseIl ciclo di verifica scomposto
Per le sezioni lunghe, scomponga il testo in singole asserzioni, verifichi ogni asserzione in modo indipendente, quindi ricostruisca la sezione utilizzando solo le asserzioni verificate.
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', [])Ricostruire il testo verificato
Dopo aver applicato una soglia a ogni asserzione, ricostruisca una sezione coerente e ordinata utilizzando solo le asserzioni verificate. Escluda quelle con bassa confidenza e riscriva il testo per migliorarne la leggibilità.
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.contentRilevare le variazioni numeriche
A volte gli LLM alterano impercettibilmente i numeri della fonte, ad esempio trasformando 9.1% in 9.2%. Estragga i numeri sia dall'asserzione sia dal testo della fonte e li confronti esplicitamente.
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.1Verifica delle attribuzioni
Dopo aver generato un report completo, esegua una verifica delle attribuzioni: per ogni frase del report, confermi che possa essere attribuita a una delle fonti. Contrassegni le frasi per le quali non esiste alcun estratto corrispondente nella fonte.
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)
Usare formulazioni caute per le asserzioni incerte
Non tutto può essere verificato con un alto livello di confidenza. Invece di escludere completamente le asserzioni al limite, utilizzi formulazioni caute, come «Alcuni analisti suggeriscono...», «Secondo X...» e «È stato riferito che...». In questo modo conserva le informazioni e segnala al contempo l'incertezza.
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))Monitorare il tasso di allucinazione
Monitori nel tempo il tasso di allucinazione: quale percentuale delle asserzioni generate non supera la verifica? Imposti una soglia di avviso. Se il tasso aumenta improvvisamente, la qualità del prompt engineering o del recupero delle informazioni è peggiorata.
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%}')
Qual è lo scopo principale del pattern «LLM-as-verifier»?
LLM-as-verifier è un pattern architetturale fondamentale per prevenire le allucinazioni. È essenziale comprendere che cosa verifica e perché questa operazione viene eseguita tramite una chiamata separata.
Riepilogo della prevenzione delle allucinazioni
Prevenga le allucinazioni tramite: controlli di grounding (ogni asserzione è riconducibile a una fonte), LLM-as-verifier (una chiamata separata valuta il supporto fornito), soglie di confidenza (escludono le asserzioni al di sotto della soglia), rilevamento delle variazioni numeriche, formulazioni caute per i casi al limite e monitoraggio del tasso di allucinazione per rilevare le regressioni.
Domande Frequenti
La lezione «Verifica dei fatti e prevenzione delle allucinazioni» è gratuita?
Sì — il testo completo di «Verifica dei fatti e prevenzione delle allucinazioni» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso AI Agents, passa a CoddyKit PRO. Il corso AI Agents include 4 lezioni in totale.
Cosa imparerò in «Verifica dei fatti e prevenzione delle allucinazioni»?
Verifica basata sul grounding: ogni affermazione deve poter essere ricondotta a una fonte recuperata. Eserciti AI Agents con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare AI Agents?
Non è richiesta alcuna esperienza precedente. AI Agents su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Verifica dei fatti e prevenzione delle allucinazioni»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione AI Agents?
Sì. Ogni lezione AI Agents include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Progettazione di cicli di ricerca multi-passaggio
- Verifica delle fonti e citazioni
- Generazione di report strutturati
- Verifica dei fatti e prevenzione delle allucinazioni