llm-eval-ap / README.md
sha6th's picture
Initial deploy of LLM eval API
7d95632
|
Raw
History Blame Contribute Delete
5.3 kB
metadata
title: Llm Eval Ap
emoji: πŸƒ
colorFrom: blue
colorTo: pink
sdk: docker
pinned: false

Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference

LLM Evaluation & Hallucination Detection Framework

A multi-metric evaluation system that automatically detects hallucinations, measures faithfulness, relevance, and fluency in LLM-generated responses β€” built for QA pipelines in RAG and LLM-powered systems.

Problem

LLMs frequently generate fluent, confident, but factually incorrect responses ("hallucinations") with no built-in way to detect this. This is a critical risk in production systems β€” healthcare Q&A, legal summarization, customer support chatbots, RAG pipelines β€” where a wrong but confident answer can cause real harm.

This framework evaluates any (context, question, llm_response) triple and returns a verdict: Faithful, Hallucinated, Irrelevant, or Unverifiable β€” backed by 4 independent scoring methods.

Why 4 Metrics, Not 1

Each metric has a blind spot the others cover:

Metric Catches Misses
NLI (cross-encoder/nli-deberta-v3-small) Direct factual contradictions Whether the question was actually answered
BERTScore Overall semantic drift from context Subtle single-fact contradictions (high lexical overlap masks them)
Cosine Similarity (all-MiniLM-L6-v2) Whether response is relevant to the question Factual correctness
Fluency (rule-based) Grammatical/structural quality Meaning entirely

Example that demonstrates this in practice β€” tested live in this project:

Context:  "Virat Kohli won 2 IPL trophies as a player and 0 as captain."
Response: "Virat Kohli won 25 IPL trophies."

BERTScore: 0.89 β†’ "Highly Faithful"  ❌ (fooled by lexical overlap)
NLI:       contradiction (0.999)      βœ… (catches the numeric hallucination)

Final verdict: Hallucinated (correct)

This is the core finding the project is built around: no single metric is reliable alone.

Architecture

POST /evaluate { context, question, llm_response }
        β”‚
        β–Ό
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚   4 evaluators run in parallelβ”‚
 β”‚  Cosine | Fluency | BERTScore | NLI β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β–Ό
   Aggregator (rule-based verdict logic)
        β”‚
        β–Ό
   SQLite (persisted) ──► GET /history
        β”‚
        β–Ό
   Streamlit Dashboard (manual testing + history view)

Tech Stack

  • FastAPI β€” REST API (/evaluate, /history)
  • HuggingFace Transformers β€” NLI model (cross-encoder/nli-deberta-v3-small)
  • bert-score β€” semantic faithfulness scoring
  • sentence-transformers β€” cosine similarity (all-MiniLM-L6-v2)
  • SQLite β€” evaluation history storage
  • Streamlit β€” interactive dashboard

All models are CPU-friendly β€” no GPU required.

Setup

git clone <your-repo-url>
cd llm-eval-framework
python -m venv venv
venv\Scripts\activate        # Windows
pip install -r requirements.txt

Running

Start the API:

uvicorn main:app --reload

API docs: http://localhost:8000/docs

Start the dashboard (separate terminal):

streamlit run dashboard/app.py

Dashboard: http://localhost:8501

API

POST /evaluate

{
  "context": "Photosynthesis converts sunlight into glucose.",
  "question": "How do plants make food?",
  "llm_response": "Plants use moonlight to produce glucose."
}

Response:

{
  "final_verdict": "Hallucinated",
  "cosine": {"score": 0.52, "verdict": "Partially Relevant"},
  "fluency": {"issues": [], "verdict": "Fluent"},
  "bert_score": {"score": 0.91, "verdict": "Highly Faithful"},
  "nli": {"label": "contradiction", "score": 0.999, "verdict": "Hallucinated"}
}

GET /history

Returns all past evaluations with verdicts and timestamps.

Project Structure

llm-eval-framework/
β”œβ”€β”€ main.py                          # FastAPI app
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ aggregator.py                # Combines all 4 scores β†’ final verdict
β”‚   β”œβ”€β”€ database.py                  # SQLite persistence
β”‚   └── evaluators/
β”‚       β”œβ”€β”€ nli_evaluator.py
β”‚       β”œβ”€β”€ bert_score_evaluator.py
β”‚       β”œβ”€β”€ cosine_evaluator.py
β”‚       └── fluency_evaluator.py
β”œβ”€β”€ dashboard/
β”‚   └── app.py                       # Streamlit UI
β”œβ”€β”€ data/                            # SQLite DB
└── requirements.txt

Known Limitations

  • Verdict aggregation uses fixed thresholds (not learned/calibrated) β€” a clear next step would be calibrating thresholds against a labeled hallucination dataset.
  • Models are English-only; no language detection guard yet.
  • Evaluators run sequentially, not batched/async β€” fine for single requests, would need optimization for high-throughput production use.
  • No authentication on the API β€” would need to add this before any real external exposure.

Author

Sharath β€” built as a hands-on project to learn FastAPI, NLI, and LLM evaluation techniques from first principles.