RAGMill
A lightweight, zero-config local pipeline engine for AI data ingestion, semantic chunking, embeddings, vector search, and retrieval-augmented chat — fully offline by default (no API keys, ever), with optional cloud backends (Pinecone, Qdrant), a REST API, a standalone setup UI, and Docker support.
Install
pip install ragmill # core only (txt/md), zero dependencies
pip install ragmill[all] # everything (PDF, DOCX, embeddings, chat, server, cloud backends)
pip install ragmill[embeddings] # + local ONNX embeddings
pip install ragmill[chat] # + local LLM for retrieval-augmented answers (no API key)
pip install ragmill[chat-gemini] # + Gemini as the chat backend (needs GEMINI_API_KEY)
pip install ragmill[chat-openai] # + ChatGPT as the chat backend (needs OPENAI_API_KEY)
pip install ragmill[pinecone] # + Pinecone cloud backend
pip install ragmill[qdrant] # + Qdrant cloud backend
pip install ragmill[server] # + FastAPI REST API
pip install ragmill[config-ui] # + standalone setup UI (writes .env)
Quick start
Ingest + chunk + embed + search (local SQLite)
Note: This example requires the
embeddingsextra:pip install ragmill[embeddings]
from ragmill import RAGEngine
from ragmill.embeddings import EmbeddingModel
from ragmill.vector_store import VectorStore
chunks = RAGEngine().execute_pipeline("./my_documents")
model = EmbeddingModel()
vectors = model.embed([c["content"] for c in chunks])
store = VectorStore("my_store.db")
store.add(chunks, vectors)
query = model.embed(["how does the overlap work?"])[0]
for r in store.search(query, top_k=3):
print(r["score"], r["metadata"]["filename"], "->", r["content"][:80])
Keep a store in sync with a folder
from ragmill import RAGEngine
from ragmill.embeddings import EmbeddingModel
from ragmill.vector_store import VectorStore
from ragmill.sync import sync_directory
engine = RAGEngine()
model = EmbeddingModel()
store = VectorStore("my_store.db")
result = sync_directory("./my_documents", engine, model, store)
print(result) # {"added": 2, "updated": 1, "skipped": 40, "deleted": 1}
Ask questions, get grounded answers
Retrieval-augmented answer generation, with a choice of three backends —
selected via RAGMILL_CHAT_BACKEND (default local):
| Backend | Install | Needs a key? | Notes |
|---|---|---|---|
local (default) |
ragmill[chat] |
No | Qwen2.5-1.5B-Instruct via llama-cpp-python. Downloads once (~1.1GB) to ~/.cache/ragmill/models, then runs fully offline. |
gemini |
ragmill[chat-gemini] |
GEMINI_API_KEY (or GOOGLE_API_KEY) |
Google's Gemini API. Best answer quality if you're online and have a key. |
openai |
ragmill[chat-openai] |
OPENAI_API_KEY |
OpenAI's Chat Completions API (ChatGPT). |
pip install ragmill[chat] # local model (default, no key)
ragmill chat # interactive terminal Q&A over your ingested docs
# Switch to Gemini
pip install ragmill[chat-gemini]
export RAGMILL_CHAT_BACKEND=gemini
export GEMINI_API_KEY=xxxxxxxx
ragmill chat
# Or ChatGPT
pip install ragmill[chat-openai]
export RAGMILL_CHAT_BACKEND=openai
export OPENAI_API_KEY=xxxxxxxx
ragmill chat
from ragmill.chat import generate_answer
answer = generate_answer("what does the overlap parameter do?", results)
All three backends share the same generate_answer(query, chunks) call — the
backend is picked at call time from RAGMILL_CHAT_BACKEND, so switching is
just an env var change, no code change. The setup UI
below lets you pick a backend and enter its key without touching the
environment by hand.
Per-backend overrides:
- Local:
RAGMILL_CHAT_MODEL_REPO,RAGMILL_CHAT_MODEL_FILE,RAGMILL_CHAT_N_CTX - Gemini:
RAGMILL_GEMINI_MODEL(defaultgemini-flash-latest) - OpenAI:
RAGMILL_OPENAI_MODEL(defaultgpt-4o-mini)
Use a cloud vector store
Set environment variables and the store backend switches automatically:
export RAGMILL_STORE_TYPE=pinecone
export RAGMILL_PINECONE_API_KEY=xxxxxxxx
export RAGMILL_PINECONE_ENVIRONMENT=us-west1-gcp
export RAGMILL_PINECONE_INDEX_NAME=ragmill
from ragmill.vector_store import store_from_config
from ragmill.config import RAGMillConfig
config = RAGMillConfig.from_env()
store = store_from_config(config) # returns a PineconeVectorStore
Or for Qdrant (local via Docker, or a managed Qdrant Cloud cluster):
export RAGMILL_STORE_TYPE=qdrant
export RAGMILL_QDRANT_URL=http://localhost:6333 # or your cloud cluster URL
export RAGMILL_QDRANT_API_KEY=xxxxxxxx # required for Qdrant Cloud
export RAGMILL_QDRANT_COLLECTION_NAME=ragmill
Payload indexes (filename, source_file) are created automatically the
first time a collection is set up — Qdrant Cloud rejects filtered
search/delete/sync operations without them, while local/self-hosted Qdrant
is more lenient about it.
Migrate between backends
Export your local SQLite store to JSONL, then import into a cloud store:
# 1. Export from SQLite
ragmill export ./backup.jsonl
# 2. Switch env to point at Pinecone
export RAGMILL_STORE_TYPE=pinecone
export RAGMILL_PINECONE_API_KEY=xxx
# 3. Import into Pinecone
ragmill import ./backup.jsonl
REST API
pip install ragmill[server]
ragmill serve
# or: uvicorn ragmill.server:app --host 0.0.0.0 --port 8000
| Method | Path | Description |
|---|---|---|
| POST | /ingest |
Ingest a directory |
| POST | /sync |
Incremental sync |
| POST | /search |
Search chunks |
| POST | /chat |
Ask a question, get a grounded answer |
| GET | /count |
Number of stored chunks |
| POST | /export |
Export store to JSONL |
| POST | /import |
Import JSONL into store |
| GET | /health |
Health check |
| GET | / |
Minimal terminal-style chatbox (test /chat in a browser) |
Standalone setup UI
A separate, minimal web UI for filling in optional config — cloud vector
store credentials, which chat backend to use (local/Gemini/ChatGPT) and its
key, or an override for the local chat model — without hand-editing
anything. It runs as its own server/process (a different port than
ragmill serve), so it's clearly a one-time setup tool independent of
wherever RAGMill actually runs as a dependency.
pip install ragmill[config-ui]
ragmill configure # http://127.0.0.1:8090 by default — binds to localhost only
Fill in what you need and click "Save configuration" — it writes only the
fields you filled in to a local .env file (via python-dotenv, preserving
any unrelated lines already there). RAGMill loads that .env automatically
on the next run. Remember to add .env to .gitignore — nothing is ever
written into source code.
Docker
# SQLite backend
docker compose --profile sqlite up
# Qdrant backend (spins up a Qdrant container too)
docker compose --profile qdrant up
CLI
ragmill ingest ./docs # Ingest + embed files
ragmill sync ./docs # Incremental sync
ragmill search "query" # Search
ragmill chat # Interactive Q&A over stored chunks (local LLM)
ragmill count # Chunk count
ragmill serve # Start API
ragmill export ./out.jsonl # Export
ragmill import ./in.jsonl # Import
ragmill configure # Standalone setup UI (writes .env)
ragmill --version # Print the installed version
Configuration
All settings are controlled via environment variables (or a .env file —
see the setup UI above):
| Variable | Default | Description |
|---|---|---|
RAGMILL_STORE_TYPE |
sqlite |
sqlite, pinecone, or qdrant |
RAGMILL_SQLITE_PATH |
./ragmill.db |
Path to SQLite database file |
RAGMILL_EMBEDDING_MODEL |
Xenova/all-MiniLM-L6-v2 |
Hugging Face model for embeddings |
RAGMILL_EMBEDDING_DIM |
384 |
Embedding vector dimension |
RAGMILL_PINECONE_API_KEY |
— | Pinecone API key |
RAGMILL_PINECONE_ENVIRONMENT |
— | Pinecone environment |
RAGMILL_PINECONE_INDEX_NAME |
ragmill |
Pinecone index name |
RAGMILL_QDRANT_URL |
— | Qdrant server/cluster URL |
RAGMILL_QDRANT_API_KEY |
— | Qdrant API key (required for Qdrant Cloud) |
RAGMILL_QDRANT_COLLECTION_NAME |
ragmill |
Qdrant collection name |
RAGMILL_CHAT_BACKEND |
local |
local, gemini, or openai |
RAGMILL_CHAT_MODEL_REPO |
Qwen/Qwen2.5-1.5B-Instruct-GGUF |
Local chat model's Hugging Face repo |
RAGMILL_CHAT_MODEL_FILE |
qwen2.5-1.5b-instruct-q4_k_m.gguf |
Local chat model's GGUF filename |
RAGMILL_CHAT_N_CTX |
4096 |
Local chat model's context window (tokens) |
GEMINI_API_KEY (or GOOGLE_API_KEY) |
— | Required when RAGMILL_CHAT_BACKEND=gemini |
RAGMILL_GEMINI_MODEL |
gemini-flash-latest |
Gemini model name |
OPENAI_API_KEY |
— | Required when RAGMILL_CHAT_BACKEND=openai |
RAGMILL_OPENAI_MODEL |
gpt-4o-mini |
OpenAI model name |
RAGMILL_CHUNK_SIZE |
500 |
Max chunk size in characters |
RAGMILL_OVERLAP |
50 |
Chunk overlap in characters |
RAGMILL_HOST |
127.0.0.1 |
Server bind address |
RAGMILL_PORT |
8000 |
Server port |
Supported file types
.txt, .md, .log, .rst, .pdf, .docx
Project structure
ragmill/
├── src/ragmill/
│ ├── __init__.py # Public API exports
│ ├── engine.py # RAGEngine: ingestion + chunking
│ ├── parsers.py # PDF/DOCX text extractors
│ ├── embeddings.py # Local ONNX embedding model
│ ├── chat.py # Local LLM answer generation (llama-cpp-python)
│ ├── vector_store.py # BaseVectorStore ABC + SQLiteVectorStore
│ ├── pinecone_store.py # Pinecone backend (optional)
│ ├── qdrant_store.py # Qdrant backend (optional)
│ ├── config.py # RAGMillConfig: env/.env-based configuration
│ ├── sync.py # Incremental directory sync
│ ├── export.py # JSONL export/import for migration
│ ├── server.py # FastAPI REST API + chat UI (optional)
│ ├── static/ # Terminal-style chatbox HTML for server.py's `/`
│ ├── config_ui.py # Standalone setup UI, separate server (optional)
│ ├── config_ui_static/ # Setup UI's HTML form
│ └── __main__.py # CLI entry point
├── tests/
├── docs/ # MkDocs documentation source
├── Dockerfile
└── docker-compose.yml
Documentation
Full documentation is published at https://abdullahbinaqeel.github.io/RAGMill/.
- Quickstart · Installation · Configuration
- CLI · REST API · Chat
- Vector stores · Migration
- API reference · FAQ
Contributing
Contributions are welcome! Please read CONTRIBUTING.md to get started, and note our Code of Conduct. Found a security issue? Please report it privately via SECURITY.md — not a public issue. Maintainers: see RELEASING.md for the release process.
License
MIT © Abdullah Bin Aqeel
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ragmill-0.3.1.tar.gz.
File metadata
- Download URL: ragmill-0.3.1.tar.gz
- Upload date:
- Size: 238.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b3a13f587fd2e7419d74e9e5e71bf2761f24ed2e931b665a4e96fadbe9df7950
|
|
| MD5 |
2feb4b67c07c5864e5c3931290744b27
|
|
| BLAKE2b-256 |
27f5e3ca6cf1ce2a456d8718508201723aa6c3e2c580a2fa250cf661bfad8bc1
|
Provenance
The following attestation bundles were made for ragmill-0.3.1.tar.gz:
Publisher:
publish.yml on Abdullahbinaqeel/RAGMill
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ragmill-0.3.1.tar.gz -
Subject digest:
b3a13f587fd2e7419d74e9e5e71bf2761f24ed2e931b665a4e96fadbe9df7950 - Sigstore transparency entry: 2218326346
- Sigstore integration time:
-
Permalink:
Abdullahbinaqeel/RAGMill@d5fdc84613d588d44d241a937564d1fa71e62b05 -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/Abdullahbinaqeel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d5fdc84613d588d44d241a937564d1fa71e62b05 -
Trigger Event:
release
-
Statement type:
File details
Details for the file ragmill-0.3.1-py3-none-any.whl.
File metadata
- Download URL: ragmill-0.3.1-py3-none-any.whl
- Upload date:
- Size: 44.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c31c0299465b33b54e397ae0e80e0eedf0206d60fb9ad81ea696c7a3a3282a3a
|
|
| MD5 |
67ee1128721e2a44ef944de06d9bd5be
|
|
| BLAKE2b-256 |
fd85eaefcc401a98240363afaeb435d51dec7004eecf0d5cc427be4e11d07ad7
|
Provenance
The following attestation bundles were made for ragmill-0.3.1-py3-none-any.whl:
Publisher:
publish.yml on Abdullahbinaqeel/RAGMill
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ragmill-0.3.1-py3-none-any.whl -
Subject digest:
c31c0299465b33b54e397ae0e80e0eedf0206d60fb9ad81ea696c7a3a3282a3a - Sigstore transparency entry: 2218326366
- Sigstore integration time:
-
Permalink:
Abdullahbinaqeel/RAGMill@d5fdc84613d588d44d241a937564d1fa71e62b05 -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/Abdullahbinaqeel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d5fdc84613d588d44d241a937564d1fa71e62b05 -
Trigger Event:
release
-
Statement type: