RS
RISHI SINGH
Back to All Projects
DOCUMENT AI · HYBRID SEARCH · RAGCompleted & VerifiedFAISS + BM25 RRF

DocMind AI

Hybrid RAG Document Intelligence Platform with Page-Level Lineage

An enterprise document synthesis engine engineered to overcome vector retrieval blind spots by combining FAISS dense cosine embeddings with BM25 sparse keyword matching via Reciprocal Rank Fusion, page-exact citation pills, and dual Groq/Ollama inference.

Retrieval Engine
Hybrid RRF
FAISS FlatIP + BM25Okapi
Citation Lineage
Page-Exact
Word-to-page tracking
Dual Inference
Cloud / Local
Groq Cloud + Ollama
Telemetry
p50 / p95 Stats
Pandas rolling analytics

01. Retrieval Failure Modes in Pure Vector Search

Dense vector embeddings map text chunks into semantic vector spaces. In academic and technical literature, however, relying solely on dense similarity introduces critical retrieval failures:

Rare Term & Identifier Blindness

Technical part numbers, acronyms, and formulas (e.g. “LOINC 1558-6” or “Liljegren WBGT”) get projected near generic concepts, missing exact lexical matches.

Untraceable Hallucinated Citations

Standard chunking drops page boundaries, leaving users unable to verify whether an AI claim came from page 4 or page 40 of a 100-page document.

02. Reciprocal Rank Fusion Architecture

DocMind AI builds two parallel indices upon document ingestion:

  • ▸Dense Index: 384-dimensional normalized vectors via sentence-transformers/all-MiniLM-L6-v2 indexed in faiss.IndexFlatIP.
  • ▸Sparse Index: Tokenized inverse index in BM25Okapi for exact keyword and identifier matches.
Reciprocal Rank Fusion Implementation (backend.py)
# RRF Score = ∑ 1 / (k + rank_i) where k = 60
def reciprocal_rank_fusion(dense_results, sparse_results, k=60):
    scores = {}
    chunk_map = {}
    for rank, item in enumerate(dense_results, start=1):
        cid = item["chunk_id"]
        chunk_map[cid] = item
        scores[cid] = scores.get(cid, 0.0) + (1.0 / (k + rank))
        
    for rank, item in enumerate(sparse_results, start=1):
        cid = item["chunk_id"]
        chunk_map[cid] = item
        scores[cid] = scores.get(cid, 0.0) + (1.0 / (k + rank))
        
    sorted_chunks = sorted(scores.items(), key=lambda x: x[1], reverse=True)
    return [{**chunk_map[cid], "rrf_score": s} for cid, s in sorted_chunks]

03. Word-to-Page Coordinate Lineage

Rather than splitting raw strings naively, DocMind AI streams words accompanied by their parent PDF page number. As sliding windows advance, each chunk records all pages it spans:

Citation Flow:
PDF Page 12 ──► Chunk #42 [pages: [12]] ──► Context: “[Page 12]: Text...” ──► Output: “... [Source: Page 12]”

The frontend translates these tags into clickable citation pills that display chunk confidence scores and text snippets on hover.

04. Dual Cloud & Local LLM Backends

Users can toggle seamlessly between two execution backends at runtime:

1. Groq Cloud (llama-3.1-8b)

High-speed cloud inference reaching ~500 tokens/sec, ideal for rapid research workflows with negligible latency.

2. Local Ollama (mistral)

100% offline, privacy-preserving inference executing against a local Ollama instance with zero data transmitted externally.

05. Telemetry & Multi-Tier Visual Search

Every request logs latency across embedding, retrieval, and LLM inference to a thread-safe queue. The /metrics/{session_id} endpoint uses Pandas to compute p50, p95, and mean execution stats.

Furthermore, when technical topics are detected, a 3-tier visual fallback hierarchy (Local SVG diagrams → Wikipedia REST API → Wikimedia Commons → Unsplash) retrieves relevant architectural diagrams alongside generated answers.