A modular, pipeline-based Retrieval-Augmented Generation (RAG) system developed for the CSE3063 Object Oriented Software Design course. This project demonstrates the implementation of key software design patterns (Strategy, Template Method, Observer, Factory) within a search architecture.
- Pipeline Architecture: Extensible processing stages (Intent Detection -> Policy Routing -> Query Expansion -> Retrieval -> Reranking -> Generation).
- Design Patterns: Strictly adheres to SOLID principles.
- Strategy Pattern: Swappable algorithms for retrieval (Keyword, Vector, Hybrid), reranking (Simple, Cross-Encoder), and generation.
- Template Method: Standardized execution flow for pipeline stages.
- Observer Pattern: Event-driven tracing system for logging execution details.
- Factory Pattern: Centralized component creation based on configuration.
- Advanced Retrieval: Supports Hybrid Search combining Keyword (BM25) and Vector Semantic Search (FAISS + Gemini Embeddings).
- LLM Integration: Uses Google Gemini for answer generation and embeddings.
- Traceability: Full execution logging to JSONL files for debugging and validation.
The project follows a strict package-by-feature/layer structure:
python_src/
├── cse3063f25grp11/
│ ├── controller/ # Application Entry Point
│ │ └── main.py # CLI Driver: Bootstraps the application and handles arguments
│ ├── factory/ # Object Creation
│ │ └── component_factory.py # GRASP Creator: Instantiates specific strategies based on Config
│ ├── model/ # Domain Data Transfer Objects (DTOs)
│ │ ├── answer.py # DTO: Encapsulates the final generated response and citations
│ │ ├── chunk.py # Entity: Atomic text unit with metadata (Source of Truth)
│ │ ├── config.py # Configuration: Maps JSON settings to Python object
│ │ ├── hit.py # DTO: Represents a scored search result
│ │ └── intent.py # Enum: Defined classification types
│ ├── pipeline/ # Orchestration Logic
│ │ ├── stages/ # Concrete Pipeline Steps (Template Method Components)
│ │ │ ├── generation_stage.py # Step: Wraps AnswerAgent execution
│ │ │ ├── intent_detection_stage.py # Step: Wraps IntentDetector execution
│ │ │ ├── policy_routing_stage.py # Step: Wraps PolicyRouter execution
│ │ │ ├── query_expansion_stage.py # Step: Wraps QueryWriter execution
│ │ │ ├── reranking_stage.py # Step: Wraps Reranker execution
│ │ │ └── retrieval_stage.py # Step: Wraps Retriever execution
│ │ ├── context.py # Blackboard Pattern: Shared state object passed between stages
│ │ ├── pipeline_stage.py # Abstract Class: Defines the contract for pipeline steps
│ │ └── rag_orchestrator.py # GRASP Controller: Manages the sequence of RAG operations
│ ├── repository/ # Data Access Layer
│ │ ├── keyword_index.py # Singleton/Repository: In-memory inverted index implementation
│ │ └── vector_index.py # Repository: FAISS-based vector index
│ └── service/ # Logic Interfaces (API)
│ ├── impl/ # Concrete Strategy Implementations
│ │ ├── bm25_retriever.py # Strategy: BM25-based retrieval algorithm
│ │ ├── cross_encoder_reranker.py # Strategy: AI-based reranker using Cross-Encoders
│ │ ├── gemini_answer_agent.py # Strategy: LLM-based response generation
│ │ ├── gemini_embedder.py # Service: Generates embeddings using Gemini API
│ │ ├── hybrid_retriever.py # Strategy: Combines Keyword and Vector retrieval
│ │ ├── keyword_retriever.py # Strategy: Simple TF-based retrieval
│ │ ├── llm_policy_router.py # Strategy: LLM-based query filtering/routing
│ │ ├── rule_intent_detector.py # Strategy: Regex/Keyword-based intent classification
│ │ └── ...
│ ├── tracing/ # Observability (Observer Pattern)
│ │ ├── jsonl_trace_sink.py # Observer: Writes trace events to JSONL log files
│ │ ├── trace_bus.py # Subject: Event bus that notifies subscribers
│ │ └── trace_event.py # DTO: Snapshot of input/output/time for logging
└── resources/ # Static Assets
├── config.json # App Configuration (Defines active strategies)
├── data.json # Raw Data Corpus
├── intent_boosters.json # Domain Data: Weighted keywords for specific intents
├── intent_rules.json # Domain Data: Regex rules for IntentDetector
├── stopwords.json # Domain Data: List of words to ignore in queries
└── vector_index.faiss # Pre-computed Vector Index
The system is fully data-driven. The config.json file located in python_src/resources/ controls the behavior of the pipeline.
| Field | Type | Description | Valid Values |
|---|---|---|---|
indexFilePath |
String | Path to document corpus | "python_src/resources/data.json" |
retrieverK |
Integer | Number of documents to retrieve | 1–20 |
intentDetectorType |
String | Intent detection strategy | "rule" |
queryWriterType |
String | Query expansion strategy | "heuristic" |
retrieverType |
String | Retrieval strategy | "keyword", "vector", "hybrid" |
rerankerType |
String | Re-scoring method | "simple", "noop", "cross_encoder" |
answerAgentType |
String | Answer generator | "template", "gemini" |
policyRouterType |
String | Policy routing strategy | "llm" |
embeddingProvider |
String | Embedding service provider | "gemini" |
geminiApiKey |
String | API Key for Google Gemini | AIza... |
hybridSemanticWeight |
Float | Weight for semantic score in hybrid search | 0.0 - 1.0 |
Example config.json:
{
"intentDetectorType": "rule",
"queryWriterType": "heuristic",
"retrieverType": "hybrid",
"rerankerType": "cross_encoder",
"answerAgentType": "gemini",
"policyRouterType": "llm",
"indexFilePath": "python_src/resources/data.json",
"retrieverK": 20,
"geminiApiKey": "YOUR_API_KEY",
"hybridSemanticWeight": 0.7,
"hybridKeywordWeight": 0.3
}The application can be run in two modes: Interactive Mode and One-Shot (CLI) Mode.
- Python 3.8 or higher
- Install dependencies:
pip install -r python_src/requirements.txtIf you plan to use Vector or Hybrid retrieval, you need to build the vector index first.
python python_src/scripts/build_vector_index.pyRun the application without arguments to enter the interactive shell.
python python_src/cse3063f25grp11/controller/main.pyOutput:
=== MiniRAG System Starting ===
Config loaded from: .../resources/config.json
...
Interactive Mode. Type 'exit' to quit.
Ask a question: Dersin kredisi kaç?
Pass the question directly using the --q argument. Useful for testing or piping.
python python_src/cse3063f25grp11/controller/main.py --q "Hocanın ofisi nerede?"You can load a specific configuration file using the --config flag.
python python_src/cse3063f25grp11/controller/main.py --config "custom_config.json"The system implements an Observer Pattern to trace every step of the pipeline.
- Logs are automatically saved to the
logs/directory. - Format: JSONL (JSON Lines).
- Each line contains: Timestamp, Stage Name, Status, Duration, and Error details (if any).
This project strictly follows the principles required for the course:
- Encapsulation: All pipeline data is encapsulated within the
Contextobject. - Modularity: Each stage is independent and swappable via configuration.
- Extensibility: New strategies (e.g., a new Retriever) can be added by implementing the interface and registering it in the Factory.
Main -> RagOrchestrator -> Pipeline -> [Intent -> Policy -> Query -> Retrieval -> Rerank -> Generation]