A production-ready Retrieval-Augmented Generation (RAG) system for semantic search over product reviews.
- ✅ Semantic search using FAISS and sentence-transformers
- ✅ Robust error handling and logging
- ✅ Checkpoint/resume functionality for large datasets
- ✅ GPU acceleration with automatic fallback to CPU
- ✅ Configurable through environment variables and config file
- ✅ Batch processing for efficient indexing
- ✅ Hybrid retrieval support (semantic + BM25, optional)
- Embedding Model:
sentence-transformers/all-mpnet-base-v2 - Embedding Dimension: 768
- Vector Index: FAISS (IndexFlatIP for cosine similarity)
- Lexical Scoring: BM25 (optional, for hybrid retrieval)
- Python 3.8+
- CUDA-compatible GPU (optional, but recommended for speed)
- PostgreSQL database with reviews table
-
Clone the repository:
git clone <your-repo> cd rag-amarole
-
Create virtual environment:
python -m venv .venv source .venv/bin/activate # On Windows: .venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
-
Configure environment variables: Create a
.envfile in the project root:# Database configuration DB_USER=your_username DB_PASSWORD=your_password DB_HOST=localhost DB_PORT=5432 DB_NAME=your_database
Run the indexing script to embed all documents and build the FAISS index:
python indexer.pyWhat it does:
- Connects to your PostgreSQL database
- Fetches documents in batches
- Generates embeddings using all-mpnet-base-v2
- Builds a FAISS index for fast similarity search
- Saves checkpoints every 5,000 documents
- Saves the final index to
indexes/
Resume from checkpoint: If the process is interrupted, simply run the command again. It will automatically resume from the last checkpoint.
Configuration: Edit config.py to adjust:
- Batch sizes
- Checkpoint frequency
- Model settings
- Index directory
Use the command-line search tool:
# Interactive mode
python search.py
# Single query
python search.py "What are customers saying about quality?"Use the retriever directly in your code:
from retriever import FAISSRetriever
from config import ModelConfig, IndexConfig, RetrievalConfig
# Initialize retriever
retriever = FAISSRetriever(
model_config=ModelConfig(),
index_config=IndexConfig(),
retrieval_config=RetrievalConfig(top_k=10)
)
# Search
results = retriever.search("What are customers saying about quality?")
# Print results
for result in results:
print(f"Doc ID: {result.doc_id}, Score: {result.score:.4f}")Start the FastAPI server:
# Development mode
uvicorn api:app --reload
# Or with make
make api-devThen search using HTTP:
# Using curl
curl -X POST http://localhost:8000/search \
-H "Content-Type: application/json" \
-d '{"query": "product quality", "top_k": 5}'
# Using Python client
python api_client.pyAPI Features:
- ✅ Full metadata - Returns Summary and Text for each result
- ✅ RESTful - Standard HTTP endpoints
- ✅ Interactive docs - Auto-generated at
/docs - ✅ Fast - Async request handling
- ✅ Production-ready - CORS, error handling, logging
See API_DOCUMENTATION.md for complete API reference.
Search multiple queries at once for better efficiency:
queries = [
"product quality issues",
"shipping and delivery",
"customer service experience"
]
all_results = retriever.batch_search(queries, top_k=5)
for query, results in zip(queries, all_results):
print(f"\nQuery: {query}")
for result in results:
print(f" - Doc {result.doc_id}: {result.score:.4f}")rag-amarole/
├── config.py # Configuration management
├── indexer.py # Embedding and FAISS indexing
├── retriever.py # Search and retrieval
├── api.py # FastAPI REST API (NEW!)
├── api_client.py # API client example (NEW!)
├── search.py # CLI search tool
├── validate.py # System validation
├── example.py # Usage examples
├── requirements.txt # Python dependencies
├── .env # Environment variables (create this)
├── indexes/ # Generated FAISS indexes and metadata
│ ├── *.index # FAISS index files
│ ├── *_metadata.pkl # Document ID mappings
│ └── *_checkpoint.pkl # Resume checkpoints
└── base/ # Legacy code (for reference)
model_name: str = "sentence-transformers/all-mpnet-base-v2"
max_seq_length: int = 512
dtype: str = "float16" # "float16" | "bfloat16" | "float32"
device: Optional[str] = None # None = auto-detect
normalize_embeddings: bool = Truedb_batch_size: int = 500 # Documents per DB query
embed_batch_size: int = 256 # GPU batch size
checkpoint_interval: int = 5000 # Checkpoint frequency
index_dir: Path = Path("indexes") # Output directorytop_k: int = 10 # Number of results
min_similarity: float = 0.0 # Similarity threshold
use_bm25: bool = False # Enable hybrid retrieval
bm25_weight: float = 0.3 # BM25 weight (0-1)-
GPU Usage: The system automatically uses GPU if available. Monitor with:
nvidia-smi
-
Batch Sizes:
- Increase
db_batch_size(500-1000) for fewer DB round trips - Increase
embed_batch_size(256-512) if you have more GPU memory
- Increase
-
Checkpointing:
- Lower
checkpoint_intervalif your system is unstable - Higher values = less overhead but more loss if interrupted
- Lower
-
Memory: For large datasets (millions of docs), consider:
- Using
faiss-gpufor GPU-accelerated search - Using IVF indexes instead of Flat for faster search
- Splitting into multiple indexes
- Using
Expected schema for the reviews table:
CREATE TABLE reviews (
"Id" INTEGER PRIMARY KEY,
"Summary" TEXT,
"Text" TEXT
);- Check your
.envfile has correct credentials - Ensure PostgreSQL is running
- Verify network connectivity
- Run
python indexer.pyfirst to build the index
- Reduce
embed_batch_sizeinconfig.py - Use
dtype="float16"instead offloat32 - Use CPU mode by setting
device="cpu"
- Check GPU is being used: look for "Auto-detected device: cuda"
- Increase batch sizes
- Ensure database is indexed on
Idcolumn
- Add support for filtering by metadata
- Implement reranking with cross-encoder
- Add API endpoint for production deployment
- Support for incremental index updates
- Add evaluation metrics and benchmarks
MIT
Contributions welcome! Please open an issue or submit a pull request.