Claim-Level LLM Hallucination Detection & Evaluation Framework
A research prototype for detecting hallucinations at the individual claim level using adaptive cascading verification.
Whole-answer hallucination detection treats a response as a single unit β either hallucinated or not. This is insufficient: an LLM answer may be mostly factual with a single fabricated detail, and binary detection misses this.
HalluciGuard verifies each extracted atomic claim independently against retrieved evidence, providing fine-grained hallucination analysis.
Example:
Question: "Who founded Tesla?"
Answer: "Tesla was founded in 2003 by Elon Musk. Martin Eberhard served as early CEO."
| Claim | Status |
|---|---|
| Tesla was founded in 2003 | β Supported |
| Elon Musk founded Tesla | β Unsupported |
| Martin Eberhard served as early CEO | β Supported |
graph TD
A[Question] --> B[LLM Answer Generation\nOllama]
B --> C[Claim Extraction\nLLM-based]
C --> D[Evidence Retrieval\nFAISS + Embeddings]
D --> E{Adaptive Verification}
E -->|High embedding sim| F[β
Supported]
E -->|Uncertain| G[NLI Verifier\nDeBERTa]
G -->|High confidence| H[Final Result]
G -->|Uncertain| I[LLM Judge\nOllama]
I --> J[Final Result]
F --> K[Report + Metrics]
H --> K
J --> K
K --> L[Streamlit Dashboard]
K --> M[MLflow Tracking]
| Method | Description | Speed | Accuracy |
|---|---|---|---|
| Embedding | Cosine similarity between claim and evidence | β‘ Fast | Baseline |
| NLI | DeBERTa entailment classification | β Medium | Better |
| LLM Judge | Ollama LLM evaluates claim vs evidence | π’ Slow | Best |
| Adaptive (proposed) | Cascades: Embedding β NLI β LLM (only when needed) | β Efficient | Competitive |
A cascading verification architecture can reduce expensive LLM calls while maintaining competitive claim-level hallucination detection performance.
HalluciGuard/
βββ backend/
β βββ main.py # FastAPI app
β βββ config.py # Centralized config (pydantic-settings)
β βββ api/routes.py # REST endpoints
β βββ services/
β β βββ answer_generator.py # Ollama LLM
β β βββ claim_extractor.py # LLM claim extraction
β β βββ retriever.py # FAISS evidence retrieval
β β βββ similarity_verifier.py # Embedding baseline
β β βββ nli_verifier.py # NLI baseline
β β βββ llm_verifier.py # LLM judge baseline
β β βββ adaptive_verifier.py # Proposed method
β β βββ report_generator.py # Metrics & report
β βββ models/schemas.py # Pydantic schemas
β βββ utils/logging_config.py
β
βββ frontend/app.py # Streamlit dashboard
β
βββ data/
β βββ documents/ # Evidence corpus (.txt files)
β βββ evaluation/benchmark.json # Ground-truth labeled claims
β
βββ experiments/
β βββ run_experiment.py # CLI runner with MLflow
β βββ baseline_embedding.py
β βββ baseline_nli.py
β βββ baseline_llm.py
β βββ adaptive_halluciguard.py
β
βββ evaluation/
β βββ metrics.py # Accuracy, F1, hallucination rate
β βββ evaluator.py # Run one method against benchmark
β βββ benchmark.py # Compare all 4 methods
β
βββ tests/ # pytest unit tests
βββ results/ # Generated experiment CSVs
βββ mlruns/ # MLflow experiment data
βββ requirements.txt
βββ .env.example
βββ run.py
python -m venv venv
Windows:
venv\Scripts\activate
Linux/Mac:
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
Edit .env as needed. Key settings:
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=qwen2.5:7b
EMBEDDING_MODEL=BAAI/bge-small-en-v1.5
TOP_K=5
Install Ollama: https://ollama.com/download
Start Ollama:
ollama serve
Pull the model:
ollama pull qwen2.5:7b
Verify:
ollama list
Any Ollama-compatible model works. Change
OLLAMA_MODELin.env.
uvicorn backend.main:app --reload --port 8000
Test health:
curl http://localhost:8000/health
In a separate terminal:
streamlit run frontend/app.py
Open: http://localhost:8501
# Single method
python experiments/run_experiment.py --method adaptive
python experiments/run_experiment.py --method embedding
python experiments/run_experiment.py --method nli
python experiments/run_experiment.py --method llm
# All methods (full comparison)
python experiments/run_experiment.py --method all
Results are saved to results/ as CSV files.
mlflow ui --port 5000
Open: http://localhost:5000
Each experiment run logs:
| Endpoint | Method | Description |
|---|---|---|
/health | GET | Backend status check |
/analyze | POST | Full pipeline analysis |
/retrieve | POST | Evidence retrieval for a query |
/verify-claim | POST | Verify a single claim against evidence |
/analyze request:curl -X POST http://localhost:8000/analyze \
-H "Content-Type: application/json" \
-d '{"question": "Who founded Tesla?", "verification_method": "adaptive"}'
pytest tests/ -v
Tests cover:
| Variable | Default | Description |
|---|---|---|
OLLAMA_MODEL | qwen2.5:7b | Ollama model name |
OLLAMA_BASE_URL | http://localhost:11434 | Ollama API URL |
EMBEDDING_MODEL | BAAI/bge-small-en-v1.5 | Sentence transformer model |
TOP_K | 5 | Evidence chunks to retrieve |
SIMILARITY_THRESHOLD | 0.70 | Embedding verification threshold |
HIGH_SIMILARITY_THRESHOLD | 0.85 | Adaptive: skip NLI if above this |
LOW_SIMILARITY_THRESHOLD | 0.40 | Adaptive: force NLI if below this |
NLI_CONFIDENCE_THRESHOLD | 0.80 | Adaptive: call LLM if NLI below this |
NLI_MODEL | cross-encoder/nli-deberta-v3-small | HuggingFace NLI model |
BACKEND_URL | http://localhost:8000 | Streamlit β Backend URL |
MLFLOW_TRACKING_URI | ./mlruns | MLflow tracking location |
Place .txt files in data/documents/. The system will:
Delete data/faiss_index/ to force a rebuild.
data/evaluation/benchmark.json for robust researchBuilt as a research internship project exploring claim-level hallucination detection using adaptive verification strategies.
Claim-Level LLM Hallucination Detection & Evaluation Framework
A research prototype for detecting hallucinations at the individual claim level using adaptive cascading verification.
Whole-answer hallucination detection treats a response as a single unit β either hallucinated or not. This is insufficient: an LLM answer may be mostly factual with a single fabricated detail, and binary detection misses this.
HalluciGuard verifies each extracted atomic claim independently against retrieved evidence, providing fine-grained hallucination analysis.
Example:
Question: "Who founded Tesla?"
Answer: "Tesla was founded in 2003 by Elon Musk. Martin Eberhard served as early CEO."
| Claim | Status |
|---|---|
| Tesla was founded in 2003 | β Supported |
| Elon Musk founded Tesla | β Unsupported |
| Martin Eberhard served as early CEO | β Supported |
graph TD
A[Question] --> B[LLM Answer Generation\nOllama]
B --> C[Claim Extraction\nLLM-based]
C --> D[Evidence Retrieval\nFAISS + Embeddings]
D --> E{Adaptive Verification}
E -->|High embedding sim| F[β
Supported]
E -->|Uncertain| G[NLI Verifier\nDeBERTa]
G -->|High confidence| H[Final Result]
G -->|Uncertain| I[LLM Judge\nOllama]
I --> J[Final Result]
F --> K[Report + Metrics]
H --> K
J --> K
K --> L[Streamlit Dashboard]
K --> M[MLflow Tracking]
| Method | Description | Speed | Accuracy |
|---|---|---|---|
| Embedding | Cosine similarity between claim and evidence | β‘ Fast | Baseline |
| NLI | DeBERTa entailment classification | β Medium | Better |
| LLM Judge | Ollama LLM evaluates claim vs evidence | π’ Slow | Best |
| Adaptive (proposed) | Cascades: Embedding β NLI β LLM (only when needed) | β Efficient | Competitive |
A cascading verification architecture can reduce expensive LLM calls while maintaining competitive claim-level hallucination detection performance.
HalluciGuard/
βββ backend/
β βββ main.py # FastAPI app
β βββ config.py # Centralized config (pydantic-settings)
β βββ api/routes.py # REST endpoints
β βββ services/
β β βββ answer_generator.py # Ollama LLM
β β βββ claim_extractor.py # LLM claim extraction
β β βββ retriever.py # FAISS evidence retrieval
β β βββ similarity_verifier.py # Embedding baseline
β β βββ nli_verifier.py # NLI baseline
β β βββ llm_verifier.py # LLM judge baseline
β β βββ adaptive_verifier.py # Proposed method
β β βββ report_generator.py # Metrics & report
β βββ models/schemas.py # Pydantic schemas
β βββ utils/logging_config.py
β
βββ frontend/app.py # Streamlit dashboard
β
βββ data/
β βββ documents/ # Evidence corpus (.txt files)
β βββ evaluation/benchmark.json # Ground-truth labeled claims
β
βββ experiments/
β βββ run_experiment.py # CLI runner with MLflow
β βββ baseline_embedding.py
β βββ baseline_nli.py
β βββ baseline_llm.py
β βββ adaptive_halluciguard.py
β
βββ evaluation/
β βββ metrics.py # Accuracy, F1, hallucination rate
β βββ evaluator.py # Run one method against benchmark
β βββ benchmark.py # Compare all 4 methods
β
βββ tests/ # pytest unit tests
βββ results/ # Generated experiment CSVs
βββ mlruns/ # MLflow experiment data
βββ requirements.txt
βββ .env.example
βββ run.py
python -m venv venv
Windows:
venv\Scripts\activate
Linux/Mac:
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
Edit .env as needed. Key settings:
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=qwen2.5:7b
EMBEDDING_MODEL=BAAI/bge-small-en-v1.5
TOP_K=5
Install Ollama: https://ollama.com/download
Start Ollama:
ollama serve
Pull the model:
ollama pull qwen2.5:7b
Verify:
ollama list
Any Ollama-compatible model works. Change
OLLAMA_MODELin.env.
uvicorn backend.main:app --reload --port 8000
Test health:
curl http://localhost:8000/health
In a separate terminal:
streamlit run frontend/app.py
Open: http://localhost:8501
# Single method
python experiments/run_experiment.py --method adaptive
python experiments/run_experiment.py --method embedding
python experiments/run_experiment.py --method nli
python experiments/run_experiment.py --method llm
# All methods (full comparison)
python experiments/run_experiment.py --method all
Results are saved to results/ as CSV files.
mlflow ui --port 5000
Open: http://localhost:5000
Each experiment run logs:
| Endpoint | Method | Description |
|---|---|---|
/health | GET | Backend status check |
/analyze | POST | Full pipeline analysis |
/retrieve | POST | Evidence retrieval for a query |
/verify-claim | POST | Verify a single claim against evidence |
/analyze request:curl -X POST http://localhost:8000/analyze \
-H "Content-Type: application/json" \
-d '{"question": "Who founded Tesla?", "verification_method": "adaptive"}'
pytest tests/ -v
Tests cover:
| Variable | Default | Description |
|---|---|---|
OLLAMA_MODEL | qwen2.5:7b | Ollama model name |
OLLAMA_BASE_URL | http://localhost:11434 | Ollama API URL |
EMBEDDING_MODEL | BAAI/bge-small-en-v1.5 | Sentence transformer model |
TOP_K | 5 | Evidence chunks to retrieve |
SIMILARITY_THRESHOLD | 0.70 | Embedding verification threshold |
HIGH_SIMILARITY_THRESHOLD | 0.85 | Adaptive: skip NLI if above this |
LOW_SIMILARITY_THRESHOLD | 0.40 | Adaptive: force NLI if below this |
NLI_CONFIDENCE_THRESHOLD | 0.80 | Adaptive: call LLM if NLI below this |
NLI_MODEL | cross-encoder/nli-deberta-v3-small | HuggingFace NLI model |
BACKEND_URL | http://localhost:8000 | Streamlit β Backend URL |
MLFLOW_TRACKING_URI | ./mlruns | MLflow tracking location |
Place .txt files in data/documents/. The system will:
Delete data/faiss_index/ to force a rebuild.
data/evaluation/benchmark.json for robust researchBuilt as a research internship project exploring claim-level hallucination detection using adaptive verification strategies.