Stap-voor-stap uitleg: Eenvoudige RAG-tool met Ollama op je PC/laptop

Ik bouw vaak zelf kleine AI-projectjes, gewoon omdat ik het leuk vind om te snappen hoe iets écht werkt. Daarbij gebruik ik soms betaalde API’s, maar experimenteer ik ook veel met open-source modellen en lokale AI-tools op mijn eigen PC. Eén van mijn favoriete mini-projectjes van de laatste tijd? Een simpele RAG (Retrieval Augmented Generation) bouwen die volledig lokaal draait.

Wat is RAG?

RAG staat voor Retrieval Augmented Generation. Klinkt ingewikkeld, maar het is eigenlijk superlogisch: geef een AI eerst relevante informatie uit je eigen documenten, en laat hem daarna pas antwoord geven.

Goed om te weten: Bij RAG wordt het model niet opnieuw getraind. Je geeft tijdelijk extra context mee tijdens het beantwoorden van een vraag

Wat is Ollama?

Ollama is een gratis programma waarmee je AI-modellen zoals Llama, Mistral en Gemma lokaal op je eigen computer draait. Na het installeren van Ollama en het downloaden van een model kun je volledig offline werken, zonder abonnement of externe AI-dienst. Lokale modellen zijn vaak kleiner en hebben daardoor meestal minder algemene kennis dan de nieuwste modellen van bijvoorbeeld ChatGPT, maar ze zijn snel, flexibel en ideaal om mee te experimenteren, bijvoorbeeld voor RAG-projecten. Met één commando, zoals ollama pull llama3.2, download je een model en kun je direct chatten via de terminal of browser.

Een voorbeeld van RAG

Jouw document: een PDF-handleiding van 40 pagina’s van de Sony A7 III op je eigen laptop.

Jouw vraag aan een lokaal Ollama-model: “Hoe plaats ik de geheugenkaart?”

Zonder RAG: Ollama probeert te gokken op basis van algemene kennis. Misschien geeft het model een deels fout antwoord of mist het specifieke stappen uit de handleiding. De exacte Sony-handleiding zat namelijk niet in de training van het model.

Met RAG:

  1. Het systeem zoekt eerst in de handleiding naar stukken over geheugenkaarten
  2. Alleen de relevante tekst wordt meegestuurd als context
  3. Het model geeft daarna een gericht antwoord op basis van die handleiding
  4. Bijvoorbeeld: Klikt de lens vast in de gleuf tot de kaart op haar plaats vastklikt.

Hoe werkt het in 4 stappen?

  1. Het document wordt opgeknipt in kleine stukjes tekst (chunking)
  2. Elk stukje krijgt een numerieke representatie, ook wel embedding genoemd
  3. Bij een vraag zoekt het systeem naar de meest relevante stukjes tekst (retrieval)
  4. Die relevante context wordt meegestuurd naar het AI-model voor het antwoord (generation)

Waar bedrijven RAG voor gebruiken?

Bedrijven gebruiken RAG om AI te laten werken met hun eigen documenten en informatie. Denk aan handleidingen, interne regels, contracten, productinformatie of kennisbanken. In plaats van dat medewerkers zelf door tientallen bestanden moeten zoeken, kan een AI-systeem eerst de juiste informatie ophalen en daarna direct antwoord geven op een vraag.

Bijvoorbeeld: een supportmedewerker vraagt:
“Wat zijn de regels rondom het bewaren van klantgegevens?”

Het systeem zoekt dan eerst in interne documenten, zoals een GDPR-handleiding of compliance-document, en gebruikt alleen die relevante informatie voor het antwoord.

Ook marketingteams gebruiken RAG. Bijvoorbeeld om nieuwe productteksten te maken op basis van eerdere productomschrijvingen uit een eigen database.

Het grote voordeel van RAG is dat antwoorden gebaseerd zijn op actuele bedrijfsinformatie, in plaats van alleen op algemene kennis van een AI-model. Dat scheelt tijd, vermindert fouten en maakt het makkelijker om met interne of gevoelige informatie te werken. Vooral bij grotere organisaties, supportafdelingen, legal teams en interne kennisbanken wordt RAG daarom steeds populairder.

Wat gaan we nu doen?

We gaan nu stap voor stap zelf een simpele lokale RAG-tool bouwen die vragen kan beantwoorden over één document. Alles draait lokaal op je eigen computer met Ollama. In dit voorbeeld gebruiken we één PDF-bestand, halen we daar relevante stukken tekst uit en laten we een lokaal AI-model antwoord geven op basis van die informatie.

We bouwen bewust geen ingewikkeld enterprise-systeem met meerdere databases, agents of geavanceerde frameworks. Het doel van dit project is vooral om te begrijpen hoe RAG in de basis werkt. Zodra je dat snapt, wordt het ook veel duidelijker hoe grotere AI-tools achter de schermen functioneren.

En ja: technisch gezien zou je ook gewoon een PDF kunnen uploaden naar ChatGPT, Claude, Copilot of Perplexity en daar dezelfde vraag stellen. Maar daar gaat het nu juist niet om. We willen begrijpen wat er onder de motorkap gebeurt, hoe documenten worden verwerkt, hoe retrieval werkt en hoe je zoiets zelf lokaal kunt bouwen zonder afhankelijk te zijn van een externe AI-dienst.

Disclaimer: Dit artikel is een leerproject om de basis van RAG te begrijpen, perfect voor beginners, maar geen basis om op te schalen naar productie. Het laat zien hoe je lokaal een simpel systeem bouwt voor één document, niet hoe je een robuuste enterprise-oplossing maakt met meerdere bestanden, databases of geavanceerde retrieval.

Stap 1: Installeer Ollama

We beginnen met Ollama. Daarmee draaien we straks lokaal een AI-model op onze eigen computer.

Ga naar: Ollama en download de versie voor jouw besturingssysteem en installeer het programma.

Na de installatie openen we een terminalvenster:

  • Windows: open het Startmenu en typ cmd
  • Mac: open Terminal
  • Linux: open je terminal-app

Typ daarna dit commando en druk op Enter:

ollama --version

Krijg je een versienummer terug? Dan werkt Ollama correct.

Stap 2: Download een lokaal AI-model

Nu gaan we een model downloaden dat Ollama straks gebruikt voor het beantwoorden van vragen.

Open opnieuw je terminal of PowerShell en voer uit:

ollama pull llama3.2

Ollama downloadt nu automatisch het model. Dit kan even duren afhankelijk van je internetverbinding.

Na het downloaden kun je testen of alles werkt:

ollama run llama3.2

Je kunt nu direct chatten met het model vanuit je terminal, zoals je op het screenshot kan zien.

Stap 3: Installeer Python en maak een projectmap

Voor onze simpele RAG-tool gebruiken we Python. Daarmee kunnen we:

  • PDF’s uitlezen
  • embeddings maken
  • tekst doorzoeken
  • en communiceren met Ollama

Heb je Python nog niet geïnstalleerd? Download dan eerst Python via: Python.org

Let tijdens de installatie goed op dat je het vinkje Add Python to PATH aanvinkt.

Maak daarna op je bureaublad een nieuwe map aan, bijvoorbeeld:

rag-project

Open die map, klik bovenin op de adresbalk, typ:

cmd

Druk op Enter. Er opent nu automatisch een terminal in die map. We maken eerst een aparte Python-omgeving voor dit project. Dat voorkomt gedoe met andere Python-projecten of libraries op je computer.

Voer uit:

python -m venv venv

Activeer daarna de omgeving:

Windows:

venv\Scripts\activate

Mac/Linux:

source venv/bin/activate

Zie je (venv) links in je terminal verschijnen? Dan werkt het goed.

Stap 4: Libraries installeren

Installeer daarna de libraries die we nodig hebben:

pip install pymupdf sentence-transformers faiss-cpu ollama

(dit kan even duren. Schrik niet van een paar ‘warnings’, ga pas door met de volgende stap als je iets als (venv) C:\Users\office\Desktop\rag-project> ziet en het installeren voltooid is)

Dit installeren we:

  • pymupdf: om PDF-bestanden uit te lezen
  • sentence-transformers: om embeddings te maken
  • faiss-cpu: om snel door embeddings te zoeken
  • ollama: om vanuit Python met Ollama te communiceren

Stap 5: Zet je PDF in de projectmap

Nu gaan we het document toevoegen waar onze RAG-tool straks vragen over kan beantwoorden. Pak een PDF-bestand, bijvoorbeeld de handleiding van een camera, en zet die in je rag-project map.

Donwload het voorbeeldbestand

Je map ziet er straks ongeveer zo uit:

rag-project/
│
├── venv/
└── sony-a7iii-handleiding

In de volgende stap gaan we de tekst uit deze PDF ophalen met Python.

Stap 6: Lees de PDF uit met Python

Nu gaan we de tekst uit de PDF halen. Daarvoor maken we ons eerste Python-bestand. Klik in je rag-project map met de rechtermuisknop en maak een nieuw bestand aan met de naam:

main.py

Open dat bestand in Kladblok, VS Code of een andere editor en plak deze code erin:

import fitz

pdf_path = "sony-a7iii-handleiding.pdf"

doc = fitz.open(pdf_path)

full_text = ""

for page in doc:
    full_text += page.get_text()

print(full_text[:3000])

Sla het bestand daarna op.

Wat doet deze code?

  1. De PDF wordt geopend
  2. Alle tekst uit de pagina’s wordt verzameld
  3. De eerste 3000 tekens worden geprint in de terminal

We testen hiermee eerst of we de handleiding correct kunnen uitlezen.

Voer daarna in je terminal uit:

python main.py

Zie je tekst uit je PDF verschijnen? Dan werkt het correct. Zo niet: dan komt dit waarschijnlijk omdat het .pdf document niet in de map staat of dat het bestand een andere naam heeft. De bestandsnaam moet 100% overeenkomen met de naam. Let ook goed op dat het bestand niet sony-a7iii-handleiding.pdf heet, maar gewoon sony-a7iii-handleiding, anders kan je computer het zien als sony-a7iii-handleiding.pdf.pdf. Zie screenshot:

Stap 7: De tekst opdelen in kleine stukken (chunking)

Nu we de volledige tekst uit de PDF kunnen uitlezen, gaan we die opdelen in kleinere stukken tekst, ook wel chunks genoemd. Een AI-model werkt beter met kleine relevante stukken tekst dan met een complete handleiding van tientallen pagina’s tegelijk. Later gaan we namelijk zoeken naar de meest relevante chunks voor een vraag.

Vervang je huidige code in main.py door dit:

import fitz

pdf_path = "sony-a7iii-handleiding.pdf"

doc = fitz.open(pdf_path)

full_text = ""

for page in doc:
    full_text += page.get_text()

chunk_size = 500

chunks = []

for i in range(0, len(full_text), chunk_size):
    chunk = full_text[i:i + chunk_size]
    chunks.append(chunk)

print(chunks[0])

Wat gebeurt hier?

  1. Eerst lezen we opnieuw alle tekst uit de PDF
  2. Daarna knippen we de tekst op in stukken van 500 tekens
  3. Alle chunks worden opgeslagen in een lijst
  4. Tot slot printen we de eerste chunk

Voer opnieuw uit:

python main.py

Zie je een stuk tekst uit de handleiding verschijnen? Dan werkt chunking correct.

Stap 8: Embeddings maken van onze chunks

Nu gaan we embeddings maken van alle chunks.

Klinkt ingewikkeld, maar het idee is simpel:
we zetten tekst om naar numerieke representaties die een AI-model kan begrijpen en vergelijken.

Daardoor kan ons systeem straks zoeken naar stukken tekst die inhoudelijk lijken op een vraag.

Vervang de code in main.py door dit:

import fitz
from sentence_transformers import SentenceTransformer

pdf_path = "sony-a7iii-handleiding.pdf"

doc = fitz.open(pdf_path)

full_text = ""

for page in doc:
    full_text += page.get_text()

chunk_size = 500

chunks = []

for i in range(0, len(full_text), chunk_size):
    chunk = full_text[i:i + chunk_size]
    chunks.append(chunk)

model = SentenceTransformer("all-MiniLM-L6-v2")

embeddings = model.encode(chunks)

print(embeddings.shape)

Wat gebeurt hier?

  1. We laden een embedding-model in
  2. Alle chunks worden omgezet naar embeddings
  3. Elke chunk krijgt een numerieke representatie
  4. Uiteindelijk printen we de vorm van de embedding-array

Voer opnieuw uit:

python main.py

De eerste keer kan dit even duren, omdat het embedding-model automatisch wordt gedownload.

Zie je uiteindelijk iets zoals:

(120, 384)

Dan werkt het goed.

Dat betekent bijvoorbeeld:

  • 120 chunks
  • met elk 384 numerieke waarden per embedding.

Tip: Foutmeldingen kan je voor dit voorbeeld gewoon negeren, zolang de uiteindelijke output maar iets is als (120, 384).

Stap 9: Zoek de meest relevante stukken tekst bij een vraag

Nu gaan we het interessante deel bouwen: retrieval.

We geven straks een vraag op, zetten die ook om naar een embedding, en zoeken daarna welke chunks uit de handleiding daar het meest op lijken.

Vervang de code in main.py door dit:

import fitz
import faiss
import numpy as np

from sentence_transformers import SentenceTransformer

pdf_path = "sony-a7iii-handleiding.pdf"

doc = fitz.open(pdf_path)

full_text = ""

for page in doc:
    full_text += page.get_text()

chunk_size = 500

chunks = []

for i in range(0, len(full_text), chunk_size):
    chunk = full_text[i:i + chunk_size]
    chunks.append(chunk)

model = SentenceTransformer("all-MiniLM-L6-v2")

embeddings = model.encode(chunks)

embeddings = np.array(embeddings).astype("float32")

index = faiss.IndexFlatL2(embeddings.shape[1])

index.add(embeddings)

question = "Hoe plaats ik de geheugenkaart?"

question_embedding = model.encode([question])

question_embedding = np.array(question_embedding).astype("float32")

distances, indices = index.search(question_embedding, k=3)

print("Vraag:")
print(question)

print("\nMeest relevante chunks:\n")

for i in indices[0]:
    print(chunks[i])
    print("\n-----------------\n")

Wat gebeurt hier?

  • We maken een zoekindex met FAISS
  • De vraag krijgt ook een embedding
  • Daarna zoeken we naar de 3 chunks die inhoudelijk het meest lijken op de vraag
  • Uiteindelijk printen we de relevante stukken tekst uit de handleiding

Voer opnieuw uit:

python main.py

Zie je nu stukken tekst verschijnen over het plaatsen van SD-kaarten en geheugenkaartgleuven? Dan werkt retrieval correct.

Stap 10: Laat Ollama antwoord geven op basis van de gevonden chunks

Nu maken we van onze retrieval-opstelling een echte simpele RAG-tool.

Tot nu toe vonden we alleen relevante stukken tekst uit de handleiding. In deze stap sturen we die context ook daadwerkelijk naar Ollama, zodat het model een normaal antwoord kan formuleren.

Vervang de code in main.py door dit:

import fitz
import faiss
import numpy as np
import ollama

from sentence_transformers import SentenceTransformer

pdf_path = "sony-a7iii-handleiding.pdf"

doc = fitz.open(pdf_path)

full_text = ""

for page in doc:
    full_text += page.get_text()

chunk_size = 500

chunks = []

for i in range(0, len(full_text), chunk_size):
    chunk = full_text[i:i + chunk_size]
    chunks.append(chunk)

model = SentenceTransformer("all-MiniLM-L6-v2")

embeddings = model.encode(chunks)

embeddings = np.array(embeddings).astype("float32")

index = faiss.IndexFlatL2(embeddings.shape[1])

index.add(embeddings)

question = "Hoe plaats ik de geheugenkaart?"

question_embedding = model.encode([question])

question_embedding = np.array(question_embedding).astype("float32")

distances, indices = index.search(question_embedding, k=3)

context = ""

for i in indices[0]:
    context += chunks[i] + "\n"

prompt = f"""
Gebruik alleen onderstaande context om de vraag te beantwoorden.

Context:
{context}

Vraag:
{question}
"""

response = ollama.chat(
    model="llama3.2",
    messages=[
        {
            "role": "user",
            "content": prompt
        }
    ]
)

print("\nAntwoord van Ollama:\n")

print(response["message"]["content"])

Wat gebeurt hier?

  • We zoeken opnieuw de meest relevante chunks
  • Die chunks voegen we samen als context
  • Daarna sturen we de vraag + context naar Ollama
  • Het model formuleert vervolgens een normaal antwoord

Voer opnieuw uit:

python main.py

Als alles goed werkt, krijg je nu geen losse chunks meer terug, maar een echt AI-antwoord op basis van de handleiding.

antwoord RAG

Wat hebben we nu eigenlijk gebouwd?

We hebben een simpele lokale RAG-tool gebouwd die:

  • Een PDF uitleest,
  • Tekst omzet naar embeddings,
  • Relevante informatie opzoekt,
  • …en daarna een lokaal AI-model antwoord laat geven op basis van die context.

Alles draaide lokaal op de computer:

  • Zonder externe AI-API,
  • Zonder cloudvector database,
  • Zonder ingewikkelde frameworks.

Natuurlijk is dit nog een basisversie. Grote RAG-systemen gebruiken vaak:

  • Slimmere chunking,
  • Betere retrieval-methodes,
  • Meerdere documenten,
  • Vector databases,
  • Metadata,
  • Reranking,
  • Geheugen,
  • Geavanceerde prompts.

Maar de kern van RAG? Die heb je nu zelf gebouwd.

Hoe zou dit eruitzien binnen een echt bedrijf?

De RAG-tool die we hier gebouwd hebben is vooral bedoeld om de basis te begrijpen. We werken lokaal, gebruiken één PDF en bewaren alles tijdelijk in het geheugen. Dat is perfect voor een experiment of proof of concept, maar grotere organisaties bouwen dit meestal uitgebreider op.

In een echte bedrijfsomgeving werk je vaak met duizenden documenten tegelijk, meerdere gebruikers en continue updates van informatie. In plaats van één lokaal script gebruiken bedrijven daarom meestal een combinatie van vector databases, document-indexering en krachtigere retrieval-methodes om snel relevante informatie terug te vinden.

Ook de AI-modellen verschillen vaak. Sommige bedrijven draaien open-source modellen lokaal of op eigen servers, terwijl anderen gebruikmaken van API’s van bijvoorbeeld OpenAI, Claude of Gemini. Frameworks zoals LangChain of LlamaIndex worden vaak toegevoegd om grotere RAG-systemen beter te beheren.

Toch blijft de kern exact hetzelfde als in ons simpele voorbeeld: documenten opdelen, embeddings maken, relevante context ophalen en die context meegeven aan een taalmodel. Dat basisprincipe verandert eigenlijk nauwelijks!

Plaats een reactie