Spaces:
Running
Running
| # Cortex RAG β Architecture & Implementation Guide | |
| This document provides a deep dive into the architecture of **Cortex**, a production-grade Retrieval-Augmented Generation (RAG) system. This guide is structured to help you explain the "what", "how", and "why" of each layer during your GenAI Engineer interview. | |
| --- | |
| ## ποΈ 1. High-Level Architecture Overview | |
| Cortex follows a modular, multi-layer RAG architecture designed for high precision, scalability, and reliability. It moves beyond "naive RAG" by implementing: | |
| - **Semantic Data Ingestion** (instead of fixed-size chunking) | |
| - **Hybrid Multi-Strategy Retrieval** (Dense + Sparse + Knowledge Graph) | |
| - **Corrective Gating (CRAG)** (to handle retrieval failures) | |
| - **Reference-Free Evaluation** (using RAGAS) | |
| --- | |
| ## π₯ 2. Ingestion Layer: "Context-Aware Processing" | |
| ### **Document Loading** | |
| - Supports multiple formats: PDF, HTML, and TXT. | |
| - **Implementation:** `DocumentLoader` handles parsing and basic cleaning. | |
| ### **Semantic Chunker (`ingestion/chunker.py`)** | |
| - **The Problem:** Fixed-size chunking (e.g., 512 tokens) often splits mid-sentence or mid-concept, losing semantic coherence. | |
| - **The Solution:** We use **Sentence-Level Semantic Boundary Detection**. | |
| - **How it works:** | |
| 1. Split text into individual sentences. | |
| 2. Embed each sentence using `BAAI/bge-small-en-v1.5`. | |
| 3. Compute the **cosine similarity** between consecutive sentence embeddings. | |
| 4. Insert a chunk boundary whenever the similarity drops below a certain threshold (e.g., 0.82) or the token limit is reached. | |
| - **Why?** This ensures each chunk contains a single, coherent topic. | |
| ### **Parent-Child Hierarchy** | |
| - **The Problem:** Small chunks are better for retrieval precision, but large chunks provide better context for generation. | |
| - **The Implementation:** | |
| - **Child Chunks (~256 tokens):** These are the units indexed in the vector database. They represent a specific "nugget" of information. | |
| - **Parent Chunks (~1024 tokens):** A wider window of text centered on the child. When a child is retrieved, its **parent text** is what gets sent to the LLM. | |
| - **Why?** It decouples **retrieval granularity** (find exactly what you need) from **context width** (give the LLM enough room to understand). | |
| --- | |
| ## π 3. Retrieval Layer: "Multi-Strategy Orchestration" | |
| Cortex doesn't just rely on vector search; it uses a `MultiStrategyRetriever` to combine different search paradigms. | |
| ### **A. Dense Retrieval (Milvus)** | |
| - **Embeddings:** `bge-small-en-v1.5` (384-dim). | |
| - **Vector DB:** Milvus (Dockerized). | |
| - **Indexing:** `IVF_FLAT` with `COSINE` similarity metric. | |
| - **Why?** Captures semantic meaning (e.g., "puppy" matches "dog"). | |
| ### **B. Sparse Retrieval (BM25)** | |
| - **Implementation:** `rank_bm25` library. | |
| - **Why?** Essential for exact keyword matching, acronyms, and specific names (e.g., "Project Cortex-X1") where vector search might be too "fuzzy". | |
| ### **C. Knowledge Graph (GraphRAG)** | |
| - **Extraction:** During ingestion, we use **spaCy** for Named Entity Recognition (NER) and **REBEL** (or LLM) for relation extraction. | |
| - **Storage:** A NetworkX graph storing triples: `(Subject) --[Predicate]--> (Object)`. | |
| - **Retrieval:** | |
| 1. Extract entities from the user query. | |
| 2. Traverse the graph to find related nodes (multi-hop traversal). | |
| 3. Retrieve the chunks associated with those nodes. | |
| - **Why?** Solves "multi-hop" queries where the answer requires connecting disparate pieces of information across the document. | |
| ### **D. Fusion & Reranking (`retrieval/fusion.py`)** | |
| - **RRF (Reciprocal Rank Fusion):** Combines the ranked lists from Milvus, BM25, and the Graph into one unified list. | |
| - **Cross-Encoder Reranker:** We take the top-15 fused candidates and run them through a Cross-Encoder (e.g., `BAAI/bge-reranker-base`). | |
| - **Why?** Cross-encoders are much more accurate (but slower) than vector search because they look at the query and chunk simultaneously. Using them as a final "filter" boosts precision significantly. | |
| --- | |
| ## π§ 4. Generation Layer: "Corrective RAG (CRAG)" | |
| The `CRAGGate` (`generation/crag.py`) acts as a "quality control" layer between retrieval and the LLM. | |
| ### **The CRAG Workflow** | |
| 1. **Grading:** An LLM-as-judge assesses if the retrieved chunks are relevant to the query. | |
| 2. **Action Categories:** | |
| - **GOOD:** Chunks are relevant. Proceed to generation. | |
| - **POOR:** Chunks are partially relevant. **Rewrite the query** (using CoT) and re-retrieve to find better results. | |
| - **ABSENT:** Knowledge base doesn't have the answer. **Fallback to Web Search** (Tavily/DuckDuckGo). | |
| 3. **LLM Generation:** Uses Groq (Llama 3), OpenAI, or NVIDIA NIM to generate the final answer with **inline citations** (e.g., "The sky is blue [1]."). | |
| --- | |
| ## π 5. Evaluation Layer: "Reference-Free Metrics" | |
| Since production RAG systems often lack "ground truth" answers, we use the **RAGAS** framework (`evaluation/ragas_eval.py`). | |
| ### **Key Metrics** | |
| - **Faithfulness:** Does the answer stay true to the retrieved context? (Prevents hallucinations). | |
| - **Answer Relevancy:** Does the answer actually address the user's question? | |
| - **Context Precision:** Were the retrieved chunks actually useful? | |
| - **Context Utilisation:** What % of retrieved chunks were actually cited? | |
| ### **Implementation** | |
| - Evaluations run **asynchronously** in background threads so they don't slow down the user's response time. | |
| - Results are stored in a local SQLite DB for monitoring. | |
| --- | |
| ## π οΈ 6. System & Infrastructure | |
| - **API:** FastAPI for high-performance, asynchronous endpoints. | |
| - **UI:** Streamlit for a clean, interactive dashboard (Ask, Ingest, Monitor). | |
| - **Cache:** Redis for caching query results (TTL-based) to save LLM costs and latency. | |
| - **Deployment:** Full **Docker Compose** setup for Milvus, Redis, API, and UI. | |
| --- | |
| ## π‘ Interview Tip: "Why this architecture?" | |
| If asked why you built it this way, emphasize these three points: | |
| 1. **Precision:** By using **Semantic Chunking** and **Cross-Encoder Reranking**, we ensure only the most relevant context reaches the LLM. | |
| 2. **Reliability:** **CRAG** ensures the system doesn't hallucinate when the knowledge base is missing information. | |
| 3. **Observability:** By integrating **RAGAS**, we have an automated way to track performance and catch regressions. | |
| Good luck with your interview! π | |