A Retrieval-Augmented Generation (RAG) engine built from scratch using FastAPI, PostgreSQL, pgvector, Sentence Transformers, and OpenRouter.
Instead of relying on high-level frameworks, this project focuses on implementing every major component of a modern RAG pipeline from first principles, including document ingestion, semantic retrieval, context engineering, prompt construction, and grounded answer generation.
- PDF document ingestion
- Page-wise text extraction using PyMuPDF
- Fixed-size chunking with overlap
- Metadata-aware chunking (
source,page_number,chunk_index) - Semantic embeddings using
BAAI/bge-small-en-v1.5 - PostgreSQL + pgvector vector storage
- Native pgvector cosine similarity search
- Similarity thresholding
- Context construction
- Prompt construction
- Grounded LLM answer generation using OpenRouter
- Modular service-oriented architecture
- FastAPI REST API
INGESTION
PDF Document
│
▼
Page Extraction
│
▼
Chunking
│
▼
Embedding Generation
│
▼
PostgreSQL + pgvector
────────────────────────────────────────────────────────────
RETRIEVAL
User Question
│
▼
Query Embedding
│
▼
Native pgvector Search
│
▼
Similarity Threshold
│
▼
Context Builder
│
▼
Prompt Builder
│
▼
OpenRouter LLM
│
▼
Grounded Response
| Method | Endpoint | Description |
|---|---|---|
| POST | /ingest |
Upload and index a PDF document |
| POST | /search |
Retrieve relevant context and generate a grounded answer |
- FastAPI
- PostgreSQL
- pgvector
- SQLAlchemy
- Sentence Transformers
- PyMuPDF
- OpenRouter
app/
│
├── config/
│ ├── embedding_config.py
│ ├── model_config.py
│ └── threshold_config.py
│
├── models/
│
├── routers/
│
├── schemas/
│
├── services/
│ ├── pdf_service.py
│ ├── chunking_service.py
│ ├── embedding_service.py
│ ├── retrieval_service.py
│ ├── context_builder_service.py
│ ├── prompt_builder_service.py
│ ├── llm_service.py
│ └── ingestion_service.py
│
└── main.py
- Extract text from uploaded PDF documents.
- Split pages into overlapping chunks.
- Generate semantic embeddings for every chunk.
- Store embeddings and metadata inside PostgreSQL using pgvector.
- Embed the user's query.
- Perform native cosine similarity search inside PostgreSQL.
- Filter low-quality matches using a similarity threshold.
- Build structured context from retrieved chunks.
- Construct a grounded prompt.
- Generate the final response using an LLM.
- No metadata-based filtering
- No Approximate Nearest Neighbor (HNSW) indexing
- No hybrid retrieval (BM25 + Vector Search)
- No Cross-Encoder reranking
- No source citations in generated responses
- No streaming responses
- No evaluation framework
- No conversational memory integration
- HNSW indexing
- Metadata filtering
- Hybrid Retrieval (BM25 + Vector Search)
- Cross-Encoder reranking
- Source-aware citations
- Streaming LLM responses
- Retrieval evaluation metrics
- Conversational memory integration
- Multi-document retrieval
- Tool calling
- Semantic retrieval pipeline
- PDF ingestion
- Chunking
- Embedding generation
- Manual cosine similarity in Python
- Metadata-aware chunking
- Modular service architecture
- Improved ingestion pipeline
- Native pgvector similarity search
- Database-side retrieval
- Similarity thresholding
- Context construction
- Prompt construction
- OpenRouter integration
- Complete Retrieval-Augmented Generation pipeline
This project is part of a broader effort to build AI systems from first principles, covering retrieval, memory, evaluation, tool use, routing, and agentic workflows without abstracting away the underlying architecture.