doc-ingestion / rag-spec-evaluation.md
Vamshi Pokala
Redesigned the README and added Citiation and truthfullness in responses
ce71763
|
Raw
History Blame
6.04 kB
# RAG Spec Evaluation Report
## Context
This is a gap analysis of the Doc-Ingestion app against a production-grade RAG spec across three phases. The goal is to identify what is built, what partially meets the spec, and what is missing or misaligned.
---
## Spec vs. Implementation: Detailed Evaluation
### Phase 1 β€” Fundamentals
| Requirement | Status | Detail |
|---|---|---|
| Ingest documents | βœ… Built | PDF, DOCX, TXT, MD, HTML via `src/core/document_processor.py` |
| 500–800 **token** chunks | ⚠️ Partial / Misaligned | Chunking uses **characters** (default: 1000 chars, 200 overlap), not tokens. Spec requires token-based chunking (500–800 tokens). No tokenizer is applied during chunking. |
| 100-token overlap | ⚠️ Partial / Misaligned | Overlap is 200 characters, not 100 tokens. Same root issue: characters vs. tokens. |
| Vector store (Chroma or Qdrant) | βœ… Built | ChromaDB for dev (`data/embeddings/chroma`), Qdrant optional for prod. Both present in `src/utils/database.py`. |
**Gap to fix:**
- `src/core/document_processor.py` `chunk_text()` method uses character sliding window. Needs to be replaced with a tokenizer-aware splitter (e.g., `tiktoken` or `transformers` tokenizer) targeting 500–800 tokens with 100-token overlap.
- `config.yaml` `chunk_size: 1000` and `overlap: 200` need to change to token units.
---
### Phase 2 β€” Hybrid Retrieval + Re-ranking
| Requirement | Status | Detail |
|---|---|---|
| BM25 keyword search | βœ… Built | `src/core/bm25_search.py`, `BM25Search` using `rank-bm25` |
| Vector semantic search | βœ… Built | `src/core/vector_search.py`, `VectorSearch` with ChromaDB |
| Hybrid retrieval combining both | βœ… Built | `src/core/hybrid_retriever.py`, `HybridRetriever` with Reciprocal Rank Fusion (RRF), parallel execution |
| Cross-encoder re-ranker | βœ… Built | `src/core/reranker.py`, `CrossEncoderReranker` using `cross-encoder/ms-marco-MiniLM-L-6-v2` |
**Phase 2 is fully built and exceeds the spec** (adds RRF fusion, LRU caching, confidence scoring, configurable weights).
---
### Phase 3 β€” Evaluation Dataset + CI/CD
| Requirement | Status | Detail |
|---|---|---|
| Golden dataset of 50–200 Q&A pairs | ⚠️ Missing | Only `evals/datasets/smoke.jsonl` (~few entries, 1 KB) and `evals/datasets/sample.jsonl` (~6 KB, estimated ~10–15 pairs). Neither meets the 50–200 pair threshold. |
| Offline evaluation script | βœ… Built | `evals/run_evals.py` (504 lines) with 8+ metrics: answer_relevancy, context_precision, context_recall, ROUGE-L, citation_rate, faithfulness |
| CI/CD pipeline integration | ⚠️ Partial | `.github/workflows/ci.yml` has `evals-smoke` job, but it runs with `--mock` flag (MockPipeline). It does **not** measure real faithfulness β€” it tests the eval harness, not the RAG pipeline. |
| Measure faithfulness | ⚠️ Partial | NLI faithfulness via `src/evaluation/truthfulness.py` exists. RAGAS integration exists in `evals/adapters/ragas_llm_adapter.py` but is optional (requires `ragas>=0.2`, `langchain-core` extra deps) and not wired into CI. |
---
### Recommended Tech Stack Alignment
| Recommendation | Status | Detail |
|---|---|---|
| LangChain or LangGraph | ❌ Not used | Core pipeline uses direct HTTP API calls (`src/core/llm_provider.py`). LangChain only appears as a thin adapter in `evals/adapters/ragas_llm_adapter.py` to satisfy RAGAS interface β€” it is not the orchestration framework. |
| ChromaDB or Qdrant | βœ… Built | Both present |
| Ragas for evaluation | ⚠️ Optional / Incomplete | Present as optional adapter, not enforced. CI runs MockPipeline without RAGAS. |
---
## Summary: What Is Missing
### Must-Fix (spec violations)
1. **Token-based chunking** β€” `src/core/document_processor.py:chunk_text()` uses character counts, not tokens. Replace with tokenizer-aware chunking (e.g., `tiktoken`) targeting 500–800 tokens, 100-token overlap. Update `config.yaml` units accordingly.
2. **Golden evaluation dataset (50–200 pairs)** β€” `evals/datasets/` only has smoke (~few entries) and sample (~10–15 pairs). Need to create a curated dataset of at least 50 ground-truth Q&A pairs with reference contexts, authored against real ingested documents.
3. **CI/CD runs real faithfulness evaluation** β€” The `evals-smoke` GitHub Actions job uses `--mock`. A CI job that runs `LivePipeline` against the golden dataset (or a representative subset) and gates on a faithfulness threshold is required by the spec.
### Should-Fix (partial alignment)
4. **RAGAS made non-optional** β€” RAGAS faithfulness should be a hard dependency in `evals/`, not a conditional import behind `try/except`. The eval report should always include RAGAS faithfulness score.
5. **LangChain / LangGraph adoption** β€” The spec recommends LangChain/LangGraph as the orchestration layer. Currently the pipeline is custom HTTP. This is a tech stack deviation, not a functional gap β€” worth noting but lower priority than items 1–3.
---
## What Is Already Production-Grade (exceeds spec)
- Full hybrid retrieval with RRF fusion, parallel execution, and LRU caching
- Cross-encoder reranking with batch scoring and threshold filtering
- Multi-provider LLM routing (Ollama, OpenAI, Anthropic, Gemini) with streaming
- NLI-based inline truthfulness scoring in the serving path
- Citation tracking and verification
- Response caching (Redis + in-memory fallback)
- Rate limiting, API key auth, audit logging
- Comprehensive IR metrics module (P@K, R@K, MRR, MAP, NDCG)
- Unit + integration test coverage with CI
---
## Verification Steps (after fixes)
1. After token-based chunking: ingest a known document, query it, verify chunk boundaries fall within 500–800 token range using `tiktoken` inspection script.
2. After golden dataset: run `python -m evals.run_evals --dataset evals/datasets/golden.jsonl --live` and confirm dataset size β‰₯ 50.
3. After CI wiring: confirm GitHub Actions `evals-golden` job fails when faithfulness drops below threshold (e.g., `nli_faithfulness < 0.7`).