A clean, lightweight Retrieval-Augmented Generation (RAG) system using OpenRouter API for LLM inference.
- PDF Processing: Load and chunk PDF documents
- Lightweight Embeddings: Uses sentence-transformers
all-MiniLM-L6-v2(25MB, very fast) - FAISS Vector Database: Fast similarity search with persistence
- OpenRouter API: Uses
microsoft/phi-3.5-mini-instructmodel (can be changed) - Error Handling: Graceful error handling for API failures
- No Large Model Downloads: No need to download large LLMs locally
rag_app.py - Main application
├── rag/
│ ├── loader.py - PDF loading (PyPDFLoader)
│ ├── splitter.py - Text splitting (RecursiveCharacterTextSplitter)
│ ├── embedder.py - Embeddings (sentence-transformers)
│ ├── vector_store.py - FAISS vector database
│ ├── retriever.py - Document retriever (top 3 chunks)
│ └── generator.py - OpenRouter API calls (requests library)
├── .env - Configuration (API keys)
└── requirements.txt - Dependencies
cd c:\edu-sample
python -m venv venv
venv\Scripts\activate # On Windowspip install -r requirements.txt- Get your API key from OpenRouter.ai
- Edit
.envfile:
OPENROUTER_API_KEY=your_api_key_here
PDF_PATH=data/Projectile Motion.pdfPlace your PDF file in the data/ folder and update PDF_PATH in .env.
python rag_app.pyQuestion: What is projectile motion?
🔍 Retrieving context...
✓ Found 3 relevant chunks
💭 Generating response...
📝 Answer:
Projectile motion is the motion of an object thrown or projected into the air...
Type exit or quit to exit the application.
| Variable | Description | Required |
|---|---|---|
OPENROUTER_API_KEY |
Your OpenRouter API key | Yes |
PDF_PATH |
Path to PDF file | Yes |
FORCE_REBUILD |
Force rebuild of FAISS index | No |
Edit rag/generator.py:
MODEL = "microsoft/phi-3.5-mini-instruct" # Change thisAvailable models: https://openrouter.ai/models
Edit rag_app.py:
retriever = get_retriever(index, metadata, embeddings_model, k=5) # Changed from 3Edit rag/splitter.py:
RecursiveCharacterTextSplitter(
chunk_size=1000, # Larger chunks
chunk_overlap=200 # More overlap
)The system correctly handles OpenRouter API responses:
{
"choices": [
{
"message": {
"content": "Generated response..."
}
}
]
}Important: Response is accessed as:
response.json()["choices"][0]["message"]["content"]NOT .content attribute!
The system handles:
- ❌ Missing PDF file
- ❌ Invalid API key
- ❌ Network timeouts
- ❌ API errors
- ❌ Invalid JSON responses
| Component | Size | Speed |
|---|---|---|
| Embeddings Model | ~25 MB | Very fast (<1s) |
| FAISS Index | Depends on PDF | Near-instant |
| API Call | - | ~2-5s |
pip install faiss-cpuMake sure .env exists in the project root and contains your API key.
Update PDF_PATH in .env to the correct path.
Check:
- API key is valid and has credits
- Model name is correct
- Request format matches OpenRouter specification
- PDF:
data/Projectile Motion.pdf(or your own PDF) - Vector Store:
faiss_index/(auto-created) - Config:
.env(auto-created, update with your key)
| Package | Purpose |
|---|---|
langchain-community |
PDF loading & text splitting |
PyPDF2 |
PDF parsing (alternative) |
sentence-transformers |
Embeddings (all-MiniLM-L6-v2) |
faiss-cpu |
Vector similarity search |
requests |
HTTP API calls |
python-dotenv |
Environment variables |
- Set up OpenRouter API key
- Place a PDF in
data/folder - Update
.envwith PDF path - Run
python rag_app.py - Ask questions about your document!
MIT License