Minimal RAG: Ollama embeddings + cosine similarity in SQLite. No vector database. ~150 lines, standard library only.
Most RAG stacks pull in a vector database (Chroma, Pinecone, Qdrant, FAISS), a web framework, and a dozen dependencies. For small-to-medium corpora you don't need any of that. This is the whole thing: embeddings come from a local Ollama server, vectors and text live in one SQLite file, and search is plain cosine similarity in Python.
- Zero dependencies — pure Python standard library (
sqlite3,urllib,json,math). - One file, readable in one sitting — easy to audit, fork, and embed in another project.
- Local & private — nothing leaves your machine.
- Portable index — the whole knowledge base is a single
.dbfile you can copy around.
ollama pull nomic-embed-text # embedding model
python example.pyQuery: How far from Earth does the telescope orbit, and at which point?
[0.807] jwst: The James Webb Space Telescope launched on 25 December 2021 ...
Generated answer:
The telescope orbits the Sun at the second Lagrange point (L2),
about 1.5 million kilometres from Earth.
from sqlite_rag import RAG
rag = RAG("mydocs.db")
rag.ingest_file("notes.md") # or rag.ingest("some text", source="x")
for hit in rag.search("how do I reset it?", k=4):
print(hit["score"], hit["source"], hit["text"][:80])- Ingest — text is split into overlapping chunks; each chunk is embedded via
Ollama's
/api/embeddingsand stored in SQLite together with its vector (as JSON). - Search — the query is embedded and compared against every stored vector with cosine similarity, computed in Python; the top-k chunks are returned.
That's it. No index structures, no ANN — a linear scan is plenty for thousands of chunks and keeps the code trivial to understand.
nomic-embed-text detail: the model expects task prefixes. This library adds
search_document:to stored chunks andsearch_query:to queries automatically — forgetting these is a common cause of poor recall.
| Variable | Default |
|---|---|
OLLAMA_URL |
http://127.0.0.1:11434 |
EMBED_MODEL |
nomic-embed-text |
CHAT_MODEL (example only) |
qwen2.5:7b |
- Linear scan: fine up to ~tens of thousands of chunks, then add an ANN index.
- Naive fixed-size chunking — swap in your own splitter if structure matters.
- No re-ranking; add a cross-encoder if you need higher precision.
MIT
Part of a small collection of local-first AI and ESP32 / maker tools:
- sqlite-memory — persistent long-term memory for local LLMs
- ollama-doctor — find out why Ollama is slow (CPU offload / VRAM)
- local-voice-edge — ESP32 voice assistant + local STT→LLM→TTS server
- axs15231b-landscape-lvgl — 3.5" AXS15231B QSPI panel in landscape with LVGL
- guition-esp32p4-lvgl9 — Guition 7" ESP32-P4 + LVGL 9 baseline
- orcaslicer-cli-cookbook — OrcaSlicer from the command line + fixes
⭐ If this saved you time, a star helps others find it.