rag-pipeline
๐ต๐ฑ [Polska wersja](README.pl.md)
# RAG Pipeline
A local, GPU-accelerated retrieval pipeline for research papers โ parses PDFs with layout-aware chunking, pulls real bibliographic metadata (DOI โ CrossRef), embeds with hybrid dense + sparse vectors, and stores everything in Qdrant for hybrid search with reranking. Built to be queried directly from Claude through an MCP server.
## Why
Dropping papers into a folder makes them invisible to search. This turns a pile of PDFs into something queryable: proper section/paragraph-aware chunks (not a naive character splitter), citation-ready metadata pulled automatically from CrossRef, and hybrid dense+sparse retrieval so both semantic and exact-term queries work โ all exposed as MCP tools so Claude can search and ingest papers directly.
## Features
- **Layout-aware PDF parsing** via [Docling](https://github.com/DS4SD/docling) โ chunks by paragraph/section instead of a naive character splitter, keeps page numbers and section headings per chunk.
- **Real bibliographic metadata** โ regex-extracts a DOI from page 1, resolves full citation data (title, authors, journal, year, volume/issue/pages) via the CrossRef API, falls back to the PDF's own metadata when no DOI is found.
- **Hybrid embeddings** โ dense (`BAAI/bge-m3`) + sparse (SPLADE, `prithvida/Splade_PP_EN_v1`) vectors per chunk, stored together in Qdrant for hybrid retrieval.
- **Background ingestion** โ a Redis + [RQ](https://python-rq.org/) worker so large PDFs don't block a request; GPU-enabled Docker container for embedding.
- **MCP server** exposing two tools to Claude โ `search_papers` (hybrid search with reranking) and `ingest_paper` (drop a PDF straight into the index) โ meant to work as a research-paper memory Claude can query directly.
- **Dockerized** โ Qdrant + Redis + GPU-enabled API/worker containers via `docker-compose`.
## Tech stack
Python ยท [Docling](https://github.com/DS4SD/docling) (PDF parsing) ยท `sentence-transformers` (BGE-M3 dense embeddings) ยท `fastembed` (SPLADE sparse embeddings) ยท [Qdrant](https://qdrant.tech/) (hybrid vector search) ยท Redis + RQ (background job queue) ยท FastAPI (planned API layer) ยท MCP (Model Context Protocol server for Claude) ยท Docker Compose, CUDA 12.9 GPU container.
## Status
Work in progress โ not fully wired up end to end yet.
**Works today:** `ingest.py` runs standalone from the CLI โ parse a PDF, pull its metadata, embed it (dense + sparse), and upsert into Qdrant. Point it at a running Qdrant instance and it works.
**Missing:** `main.py`, the FastAPI service that's supposed to expose `/search`, `/ingest`, and `/health` โ the Dockerfile copies it, the Docker Compose healthcheck pings it, the RQ worker expects something to be enqueuing jobs for it, and `mcp_server.py`'s two Claude tools both call it over HTTP at `localhost:8000`. Without it, the worker has nothing to consume, the MCP tools have no backend to talk to, and `docker-compose up` won't build (the API/worker image's build step copies a file that isn't there).
The `docker-compose.yml` bind mounts also still point at a Windows path (`S:\RAG-data\...`) from an earlier setup โ adjust those to wherever you want Qdrant/Redis/model cache data to live before running it.
## Running it (today)
```bash
uv sync
# Qdrant needs to be running somewhere ingest.py can reach:
docker run -p 6333:6333 qdrant/qdrant
python ingest.py path/to/paper.pdf
```
The full pipeline (Docker Compose stack, `/search` and `/ingest` API, MCP tools) will work once `main.py` exists.
TDQS
Scored across 2 tools
The two tools have completely distinct roles: one adds documents to the index, the other queries it. There is no overlap or ambiguity between ingestion and search.
Both tools follow a verb_noun pattern and are recognizable at a glance. The only minor inconsistency is that one uses the plural 'papers' while the other uses singular 'paper'.
Two tools is a thin surface, falling below the typical 3-15 well-scoped range. Each tool is essential for the core RAG workflow, but the set still feels minimal for anything beyond basic ingest-and-query usage.
The core ingest and search operations are present, giving agents the main RAG loop. However, there is no way to list, delete, or update ingested papers, which leaves obvious workflow gaps around managing the collection.