A local, from-scratch Retrieval-Augmented Generation (RAG) API. It stores personal profile text in a vector database, retrieves the most relevant chunks for a question, and uses a local LLM (via Ollama) to generate a grounded answer — all running on your own machine, no external API calls.
This started as a learning project to understand how RAG actually works under the hood: chunking, embeddings, retrieval, prompt augmentation, and generation.
Retrieval-Augmented Generation combines a retrieval step with a generative model so the LLM answers using your own data instead of guessing from what it was trained on:
- Retrieval — search a knowledge base (here, a ChromaDB vector store) for the chunks most relevant to the question.
- Augmentation — merge those retrieved chunks with the original question into a single prompt, so the model has the exact context it needs.
- Generation — send that augmented prompt to the LLM, which answers using only the provided context.
profile.txt— a plain-text personal profile, split into chunks by blank line (paragraph). (Not included in this repo — it's.gitignored since it contains real personal info. Add your own to run this locally.)build_knowledge.py— readsprofile.txt, chunks it, generates embeddings via Ollama'snomic-embed-textmodel, and stores everything in a persistent ChromaDB collection (./chroma_db).main.py— a single-user FastAPI app with oneGET /askendpoint. It embeds the question, retrieves the top 2 matching chunks, builds an augmented prompt, and sends it to a localqwen3:4bmodel via Ollama for a grounded answer.MultiUser.py— an extended version that supports multiple people's profiles in the same collection. Adds aPOST /documentsendpoint to submit a profile under auser_name, and letsGET /askfilter retrieval byuserso each person only gets answers grounded in their own data.
- FastAPI — web framework for the API, with auto-generated Swagger UI for testing.
- Uvicorn — ASGI server that runs the FastAPI app.
- ChromaDB — vector database for storing and searching text via embeddings.
- Ollama — runs local models for both embeddings (
nomic-embed-text) and generation (qwen3:4b), so nothing leaves your machine.
-
Install and start Ollama, then pull the models this project uses:
ollama pull nomic-embed-text ollama pull qwen3:4b
-
Create a virtual environment and install dependencies:
python3 -m venv venv source venv/bin/activate pip install fastapi uvicorn chromadb ollama pydantic -
Add your profile data: Create a
profile.txtin the project root with your own bio, written as paragraphs (separated by blank lines) — each paragraph becomes one retrievable chunk. -
Build the knowledge base:
python build_knowledge.py
This embeds and stores your profile chunks in
./chroma_db. -
Run the API:
uvicorn main:app --reload
For the multi-user version instead:
uvicorn MultiUser:app --reload
Once the server is running, open http://127.0.0.1:8000/docs in your browser. Swagger UI lists all available endpoints and lets you send requests and see responses directly, without needing curl or a separate client.
GET /ask?question=...— retrieves the top 2 relevant chunks, augments the prompt, and returns a generated answer along with the context used.
POST /documents— submit a profile:{"user_name": "...", "content": "..."}. The content is chunked and stored withuser_nameas metadata.GET /ask?question=...&user=...— same as above, but ifuseris provided, retrieval is filtered to that user's chunks only.
- Everything runs locally — Ollama serves both the embedding model and the chat model on
http://localhost:11434. chroma_db/is generated output (rebuild it any time withbuild_knowledge.py) and is.gitignored, along withvenv/,__pycache__/, andprofile.txt.