Knowledge Studio is a Django-based Retrieval-Augmented Generation (RAG) web application for uploading knowledge documents, indexing them into Qdrant, and answering user questions with cited context.
The current implementation uses:
- Local LLM inference through Ollama (
qwen2.5:7b) for query rewriting and final response generation. - Hybrid retrieval in Qdrant (dense + sparse BM25).
- Local embedding/reranking models from Hugging Face (
BAAI/bge-large-en-v1.5,BAAI/bge-reranker-large).
- User authentication, profile, and dashboard pages.
- Document ingestion API for PDF/TXT/MD uploads.
- OCR fallback for scanned PDF pages.
- Multi-stage RAG pipeline:
- Query processing
- Retrieval from Qdrant
- Re-ranking
- Context building
- LLM answer generation
- Streaming API responses for real-time pipeline updates.
The diagram below traces the complete request lifecycle from the moment a user submits a question to the moment a cited answer is streamed back to the browser.
flowchart LR
User(["👤 User"])
subgraph INPUT [" Input "]
A["Submit Query\nPOST /api/rag/"]
end
subgraph PREP [" Query Preparation "]
B["Query Rewriter\nOllama · qwen2.5:7b"]
C["Query Processor\nNormalise · Classify Intent"]
end
subgraph RETRIEVAL [" Retrieval "]
D["Qdrant Retriever\nHybrid Search · top-15 chunks\nDense + Sparse BM25"]
E["Re-ranker\nCrossEncoder · top-10 results\nBAAI/bge-reranker-large"]
end
subgraph GENERATION [" Generation "]
F["Context Builder\n3 100-token budget · citations"]
G["LLM Generation\nOllama · qwen2.5:7b"]
end
subgraph OUTPUT [" Output "]
H["SSE Stream\nper-stage progress events"]
end
Answer(["💬 Cited Answer"])
User --> A
A --> B --> C
C --> D --> E
E --> F --> G
G --> H --> Answer
Each pipeline stage emits a Server-Sent Event (SSE) so the frontend can surface live progress indicators —
process → retrieve → rerank → context → generate → complete— before the final answer arrives.
- Python / Django
- PostgreSQL-compatible database URI (currently expected via
SUPABASE_URI) - Qdrant Cloud (vector database)
- LangChain ecosystem (
langchain-ollama,langchain-qdrant,langchain-huggingface) - Ollama (local LLM serving)
- PyTorch, SentenceTransformers
- OCR tooling: PyMuPDF (
fitz) + Tesseract
Install and configure the following before running the app:
- Python 3.12+
- pip and virtualenv
- Ollama installed and running locally
- Tesseract OCR installed on your machine
- A PostgreSQL-compatible connection string (for
SUPABASE_URI) - A Qdrant Cloud account, cluster endpoint, and API key
brew install tesseract
brew install ollamaStart Ollama service (if not already running):
ollama servePull the model currently used by this project:
ollama pull qwen2.5:7bThis project stores vectors in Qdrant Cloud and requires three values:
QDRANT_ENDPOINT: your cluster URLQDRANT_API_KEY: API key for that clusterCOLLECTION_NAME: target collection (for exampleknowledge_base)
- Go to Qdrant Cloud and create an account.
- Create a new cluster (free tier is fine for development).
- Copy the cluster endpoint URL.
- Generate an API key in the cluster security/settings section.
- Choose a collection name and set it in your environment file.
From the project root:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pipInstall core dependencies (if you do not already have a pinned requirements file):
pip install -r requirements.txtCreate a .env file in the project root (do not commit secrets):
SUPABASE_URI=postgresql://<user>:<password>@<host>/<db>?sslmode=require
QDRANT_API_KEY=<your_qdrant_api_key>
QDRANT_ENDPOINT=https://<your-cluster-id>.<region>.cloud.qdrant.io
COLLECTION_NAME=knowledge_baseNotes:
- The app loads
.envin Django settings. - The KB config also attempts to load
config/.env.local; keep variables in.envfor normal app execution, and optionally duplicate them intoconfig/.env.localif you run service modules independently.
Apply migrations and start the server:
python manage.py migrate
python manage.py createsuperuser
python ../manage.py runserverOpen:
- Home:
http://127.0.0.1:8000/ - Admin:
http://127.0.0.1:8000/admin/
POST /api/embed/- Ingest and index uploaded documents into QdrantPOST /api/rag/- Execute streaming RAG answer pipeline
This repo supports two architecture options for answer generation.
Current code path in apps/kb/services/llm_generation_05.py:
- Uses
ChatOllama(model="qwen2.5:7b", temperature=0) - Keeps inference local (no third-party LLM API required)
- Requires Ollama daemon + downloaded model
Recommended when:
- You want local/offline inference
- You want to avoid per-token API cost
- You are comfortable running models on local hardware
OpenAI is not wired in the current code, but you can switch by replacing the ChatOllama client with a LangChain OpenAI client.
Typical requirements:
OPENAI_API_KEYin.env- Install provider package (for example
langchain-openai) - Update the LLM initialization in
apps/kb/services/llm_generation_05.py
Benefits:
- No local model hosting
- Easy scaling and model upgrades
Trade-offs:
- Network dependency
- Ongoing API usage cost
- External data processing considerations
The following models are referenced by the current implementation:
-
Generation model (Ollama):
qwen2.5:7b
-
Dense embedding model (Hugging Face):
BAAI/bge-large-en-v1.5
-
Sparse retrieval model:
Qdrant/bm25
-
Re-ranker model (CrossEncoder):
BAAI/bge-reranker-large
First-time startup can download model artifacts and may take several minutes depending on network and hardware.
- Do not commit
.envwith real keys. - Rotate any API keys that were ever exposed in repository history.
- Use separate development/staging/production credentials.
-
Connection error to Qdrant:- Verify
QDRANT_ENDPOINTandQDRANT_API_KEY. - Confirm your cluster is running and reachable.
- Verify
-
Ollama model not found:- Run
ollama pull qwen2.5:7b. - Ensure
ollama serveis active.
- Run
-
OCR not working:- Confirm Tesseract is installed (
tesseract --version).
- Confirm Tesseract is installed (
-
Database connection issues:- Validate
SUPABASE_URIformat and SSL parameters.
- Validate
