--- 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 ```bash git clone cd llm-eval-framework python -m venv venv venv\Scripts\activate # Windows pip install -r requirements.txt ``` ## Running **Start the API:** ```bash uvicorn main:app --reload ``` API docs: `http://localhost:8000/docs` **Start the dashboard** (separate terminal): ```bash streamlit run dashboard/app.py ``` Dashboard: `http://localhost:8501` ## API ### `POST /evaluate` ```json { "context": "Photosynthesis converts sunlight into glucose.", "question": "How do plants make food?", "llm_response": "Plants use moonlight to produce glucose." } ``` Response: ```json { "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.