Production-ready RAG pipeline for technical PDFs — VLM/OCR preprocessing, hybrid dense–sparse retrieval, cross-encoder reranking, and an OpenWebUI chat interface.
Domain-agnostic Retrieval-Augmented Generation framework for engineering specs, regulatory standards, scientific papers, and formula-heavy documents. Ingest scanned PDFs with tables and equations, retrieve with hybrid search, and generate grounded answers via LLM.
Keywords: rag · retrieval-augmented-generation · qdrant · open-webui · fastapi · docker · ocr · vision-language-model · hybrid-search · technical-documentation · llm
- VLM/OCR preprocessing — extract text from scanned, tabular, and formula-rich PDFs
- Hybrid retrieval — dense embeddings + sparse BM42 keyword search in Qdrant
- Technical chunking — optimized for tables, identifiers, and structured content
- Cross-encoder reranking — BGE reranker for higher precision on domain queries
- OpenWebUI integration — chat UI with a custom Python tool for the RAG pipeline
- Docker-ready — full stack via Compose, GPU-accelerated inference
flowchart LR
Docs["PDF / Images\n(docs/)"] --> VLM["VLM Preprocessor\nQwen3-VL"]
VLM --> JSON["OCR JSON"]
JSON --> Chunk["Chunking +\nEmbedding"]
Chunk --> Qdrant["Qdrant\nHybrid Index"]
User["User"] --> WebUI["OpenWebUI"]
WebUI --> RAG["rag-service\nFastAPI"]
RAG --> Qdrant
RAG --> Rerank["BGE Reranker"]
Rerank --> Ollama["Ollama\nQwen2.5"]
Ollama --> WebUI
| Service | Technology | Role |
|---|---|---|
| Ollama | LLM + VLM | Answer generation and OCR |
| OpenWebUI | Web frontend | Chat UI and Python tools |
| rag-service | FastAPI + Python | Embeddings, retrieval, reranking |
| rag-qdrant | Qdrant | Vector + sparse storage |
| Stage | Model |
|---|---|
| VLM / OCR | qwen3-vl:4b-q3_k_s |
| Dense embedding | sentence-transformers/paraphrase-multilingual-mpnet-base-v2 |
| Sparse retrieval | Qdrant/bm42-all-minilm-l6-v2-attentions |
| Vector DB | Qdrant |
| Reranking | BAAI/bge-reranker-v2-m3 |
| Answer LLM | qwen2.5:7b-instruct |
- Docker + Docker Compose v2
- NVIDIA Container Toolkit (GPU)
- Ollama installed in WSL2
- PDF / PNG / JPG files in
docs/
cd rag/
python3 download_models.pyFull pipeline: Ollama, Docker rebuild, OCR, Qdrant ingestion, smoke test.
chmod +x mount.sh
./mount.shchmod +x start.sh
./start.sh # start
./start.sh stop # stop containers
./start.sh restart # restart stack
./start.sh restart-rag # restart backend only
./start.sh status # show status| Service | URL |
|---|---|
| OpenWebUI | http://localhost:8080 |
| RAG API (Swagger) | http://localhost:8000/docs |
| Qdrant Dashboard | http://localhost:6333/dashboard |
| Ollama API | http://$WSL_IP:11434 |
- Open Workspace → Tools
- Create a new tool from
openwebui/function.py - Start a chat → Integrations → Tools → enable the tool
- Queries run against documents in
docs/
Full environment setup (click to expand)
Windows: install the latest NVIDIA drivers with WSL2 support.
WSL2:
nvidia-smicurl -fsSL https://ollama.com/install.sh | sh
ollama --versionGet-Service ollama
Stop-Service ollama
Set-Service ollama -StartupType Disabledsudo rm -rf /usr/share/ollama
sudo mkdir -p /usr/share/ollama
sudo chown $USER:$USER /usr/share/ollamasudo systemctl disable ollama
sudo systemctl stop ollamapkill -f ollama
export OLLAMA_HOST=0.0.0.0:11434
nohup ollama serve > ~/.ollama.log 2>&1 &curl http://$(hostname -I | awk '{print $1}'):11434/api/tagsVisTex-RAG/
├── docker/ # Dockerfile + docker-compose.yml
├── docs/ # Source documents (PDF, images)
├── openwebui/ # OpenWebUI custom tool
├── rag/
│ ├── config.py # Models, hosts, flags
│ ├── vlm_preprocessor.py # VLM OCR → JSON
│ ├── populate_qdrant.py # Chunk, embed, ingest
│ ├── rag_server.py # Hybrid RAG API
│ ├── modern_chunking.py
│ └── text_processing.py
├── mount.sh # First-time build + ingest
└── start.sh # Fast start/stop/restart
Runs VLM-based OCR on PDFs and images, outputs structured Markdown JSON.
Chunks OCR output, generates dense + sparse vectors, uploads to Qdrant.
FastAPI server: hybrid search, cross-encoder reranking, parent-chunk context expansion.