A fully grounded Retrieval-Augmented Generation (RAG) pipeline for the INDECIMAL home construction marketplace, with a deployed chatbot interface.
Open indecimal_rag_chatbot.html in any browser — no server required. The frontend uses the Anthropic API directly via JavaScript.
For the Python backend: run python/rag_pipeline.py (requires dependencies below).
User Query
│
▼
[1] Chunk Documents ──► 6 sections → ~30 overlapping chunks
│
▼
[2] Embed Query ──► TF-IDF vector (frontend JS) / all-MiniLM-L6-v2 (Python)
│
▼
[3] Cosine Similarity / FAISS Search ──► Top-k most relevant chunks
│
▼
[4] Prompt Claude with ONLY retrieved context
│
▼
[5] Grounded Answer + Displayed retrieved chunks (transparency)
- Method: TF-IDF + Cosine Similarity (in-browser, zero latency, zero API cost)
- Why: No server needed; works fully client-side; fast enough for small corpora (<50 chunks); perfectly interpretable scores.
- Model:
sentence-transformers/all-MiniLM-L6-v2(22M params, ~80MB) - Why chosen:
- Free, open-source, runs locally (no API key)
- Excellent performance on semantic similarity benchmarks
- Fast inference (<100ms per query on CPU)
- 384-dimensional embeddings, manageable memory footprint
- Model:
claude-sonnet-4-20250514(via Anthropic API) - Why chosen:
- Strong instruction-following; respects strict "answer only from context" constraints
- Excellent at structured output for pricing/spec data
- Low hallucination rate on grounded prompts
- Grounding mechanism: System prompt explicitly forbids using external knowledge; context is injected directly into the user message with section labels
- Chunk size: ~120 words (frontend JS) / ~300 words (Python)
- Overlap: ~25 words (JS) / ~50 words (Python)
- Why overlap? Prevents information from being split at chunk boundaries; a fact spanning two windows is captured in at least one chunk.
- Section-aware: Each chunk carries its source section label (e.g.,
packages,flooring) for display and debugging.
| Section | Content |
|---|---|
packages |
Pricing per sqft, steel, cement, block work, RCC, ceiling height |
kitchen_bathroom |
Wall dado, sinks, faucets, sanitary fittings, CPVC pipes |
doors_windows_painting |
Main door wallets, window specs, interior & exterior paint |
flooring |
Living/dining and room flooring wallets per sqft |
quality_payments |
Escrow model, 445+ checkpoints, delay policy, maintenance |
company_journey |
Company overview, 10-stage customer journey, financing |
- Algorithm: TF-IDF cosine similarity (pure JS, no dependencies)
- Index: In-memory Float32Array per chunk
- Query time: <5ms for 30 chunks
- Index: FAISS
IndexFlatIP(inner product on L2-normalized vectors = cosine similarity) - Why FAISS? Industry standard, highly optimized, works locally, scales to millions of vectors
- Top-k: Configurable (default k=3)
The LLM is constrained via a strict system prompt:
STRICT RULES:
1. Answer ONLY using the provided context below. Do NOT use external knowledge.
2. If the context does not contain enough information, say so clearly.
3. Quote specific numbers, brand names, and allowances from the context when relevant.
4. Keep answers concise, structured, and easy to read.
5. Do NOT speculate or invent any figures or policies.
Context is passed as labeled sections:
[Section: packages]
...chunk text...
---
[Section: kitchen_bathroom]
...chunk text...
Every response in the UI shows:
- Retrieved chunks panel (collapsible): shows section name + similarity score + full chunk text
- Final generated answer: clearly separated from the context display
- k selector: user controls how many chunks are retrieved
open indecimal_rag_chatbot.html
# or double-click the file in your file explorerThe chatbot calls the Anthropic API via
fetch. You'll need a valid API key injected if running outside Claude.ai.
pip install anthropic sentence-transformers faiss-cpu numpycd python
python rag_pipeline.py
# Outputs eval_results.json with 8 test Q&A pairs| # | Question | Chunk Relevance | Hallucination Risk | Answer Quality |
|---|---|---|---|---|
| 1 | What is the price of the Premier package? | ✅ High | ✅ None | ✅ Exact figure cited |
| 2 | Which steel brand is used in Pinnacle? | ✅ High | ✅ None | ✅ TATA quoted correctly |
| 3 | What flooring options for Infinia living room? | ✅ High | ✅ None | ✅ tiles/granite/marble + ₹140 wallet |
| 4 | How does Indecimal ensure quality? | ✅ High | ✅ None | ✅ 445 checkpoints, escrow, dashboard |
| 5 | Main door wallet for Essential? | ✅ High | ✅ None | ✅ ₹20,000 panelled door cited |
| 6 | How are contractor payments handled? | ✅ High | ✅ None | ✅ Escrow model explained |
| 7 | What exterior paint brand for Pinnacle? | ✅ High | ✅ None | ✅ Asian Paints Apex Ultima |
| 8 | What sanitary fittings in Infinia? | ✅ High | ✅ None | ✅ ₹70,000 Jaquar/Essco cited |
- Retrieval is highly accurate for direct lookup queries (pricing, brands, specs)
- Grounding is strong: the model consistently cites exact figures from context
- No hallucinations observed in test set — system prompt enforcement works well
- Limitation: TF-IDF (frontend) may miss semantic paraphrases; sentence-transformers handles these better
- Out-of-scope handling: when asked about topics not in the documents (e.g. "what is the weather in Bangalore"), the model correctly says it cannot find the information in the provided context
- ✅ Local embedding model:
all-MiniLM-L6-v2in Python (vs TF-IDF in frontend) - ✅ FAISS index: production-grade vector search in Python backend
- ✅ Quality analysis: 8 test questions evaluated above
- ✅ Transparency UI: retrieved chunks with scores always visible
- ✅ Configurable top-k: user can tune retrieval depth in the UI
indecimal-rag/
├── README.md
├── indecimal_rag_chatbot.html # Deployed chatbot (open in browser)
└── python/
└── rag_pipeline.py # Full Python RAG pipeline
| Component | Technology |
|---|---|
| Embedding (frontend) | TF-IDF + cosine similarity (JavaScript) |
| Embedding (backend) | sentence-transformers/all-MiniLM-L6-v2 |
| Vector store (backend) | FAISS IndexFlatIP |
| LLM | Claude Sonnet 4 (Anthropic API) |
| Frontend | Vanilla HTML/CSS/JS |
| Backend | Python 3.10+ |