Author: Bajrang Chapola
Version: 0.1.0
Stack: Python 3.13 · FastAPI · Uvicorn · RabbitMQ · Qdrant · uv
- What Is AgenticXRAG?
- Architecture Overview
- Infrastructure Layer
- AI Services Layer
- Application Layer
- 5.1 API Server
- 5.2 Ingestion API
- 5.3 Retrieval API
- Ingestion Pipeline
- 6.1 Pipeline Stages
- 6.2 Ingestion Profiles
- Retrieval Pipeline
- Embedding Models
- Configuration Reference
- Platform Operations
- Docker & Deployment
- Project Structure
AgenticXRAG is a production-ready, event-driven Retrieval-Augmented Generation (RAG) platform built for high-accuracy document ingestion and semantic retrieval. It is designed to ingest large document corpora (PDFs and other formats), store vector representations in a managed knowledge base, and serve low-latency hybrid search queries over that knowledge base via a REST API.
Key design principles:
- Event-driven — document ingestion is decoupled from the API via RabbitMQ message queues, enabling high-throughput async processing.
- Hybrid retrieval — combines dense semantic vectors, sparse BM42/SPLADE vectors, and late-interaction ColBERT vectors for maximum recall and precision.
- Profile-driven — ingestion and retrieval behaviour is controlled by named profiles in a single YAML config file, with no code changes required.
- Microservice-friendly — embedding inference is offloaded to dedicated FastAPI microservices, keeping the core application stateless with respect to GPU resources.
- Production-ready — structured JSON logging, CORS middleware, score thresholding, graceful shutdown hooks, and Docker Compose orchestration throughout.
┌─────────────────────────────────────────────────────────────────────────┐
│ CLIENT / UPSTREAM │
│ (REST API calls on port 8080) │
└────────────────────────────┬────────────────────────────────────────────┘
│
┌───────────▼───────────┐
│ AgenticXRAG API │ FastAPI · Uvicorn · :8080
│ (Application Layer) │
└──────┬────────┬───────┘
│ │
┌──────────▼─┐ ┌──▼──────────────┐
│ Ingestion │ │ Retrieval │
│ Router │ │ Router │
│ /api/v1/ │ │ /api/v1/ │
│ ingestion/ │ │ retrieval/ │
└──────┬──────┘ └──────┬───────────┘
│ │
┌─────────▼──────┐ ┌──────▼─────────────────────────┐
│ RabbitMQ Queue│ │ Hybrid Retrieval Service │
│ (ingestion_q) │ │ Dense + Sparse + Rerank │
└─────────┬──────┘ └──────┬─────────────────────────┘
│ │
┌─────────▼──────┐ ┌──────▼────────────┐
│ Ingestion │ │ Qdrant │
│ Worker │ │ Vector Database │
│ (Pipeline) │ │ :6333 │
└──────┬──────────┘ └───────────────────┘
│
┌─────────────┼──────────────────────┐
│ │ │
┌──▼──┐ ┌─────▼──────┐ ┌──────────▼───────┐
│ HF │ │ FastEmbed │ │ FastEmbed │
│ : │ │ Sparse │ │ ColBERT │
│8002 │ │ :8001 │ │ :8001 │
└─────┘ └────────────┘ └──────────────────┘
The platform is split into three layers, each independently managed:
| Layer | Components | Script |
|---|---|---|
| Infrastructure | RabbitMQ, Qdrant | infra/infra.sh |
| AI Services | FastEmbed, HF Embedder | services/services.sh |
| Application | AgenticXRAG API | agenticxrag.sh |
Managed by infra/infra.sh → platform.sh.
| Property | Value |
|---|---|
| Image | rabbitmq:3-management |
| Container | agenticxrag-rabbitmq |
| AMQP Port | 5672 |
| Management UI | 15672 |
| Exchange | xrag.service.exchange |
| Ingestion Queue | ingestion_q |
| Request Queue | request_q |
| Volume | agenticxrag_rabbitmq_data |
RabbitMQ is the backbone of the async ingestion pipeline. When the Ingestion API receives a document request, it publishes a message to ingestion_q. The Ingestion Worker (running inside the core application) consumes these messages and executes the full pipeline without blocking the API response.
| Property | Value |
|---|---|
| Image | qdrant/qdrant:latest |
| Container | qdrant |
| HTTP Port | 6333 |
| gRPC Port | 6334 |
| Collection | csa_knowledge_base |
| Dense Vector Size | 1024 dimensions |
| ColBERT Vector Size | 128 dimensions |
| Volume | agenticxrag_qdrant_data |
Qdrant stores three vector types per chunk:
text-dense— full-float dense vectors from HuggingFace embeddings (1024-dim).text-sparse— sparse vectors from SPLADE (variable indices/values).text-colbert— multi-vector ColBERT representations (128-dim per token).
All vectors share the same named collection so that multi-vector queries can be batched efficiently.
Managed by services/services.sh → platform.sh.
| Property | Value |
|---|---|
| Container | agenticxrag-fastembed-service |
| Port | 8001 |
| Volume | agenticxrag_fastembed_cache |
| Network | agenticxrag-net |
A standalone FastAPI microservice built on the fastembed library. Handles all lightweight, CPU-efficient embedding tasks and reranking.
Endpoints:
| Endpoint | Method | Description |
|---|---|---|
POST /embed/dense |
POST | Dense vector generation (MiniLM-style) |
POST /embed/sparse |
POST | Sparse SPLADE vector generation |
POST /embed/colbert |
POST | ColBERT multi-vector generation |
POST /rerank |
POST | Cross-encoder reranking |
GET /health |
GET | Health check + loaded model list |
Models served (configurable via config.yaml):
| Type | Default Model |
|---|---|
| Sparse | prithivida/Splade_PP_en_v1 |
| ColBERT | colbert-ir/colbertv2.0 |
| Reranker | BAAI/bge-reranker-base |
Models are lazy-loaded on first request and cached in memory for subsequent calls.
| Property | Value |
|---|---|
| Container | agenticxrag-hf-embedding-service |
| Port | 8002 |
| Volume | agenticxrag_hf_model_cache |
| Network | agenticxrag-net |
A dedicated microservice for dense embedding inference using full HuggingFace transformer models. GPU-accelerated versions are available via the docker-compose-cuda.yml variant.
Default model: Qwen/Qwen3-Embedding-0.6B (1024-dim output)
Endpoint:
| Endpoint | Method | Description |
|---|---|---|
POST /embed |
POST | Dense vector generation |
Managed by agenticxrag.sh. The core Python application running the FastAPI server.
- Framework: FastAPI 0.136+
- Server: Uvicorn (single worker)
- Port:
8080 - Host:
0.0.0.0 - Docs (dev):
GET /docs(Swagger UI),GET /redoc - Docs (prod): Disabled
- Health:
GET /health
The API server starts with a lifespan context manager that bootstraps all infrastructure connections on startup (RabbitMQ, Qdrant, Ingestion Worker) and performs a graceful shutdown sequence on termination.
CORS is configured to allow all origins (*) — tighten this for production deployments.
Base prefix: /api/v1/ingestion
All ingestion endpoints are asynchronous — they return 202 Accepted immediately after queuing the job to RabbitMQ. Processing happens in the background.
| Endpoint | Method | Description |
|---|---|---|
/api/v1/ingestion/file |
POST | Ingest a single file by path |
/api/v1/ingestion/files |
POST | Ingest a specific list of file paths |
/api/v1/ingestion/folder |
POST | Ingest all files in a directory |
Example — single file:
curl -X POST http://localhost:8080/api/v1/ingestion/file \
-H "Content-Type: application/json" \
-d '{"file_path": "/data/documents/report.pdf", "profile": "default"}'Example — folder:
curl -X POST http://localhost:8080/api/v1/ingestion/folder \
-H "Content-Type: application/json" \
-d '{"folder_path": "/data/documents/", "profile": "pdf_semantic"}'Base prefix: /api/v1/retrieval
| Endpoint | Method | Description |
|---|---|---|
/api/v1/retrieval/search |
POST | Execute a hybrid search query |
Request body:
{
"query": "What are the key findings in the Q3 financial report?",
"profile_name": "default",
"filters": null,
"top_n": 5
}Response: Ranked list of document chunks with RRF score, dense score, sparse score, and full metadata from the original document.
Example:
curl -X POST http://localhost:8080/api/v1/retrieval/search \
-H "Content-Type: application/json" \
-d '{"query": "quarterly revenue trends", "top_n": 5}'When a document job is dequeued from RabbitMQ, the Ingestion Worker runs it through a sequential pipeline of processors.
Document Path
│
▼
┌──────────────────┐
│ 1. Parsing │ DoclingPDFParser → extracts structured text + layout
└────────┬─────────┘
▼
┌──────────────────┐
│ 2. Text │ Normalises whitespace, removes artifacts, strips noise
│ Cleaning │
└────────┬─────────┘
▼
┌──────────────────┐
│ 3. Chunking │ Splits text into overlapping chunks (configurable strategy)
└────────┬─────────┘
▼
┌──────────────────┐
│ 4. Dense │ Calls HF Service (:8002) → Qwen3-Embedding-0.6B vectors
│ Embedding │
└────────┬─────────┘
▼
┌──────────────────┐
│ 5. Sparse │ Calls FastEmbed (:8001) → SPLADE sparse vectors
│ Embedding │
└────────┬─────────┘
▼
┌──────────────────┐
│ 6. ColBERT │ Calls FastEmbed (:8001) → ColBERT multi-vectors
│ Embedding │
└────────┬─────────┘
▼
┌──────────────────┐
│ 7. Qdrant │ Upserts all three vector types into the collection
│ Storage │
└──────────────────┘
Profiles are defined in config/agenticxrag_config.yaml under ingestion_profiles. Each profile selects a parser, chunker, and the three embedder types.
| Profile | Parser | Chunker | Use Case |
|---|---|---|---|
default |
docling_pdf | sentence | General purpose PDF ingestion |
pdf_semantic |
docling_pdf | semantic | High-quality semantic chunking, slower |
pdf_fast |
docling_pdf | sentence | Fast ingestion, same as default |
Chunker parameters:
| Chunker | Chunk Size | Overlap | Strategy |
|---|---|---|---|
sentence |
1024 tokens | 200 tokens | Sentence boundary splitting |
semantic |
— | — | Embedding-based semantic breaks (95th percentile) |
recursive |
512 tokens | 50 tokens | Recursive character splitting |
A query goes through three parallel searches against Qdrant:
- Dense search (
text-densevector namespace) — cosine similarity, threshold0.5, top-K20 - Sparse search (
text-sparsevector namespace) — dot product, threshold5.0, top-K20
Both searches execute as a batch query to Qdrant to minimise round-trip latency.
Results from dense and sparse searches are merged using Weighted Reciprocal Rank Fusion (RRF):
RRF_score(doc) = dense_weight × 1/(k + rank_dense)
+ sparse_weight × 1/(k + rank_sparse)
| Parameter | Value |
|---|---|
k (rank dampening) |
60 |
dense_weight |
0.7 |
sparse_weight |
0.3 |
Raw dense and sparse scores are preserved in chunk metadata alongside the fused RRF score, giving consumers full transparency into why a chunk was ranked.
After fusion, the top candidates are passed to a cross-encoder reranker (via FastEmbed service) which scores each chunk against the original query using a bidirectional attention model.
| Parameter | Value |
|---|---|
| Reranker Model | BAAI/bge-reranker-base |
Final top_n |
5 |
| Reranking | Enabled by default (configurable) |
If the reranker service is unavailable, the pipeline gracefully falls back to the fused RRF ranking.
| Role | Model | Dim | Service |
|---|---|---|---|
| Dense | Qwen/Qwen3-Embedding-0.6B |
1024 | HF Service :8002 |
| Sparse | prithivida/Splade_PP_en_v1 |
sparse | FastEmbed :8001 |
| ColBERT | colbert-ir/colbertv2.0 |
128 | FastEmbed :8001 |
| Reranker | BAAI/bge-reranker-base |
— | FastEmbed :8001 |
All embedding calls are made over HTTP to the respective microservices. The core application has no direct model loading — it is entirely model-server agnostic and communicates via JSON REST.
All runtime behaviour is controlled by config/agenticxrag_config.yaml. Environment variables can override config values using ${VAR:-default} syntax.
Key environment variables:
| Variable | Default | Description |
|---|---|---|
AGENTICXRAG_CONFIG |
./config/agenticxrag_config.yaml |
Path to main config file |
API_HOST |
0.0.0.0 |
FastAPI bind host |
API_PORT |
8080 |
FastAPI bind port |
RUN_ENV |
dev |
dev enables hot-reload and API docs |
LOG_DIR |
./data/logs |
Directory for log files |
LOG_LEVEL |
INFO |
Logging verbosity |
QDRANT_URL |
http://localhost:6333 |
Qdrant HTTP endpoint |
RABBITMQ_HOST |
localhost |
RabbitMQ hostname |
RABBITMQ_PORT |
5672 |
RabbitMQ AMQP port |
HF_EMBEDDING_SERVER_URL |
http://localhost:8002/embed |
Dense embedding service |
SPARSE_EMBEDDING_SERVER_URL |
http://localhost:8001/embed/sparse |
Sparse embedding service |
COLBERT_EMBEDDING_SERVER_URL |
http://localhost:8001/embed/colbert |
ColBERT embedding service |
RERANKER_SERVER_URL |
http://localhost:8001/rerank |
Reranker service |
Orchestrates the entire platform: Platform (infra + services) → Core (API).
Startup order: platform.sh → agenticxrag.sh
Shutdown order (stop/clean): agenticxrag.sh → platform.sh
./run.sh # smart-restart (default — safest)
./run.sh start # cold-start the entire stack
./run.sh stop # gracefully stop everything
./run.sh restart # full stop → start cycle
./run.sh status # view all container statuses
./run.sh clean # ⚠️ full teardown (data loss)Manages infrastructure and AI services only (no application).
./platform.sh # smart-restart (default)
./platform.sh start # start infra + services
./platform.sh stop # stop infra + services
./platform.sh restart # full cycle
./platform.sh status # view infra + service status
./platform.sh clean # ⚠️ reset infra (data loss)Manages the AgenticXRAG API container independently.
./agenticxrag.sh # smart-restart (default)
./agenticxrag.sh start # start the API container
./agenticxrag.sh stop # stop the API container
./agenticxrag.sh restart # full cycle
./agenticxrag.sh status # view API container status
./agenticxrag.sh clean # ⚠️ remove API container + imageAction reference:
| Action | Description |
|---|---|
start |
Start containers. Skip already-running ones. |
stop |
Stop containers. Preserve volumes and images. |
restart |
Full stop → start cycle. |
smart-restart |
Stop running containers, then start. Fastest option. |
status |
Read-only status via docker compose ps. |
clean |
down -v --rmi all). |
Log files:
| Script | Log Location |
|---|---|
run.sh |
logs/agenticxrag.log |
platform.sh |
logs/platform.log |
agenticxrag.sh |
logs/agenticxrag-core.log (core) |
infra/infra.sh |
infra/logs/infra.log |
services/services.sh |
services/logs/services.log |
The application is containerised using a multi-stage Dockerfile based on uv for fast, reproducible builds.
Build stages:
| Stage | Base Image | Purpose |
|---|---|---|
builder |
python:3.13-slim |
Install all dependencies into /app/.venv using uv sync --frozen |
runtime |
python:3.13-slim |
Copy pre-built .venv + source code; no build tools in production |
Build & run with Docker Compose:
# Build and start the full platform
docker compose up -d --build
# View logs
docker compose logs -f
# Stop
docker compose downKey runtime environment variables for Docker (docker-compose.yml):
environment:
RUN_ENV: prod
QDRANT_URL: http://qdrant:6333
RABBITMQ_HOST: agenticxrag-rabbitmq
HF_EMBEDDING_SERVER_URL: http://agenticxrag-hf-embedding-service:8002/embed
SPARSE_EMBEDDING_SERVER_URL: http://agenticxrag-fastembed-service:8001/embed/sparse
COLBERT_EMBEDDING_SERVER_URL: http://agenticxrag-fastembed-service:8001/embed/colbert
RERANKER_SERVER_URL: http://agenticxrag-fastembed-service:8001/rerankAll containers share the external Docker network agenticxrag-net.
Last updated: May 2026