Spaces:
Sleeping
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.pychunk_text()method uses character sliding window. Needs to be replaced with a tokenizer-aware splitter (e.g.,tiktokenortransformerstokenizer) targeting 500β800 tokens with 100-token overlap.config.yamlchunk_size: 1000andoverlap: 200need 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 (evals/datasets/sample.jsonl ( |
| 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)
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. Updateconfig.yamlunits accordingly.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.CI/CD runs real faithfulness evaluation β The
evals-smokeGitHub Actions job uses--mock. A CI job that runsLivePipelineagainst the golden dataset (or a representative subset) and gates on a faithfulness threshold is required by the spec.
Should-Fix (partial alignment)
RAGAS made non-optional β RAGAS faithfulness should be a hard dependency in
evals/, not a conditional import behindtry/except. The eval report should always include RAGAS faithfulness score.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)
- After token-based chunking: ingest a known document, query it, verify chunk boundaries fall within 500β800 token range using
tiktokeninspection script. - After golden dataset: run
python -m evals.run_evals --dataset evals/datasets/golden.jsonl --liveand confirm dataset size β₯ 50. - After CI wiring: confirm GitHub Actions
evals-goldenjob fails when faithfulness drops below threshold (e.g.,nli_faithfulness < 0.7).