A production-ready Retrieval-Augmented Generation (RAG) system that allows you to upload PDF documents, process them into a vector database, and ask questions about their content using AI.
- 📄 PDF Document Processing: Upload and automatically chunk PDF documents
- 🔍 Vector Search: Efficiently search through document embeddings using Qdrant
- 🤖 AI-Powered Answers: Get accurate answers from your documents using Groq LLM
- 🔄 Workflow Orchestration: Reliable event-driven processing with Inngest
- 🎨 User-Friendly Interface: Clean Streamlit UI for document upload and querying
- Backend Framework: FastAPI
- Workflow Engine: Inngest
- Vector Database: Qdrant
- LLM Provider: ChatGroq
- Embeddings: HuggingFace sentence-transformers/all-MiniLM-L6-v2 (free)
- Document Processing: LlamaIndex
- Frontend: Streamlit
- Language: Python
- Python 3.8+
- Docker (for Qdrant database)
- Node.js/npm (for Inngest CLI)
- UV package manager (recommended) or pip
git clone <your-repo-url>Using UV (recommended):
uv pip install -r requirements.txtOr using pip:
pip install -r requirements.txtCreate a .env file in the root directory:
GROQ_API_KEY=your_groq_api_key_hereGetting a Groq API Key:
- Visit [https://console.groq.com]
- Sign up for a free account
- Navigate to API Keys section
- Create a new API key
Ensure Docker is running, then execute:
docker run -d --name qdrantRagDb -p 6333:6333 -v "$(pwd)/qdrant_storage:/qdrant/storage" qdrant/qdrantThis command:
- Creates a Qdrant container named
qdrantRagDb - Maps port 6333 for database access
- Persists data in
./qdrant_storagedirectory
You need to run three services simultaneously. Open three separate terminal windows:
uv run uvicorn main:app --reloadThe API will be available at http://127.0.0.1:8000
npx inngest-cli@latest dev -u http://127.0.0.1:8000/api/inngest --no-discoveryThe Inngest dashboard will be available at http://127.0.0.1:8288
streamlit run streamlit_app.pyThe Streamlit app will open automatically in your browser at http://localhost:8501
rag-ai-agent/
│
├── main.py # FastAPI app with Inngest functions
├── streamlit_app.py # Streamlit frontend interface
├── vector_db.py # Qdrant vector database operations
├── data_loader.py # PDF loading and embedding functions
├── custom_types.py # Pydantic models for type safety
├── .env # Environment variables (create this)
├── requirements.txt # Python dependencies
├── README.md # This file
│
├── uploads/ # Uploaded PDF storage (auto-created)
└── qdrant_storage/ # Qdrant database persistence (auto-created)
- Open the Streamlit app in your browser
- Click "Browse files" and select a PDF document
- The system will automatically:
- Save the PDF to the
uploads/directory - Chunk the document into manageable pieces
- Generate embeddings using HuggingFace
- Store vectors in Qdrant database
- Save the PDF to the
- Enter your question in the text input field
- Adjust "How many chunks to retrieve" (default: 5)
- Click "Ask"
- The system will:
- Search for relevant document chunks
- Send context to the LLM
- Generate an answer based on your documents
- Display sources used
User Upload → Streamlit → Inngest Event → FastAPI Function
↓
PDF Processing
↓
Chunking (LlamaIndex)
↓
Embedding (HuggingFace)
↓
Qdrant Storage
User Query → Streamlit → Inngest Event → FastAPI Function
↓
Vector Search (Qdrant)
↓
Context Retrieval
↓
LLM Generation (Groq)
↓
Answer Display
Ingestion Workflow (rag/ingest_pdf event):
- Load PDF using LlamaIndex PDFReader
- Split text into chunks (1000 chars, 200 overlap)
- Generate embeddings using sentence-transformers
- Store in Qdrant with metadata
Query Workflow (rag/query_pdf_ai event):
- Embed user question
- Search Qdrant for top-k similar chunks
- Build context from retrieved chunks
- Send to Groq LLM with system prompt
- Return answer with sources
Edit vector_db.py to customize:
url: Qdrant server URL (default:http://localhost:6333)collection: Collection name (default:docs)dim: Embedding dimensions (default:384for MiniLM-L6-v2)
Edit data_loader.py:
chunk_size: Characters per chunk (default:1000)chunk_overlap: Overlap between chunks (default:200)
Edit main.py in the rag_query_pdf_ai function:
model: Groq model (default:openai/gpt-oss-120b)temperature: Response randomness (default:0.2)top_k: Number of chunks to retrieve (default:5)
First run may take time to download the sentence-transformers model (~80MB). This is normal and happens once.
GET /: Root endpointPOST /api/inngest: Inngest webhook endpoint
rag/ingest_pdf: Process and ingest PDF documentsrag/query_pdf_ai: Query documents and generate answers
This project uses entirely free services:
- Groq: Free tier with generous limits for LLM inference
- HuggingFace: Free open-source embedding models
- Qdrant: Free self-hosted vector database
- Inngest: Free local development server
- Chunk Size: Smaller chunks (500-1000 chars) work better for specific questions
- Top-K: Start with 5 chunks, increase if answers lack detail
- Temperature: Keep low (0.1-0.3) for factual answers
- Embeddings: MiniLM-L6-v2 is fast; use larger models for better accuracy
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
This project is licensed under the MIT License.
- Groq for fast LLM inference
- Qdrant for vector database
- Inngest for workflow orchestration
- LlamaIndex for document processing
- HuggingFace for embeddings
For issues and questions:
- Open an issue on GitHub
- Check existing issues for solutions
- Review Inngest dashboard for workflow errors