Cortex / ARCHITECTURE_EXPLANATION.md
aditya-joshi-05's picture
Add conversational memory
a2f2da3
|
Raw
History Blame Contribute Delete
6.38 kB

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! πŸš€