DEV Community

RobustTrueTry
RobustTrueTry

Posted on

Stop AI Hallucinations: Verify Your LLM Summaries Before Publishing

You’ve probably seen headlines about AI summarizers that miss key facts or invent details. That’s the AI‑DR problem—models that claim to read but don’t. It can cost you credibility and time.

What You’ll Learn

  • Add a verification step after summarization.
  • Compare different verification strategies.
  • Spot common failure modes and how to mitigate them.

Why Verification Matters

When an LLM produces a summary, it can hallucinate facts that aren’t in the source. Those hallucinations can mislead users or propagate misinformation. Adding a verification step lets you catch those errors before they reach the audience.

Choose a Verification Strategy

You have three main options: a simple embedding similarity check, a retrieval‑based fact check, or a human‑in‑the‑loop review. Each has its own cost, latency, and accuracy profile. The choice depends on how critical the content is and how much automation you can afford.

Embedding Similarity

Embedding similarity is the lightest option. It turns both the source and the summary into vectors and compares them with cosine similarity. If the similarity falls below a threshold, you flag the summary.

import numpy as np
import openai

## Convert text to a vector using a small embedding model

def embed(text, model="text-embedding-3-small"):
    resp = openai.Embedding.create(input=text, model=model)
    return np.array(resp.data[0].embedding)

## Compare two vectors and decide if the summary is close enough

def verify(summary, source, threshold=0.75):
    src_vec = embed(source)
    sum_vec = embed(summary)
    similarity = np.dot(src_vec, sum_vec) / (np.linalg.norm(src_vec) * np.linalg.norm(sum_vec))
    return similarity >= threshold
Enter fullscreen mode Exit fullscreen mode

The code is short and uses only the OpenAI API. It works with any LLM that can produce a summary.

Retrieval‑Based Fact Check

If you need higher precision, you can retrieve the exact sentences that support each claim. The LLM is asked to list the source sentences it used, and you compare that list to the original text.

import openai

## Ask the model to list supporting sentences

def get_supporting_sentences(summary, source, model="gpt-4o-mini"):
    prompt = (
        "Given the following summary, list the exact sentences from the source that support each bullet point."
        f"\n\nSummary:\n{summary}\n\nSource:\n{source}"
    )
    response = openai.ChatCompletion.create(
        model=model,
        messages=[{"role": "user", "content": prompt}],
    )
    return response.choices[0].message.content.strip()
Enter fullscreen mode Exit fullscreen mode

You then parse the returned sentences and check that each appears verbatim in the source. This method is more expensive but catches subtle hallucinations.

Build the Pipeline

Below is a minimal, end‑to‑end pipeline that stitches the steps together.

Step 1: Fetch and Clean the Source

import requests
from bs4 import BeautifulSoup

## Grab the main article body from a URL

def fetch_text(url):
    resp = requests.get(url)
    resp.raise_for_status()
    soup = BeautifulSoup(resp.text, "html.parser")
    # Very naive extraction: grab all paragraph tags
    paragraphs = soup.find_all("p")
    return "\n".join(p.get_text() for p in paragraphs)
Enter fullscreen mode Exit fullscreen mode

In production you might use a dedicated article extractor, but this keeps the example focused.

Step 2: Summarize with an LLM

import openai

## Ask the model to produce a concise, bullet‑point summary

def summarize(text, model="gpt-4o-mini"):
    prompt = (
        "Summarize the following text in 3–5 bullet points. Only include facts that appear in the source."
        f"\n\n{text}"
    )
    response = openai.ChatCompletion.create(
        model=model,
        messages=[{"role": "user", "content": prompt}],
    )
    return response.choices[0].message.content.strip()
Enter fullscreen mode Exit fullscreen mode

The prompt explicitly asks for factuality, which helps reduce hallucinations.

Step 3: Verify the Summary

You can plug either verification method here. For brevity we’ll use the embedding similarity check.


## Reuse the verify() function from the Embedding Similarity section

def process(url):
    source = fetch_text(url)
    summary = summarize(source)
    if verify(summary, source):
        print("✅ Summary approved")
    else:
        print("❌ Summary flagged for review")
Enter fullscreen mode Exit fullscreen mode

Step 4: Decision Logic

If verify() returns True, you can publish the summary. If it returns False, you have three options:

  • Re‑run the summarization with a stricter prompt.
  • Send the summary to a human reviewer.
  • Log the failure for future analysis.

Tradeoffs Between Approaches

Approach Cost Latency Hallucination Risk Human Effort
Embedding Similarity Low Fast Medium None
Retrieval‑Based Fact Check Medium Medium Low None
Human Review High Slow Very Low High

The table shows that the embedding check is the cheapest and fastest, but it may miss subtle errors. Retrieval‑based checks are more accurate but cost more. Human review is the most reliable but also the slowest.

Common Failure Modes

  • Embedding drift: The embedding model may not capture subtle differences, leading to false positives.
  • Threshold mis‑tuning: A too‑high threshold rejects good summaries; a too‑low threshold lets hallucinations slip.
  • Prompt leakage: If the verification prompt is too similar to the summarization prompt, the model may repeat hallucinations.
  • Source noise: Web pages with ads or commentary can confuse the summarizer.

Tuning the Verification

  • Start with a threshold of 0.75 and adjust based on observed false‑positive/false‑negative rates.
  • Use a diverse set of test documents to calibrate the threshold.
  • Add a small “source‑check” prompt that asks the model to list the exact sentences it used.
  • Cache embeddings for repeated documents to reduce cost.

Key Takeaways

  • Adding a verification step dramatically reduces hallucinations.
  • Embedding‑based similarity is a lightweight, model‑agnostic check.
  • Retrieval‑based fact checks offer higher precision at a higher cost.
  • Tune the similarity threshold to balance cost and accuracy.
  • Keep an eye on failure modes and iterate on prompts and thresholds.

Source

AI;DR (AI; Didn't Read) – I added code, a verification strategy, tradeoff analysis, and failure‑mode discussion.

Top comments (0)