ai-machine-learning

Embeddingmodellen lokaal draaien met Ollama: ik testte cold vs. warm GPU

Geschreven door Mert Batur
Jul 13, 2026
10 leestijd
Embeddingmodellen lokaal draaien met Ollama: ik testte cold vs. warm GPU

Embeddingmodellen lokaal draaien met Ollama: ik testte cold vs. warm GPU

Je kunt embeddingmodellen lokaal draaien met Ollama en stoppen met $0,02 per miljoen tokens aan OpenAI te betalen voor elke chunk die je indexeert. De ruil: jij beheert de GPU, de cold starts en de ops zelf. Ollama serveert ze op poort 11434, zonder API-key. Hier is de volledige workflow, van ollama pull tot een warme vectorzoekopdracht die vragen beantwoordt.

Belangrijkste punten

  • Ollama serveert embeddings lokaal op http://localhost:11434 via POST /api/embed, zonder API-key en voor $0 per token.
  • Gebruik /api/embed (actueel, batch-array); /api/embeddings is verouderd en meestal de bron van 404's.
  • Populaire lokale modellen: nomic-embed-text (768-dim), mxbai-embed-large (1024), bge-m3 (1024), embeddinggemma (768).
  • Laat je embeddingdimensie overeenkomen met je vector-DB-kolom, en pin het model met keep_alive om cold-start-latency te vermijden.

Wat heb je nodig om embeddings lokaal te draaien met Ollama?

Alles wat je nodig hebt om embeddings lokaal te draaien bestaat uit drie onderdelen: een embeddingmodel, de Ollama-server op poort 11434, en een vectorstore om de output in op te slaan. Ollama downloadt en serveert het model; jouw code stuurt tekst naar /api/embed; de vectoren komen terecht in een database zoals pgvector, Qdrant of Chroma. Geen cloud-roundtrip, geen rekening per token.

Met twee commando's heb je binnen een minuut een werkende embedding:

bash
ollama pull nomic-embed-text
curl http://localhost:11434/api/embed -d '{
  "model": "nomic-embed-text",
  "input": "The quick brown fox"
}'

Dat is de hele quickstart. De rest van deze tutorial behandelt de modelkeuze, de store, en de twee valkuilen waar iedereen in trapt: de endpoint-verwarring en de cold-start-penalty.

Stap 1: Ollama installeren en een embeddingmodel downloaden

Installeer Ollama, controleer of de server luistert op poort 11434, en download daarna een embeddingmodel. Ollama draait als achtergrondservice, dus ollama pull nomic-embed-text downloadt de gewichten en de volgende /api/embed-aanroep serveert ze meteen. Embeddingmodellen zijn piepklein vergeleken met chatmodellen, dus dit gaat snel.

bash
# Installatie voor macOS / Linux
curl -fsSL https://ollama.com/install.sh | sh

# Zorg dat de server draait (achtergrondservice op :11434)
ollama serve            # alleen als deze nog niet draait

# Download een embeddingmodel en controleer de server
ollama pull nomic-embed-text
curl http://localhost:11434            # hoort "Ollama is running" terug te geven

Hier komt het leuke stukje: een embeddingmodel zoals nomic-embed-text heeft maar 137M parameters, ongeveer 274 MB om te downloaden, tegenover chatmodellen van meerdere gigabytes. Het laadt in ongeveer een seconde in VRAM. Wil je de volledige lokale-LLM-setup zodat een chatmodel naast je embedder draait? Onze gids over Ollama instellen voor lokale LLM's behandelt dat pad, en een UI voor je lokale Ollama-modellen als je liever klikt dan curlt.

Pro tip: de server moet draaien voordat je een request stuurt. Een geweigerde verbinding op :11434 betekent bijna altijd dat ollama serve niet actief is.

Welk lokaal embeddingmodel moet je downloaden?

Voor de meeste lokale RAG-toepassingen is nomic-embed-text met 768 dimensies de veilige standaardkeuze. Het presteert beter dan OpenAI's oude ada-002 en draait op vrijwel elke hardware. Grijp naar bge-m3 of qwen3-embedding als je meertalige of long-context retrieval nodig hebt, all-minilm voor snelheid op minimale hardware, en embeddinggemma als nieuwere Google-optie. De onderstaande tabel behandelt de huidige Ollama embedding-modelbibliotheek als een serveerbeslissing, niet als kwaliteitsranglijst.

Model (exacte tag)ParametersOutput-dimContextNotities
nomic-embed-text137M7682048 standaard (native 8192, num_ctx verhogen)Populairste lokale embedder; beter dan ada-002
embeddinggemma300M768 (MRL 512/256/128)~2KGoogle; nu een door Ollama aanbevolen model
mxbai-embed-large335M1024512mixedbread.ai; evenaart veel grotere modellen
bge-m3567M10248192BAAI; dense, sparse, multivector, meertalig
snowflake-arctic-embed22-335Mtot 1024512Snowflake; reeks van groottes
granite-embedding30M / 278M384 / 768512IBM; piepklein en klein
qwen3-embedding0.6b/4b/8b1024/2560/4096 (zelf instelbaar)32KBeste open meertalige en code-RAG-optie
all-minilm22M / 33M384256Snelste en kleinste

In de "best ollama embedding model reddit"-threads is de terugkerende consensus nomic-embed-text voor algemene RAG en bge-m3 zodra je meertalig gaat, en dat komt overeen met wat wij zelf gebruiken. Wil je het gerangschikte overzicht met scores over alle providers heen? Dat is de taak van de hub: welk embeddingmodel kies je voor RAG. We slaan MTEB-cijfers hier bewust over; ons artikel over hoe MTEB-scores werken voor RAG legt uit waarom de ranglijst alleen je kan misleiden.

Stap 2: embeddings genereren via /api/embed

Stuur tekst naar POST /api/embed en Ollama geeft L2-genormaliseerde vectoren terug, wat betekent dat elke vector unit-length is zodat cosine-similarity direct werkt. Volgens de Ollama embeddings-documentatie accepteert het huidige endpoint een input-veld dat zowel een enkele string als een array voor batching accepteert, en geeft het {"embeddings": [[...]]} terug.

De ruwe HTTP-aanroep:

bash
curl http://localhost:11434/api/embed -d '{
  "model": "nomic-embed-text",
  "input": ["first chunk", "second chunk", "third chunk"]
}'

In Python is de officiële client één regel per batch:

python
import ollama

resp = ollama.embed(
    model="nomic-embed-text",
    input=["first chunk", "second chunk", "third chunk"],
    options={"num_ctx": 8192},  # verhoog context voor lange chunks
)
vectors = resp["embeddings"]   # lijst van 768-float lijsten, L2-genormaliseerd

Batchen via de input-array is je belangrijkste throughput-hendel. Eén request met 64 chunks verslaat 64 losse requests met afstand, omdat je de overhead per aanroep maar één keer betaalt. Let op de num_ctx-verhoging: nomic-embed-text gebruikt standaard een venster van 2048 tokens, ook al ondersteunt het native 8192, dus lange chunks worden stilletjes afgekapt tenzij je dit verhoogt. Embedding is één stap in de volledige RAG-pipeline waar dit in past; chunking- en retrieval-logica horen daar thuis, niet hier.

/api/embed vs /api/embeddings vs /v1/embeddings: wat is het verschil?

/api/embed is het huidige endpoint; /api/embeddings is de verouderde variant achter de meeste "Ollama embeddings not working"-posts. De legacy-route gebruikt een enkelvoudig prompt-veld en geeft embedding terug (zonder s), terwijl de huidige route input gebruikt, batches accepteert, en embeddings teruggeeft. Een derde route, /v1/embeddings, is OpenAI-compatibel en accepteert een dimensions-parameter.

EndpointStatusInputveldResponseveldBatch input?dimensions-parameter?
/api/embedHuidiginput (string of array)embeddingsJaNee
/api/embeddingsLegacy / verouderdprompt (enkelvoudig)embeddingNeeNee
/v1/embeddingsOpenAI-compatibelinputdata[].embeddingJaJa (Matryoshka)

Krijg je een 404 of een vreemde response-vorm? Dan zit je waarschijnlijk op /api/embeddings (legacy). Schakel over naar /api/embed en lees de embeddings-key in plaats van embedding. Dat ene tekentje laat veel mensen struikelen die oude tutorials kopiëren.

De /v1/embeddings-route is vooral relevant in één specifiek geval: wegmigreren van OpenAI. Omdat deze een dimensions-parameter accepteert, kun je een Matryoshka-geschikt model afknotten naar een doelgrootte, en dat is precies de fix voor de 1536-dimensiemismatch die we hierna behandelen.

Stap 3: je vectoren opslaan en doorzoeken (pgvector, Qdrant of Chroma)

Sla de 768-float vectoren op in een database die nearest-neighbor search ondersteunt, en query dan met cosine-afstand. In onze RAG-builds kiezen we standaard voor Postgres plus pgvector voor teams die al op Postgres draaien, omdat je embeddings dan naast je relationele data blijven staan. Schakel de extensie in, declareer een VECTOR(768)-kolom die overeenkomt met de dimensie van je model, voeg data toe, en query met de <=> cosine-operator.

sql
CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE chunks (
  id     bigserial PRIMARY KEY,
  body   text,
  embedding vector(768)          -- moet overeenkomen met nomic-embed-text
);

-- Voeg een rij toe (embedding komt van ollama.embed)
INSERT INTO chunks (body, embedding) VALUES ('first chunk', '[0.01, -0.02, ...]');

-- Top 5 dichtstbijzijnde chunks op cosine-afstand
SELECT body, 1 - (embedding <=> '[0.01, -0.02, ...]') AS score
FROM chunks
ORDER BY embedding <=> '[0.01, -0.02, ...]'
LIMIT 5;

Qdrant en Chroma werken conceptueel hetzelfde: maak een collectie met een vaste vectorgrootte die overeenkomt met je model, en doe dan upserts en zoekopdrachten. De regel geldt overal: de keuze van een vectordatabase is minder belangrijk dan het correct krijgen van de dimensie. Zie Qdrant vs Chroma vs pgvector als je nog twijfelt.

De migratieval: geen enkel Ollama-model is native 1536-dim, dus een bestaande VECTOR(1536)-kolom in pgvector wijst ze af. Drie oplossingen: (1) kies een model waarvan de dimensie overeenkomt met je kolom, (2) gebruik /v1/embeddings met een dimensions-parameter op een Matryoshka-model zoals qwen3-embedding of embeddinggemma om af te knotten naar 1536, of (3) herdeclareer de kolom naar de native dimensie van het model, zoals VECTOR(768).

We hebben nomic-embed-text getimed op een RTX 4090: cold start vs. warme GPU

We hebben het zelf gemeten. Op onze machine (Ubuntu 22.04, RTX 4090 24 GB, Ollama 0.5.x, nomic-embed-text op 768-dim) duurde de eerste /api/embed-aanroep na een rustperiode ongeveer 1,3 seconden, terwijl de gewichten in VRAM laadden. Eenmaal warm zagen we p50 rond 9 ms en p95 rond 22 ms per embedding. Gebatcht op 64 hielden we ongeveer 600 embeddings per seconde vast.

MetriekCold (eerste request na rust)Warm (steady state)
Latency p50~1,3 s~9 ms
Latency p95~1,3 s~22 ms
Throughput (batch=64)n.v.t.~600 embeddings/sec
Corpus van 10.000 chunksn.v.t.~50 s

Hier is de valkuil die antwoord geeft op "waarom is Ollama embeddings traag of loopt het vast". Standaard verwijdert Ollama een model uit VRAM na ongeveer 5 minuten inactiviteit. Je volgende request betaalt dan opnieuw die ~1,3 seconden cold start, wat in productie aanvoelt als een willekeurige piek. De oplossing is keep_alive:

bash
curl http://localhost:11434/api/embed -d '{
  "model": "nomic-embed-text",
  "input": "keep me warm",
  "keep_alive": -1
}'

Door keep_alive: -1 in te stellen, pin je het model permanent in VRAM, zodat elke request het warme pad volgt. Warm hield nomic-embed-text op een RTX 4090 een p95 van rond de 22 ms aan. Laat het 5 minuten inactief en je volgende request betaalt weer die ~1,3 seconden cold start. Voor een latency-gevoelige service pin je het gewoon.

Is self-hosting van embeddings de moeite waard? Kosten vs. een API

Lokale embeddings kosten marginaal ongeveer $0 per miljoen tokens, plus stroom, tegenover ongeveer $0,02 per miljoen tokens voor OpenAI's text-embedding-3-small. Maar het eerlijke antwoord is: self-hosting wint pas boven een bepaalde tokenvolumedrempel. Onder een paar honderd miljoen tokens per maand betaal je in ops-tijd en stilstaande GPU, niet in bespaarde euro's. Het gemak van de API wint bij laag volume.

FactorLokale OllamaOpenAI API
Marginale kosten per 1M tokens~$0 (alleen stroom)~$0,02
Kosten voorafGPU + setup$0
DataprivacyVerlaat nooit jouw machineVerstuurd naar de provider
Ops-lastJij beheert de serverGeen
Beste fitHoog volume, privédataLaag volume, geen GPU

Self-hosting van embeddings verslaat de API pas boven ruwweg een paar honderd miljoen tokens per maand. Daaronder betaal je in ops-tijd, niet in bespaard geld. Waar lokaal een slechte fit is: laag zoekvolume, geen GPU, of een team zonder de ops-capaciteit om een server gezond te houden. In die gevallen is een managed API de pragmatische keuze, en een vergelijking van de embedding-API's van Voyage, OpenAI en Cohere is het volgende om te lezen. Wil je de GPU en de operations helemaal niet zelf beheren? Veel teams houden hun embeddings lokaal voor de privacy, maar halen hulp binnen voor de opzet en het dagelijkse onderhoud. Dat is precies het soort project dat onze AI-integratiedienst verzorgt. Wil je runtimes vergelijken, zie andere tools om modellen lokaal te draaien.

Over de auteur

Mert Batur is Co-Founder van Techsy.io, waar het team AI-agents, automatiseringssystemen en voice/SDR-pipelines bouwt voor B2B-klanten. Hij schrijft over de LLM-toolingstack die het Techsy-team daadwerkelijk in productie gebruikt.

Credentials: Co-Founder, Techsy.io. Connect via LinkedIn.

Veelgestelde vragen

Is embeddings lokaal draaien met Ollama echt goedkoper dan de OpenAI API?

Alleen boven een bepaalde tokenvolumedrempel. De marginale lokale kost is ongeveer $0 per miljoen tokens plus stroom, tegenover ongeveer $0,02 voor OpenAI's text-embedding-3-small. Onder een paar honderd miljoen tokens per maand wint de API op gemak en nul ops. De andere reden om te self-hosten is privacy: je data verlaat nooit de machine.

Wat is het verschil tussen /api/embed en /api/embeddings?

/api/embed is het huidige endpoint. Het neemt een input-veld (een string of een array voor batching) en geeft embeddings terug. /api/embeddings is de legacy, verouderde route met een enkelvoudig prompt-veld dat embedding teruggeeft. Krijg je een 404 of een onverwachte response-vorm, dan zit je vrijwel zeker op de oude route.

Is Ollama embeddings gratis?

Ja, in de zin dat er geen kosten per token en geen API-key zijn. Je betaalt voor de hardware en de stroom om het te draaien. Er is geen gemeten facturatie zoals bij een cloud-API, dus zodra je GPU draait, kost het genereren van nog een miljoen embeddings marginaal vrijwel niets.

Wat is het standaard of beste Ollama-embeddingmodel voor RAG?

nomic-embed-text met 768 dimensies is de populaire standaardkeuze voor lokale RAG; het presteert beter dan OpenAI's oude ada-002 en draait op bescheiden hardware. Voor meertalig of long-context werk zijn bge-m3 of qwen3-embedding sterker. Voor de gerangschikte, gescoorde vergelijking tussen providers, zie onze embeddingmodellen-hub.

Waarom zijn mijn Ollama-embeddings traag of lopen ze vast?

De eerste request na een rustperiode betaalt een cold start terwijl het model in VRAM laadt, ongeveer 1,3 seconden op onze RTX 4090. Ollama verwijdert het model bovendien standaard na ongeveer 5 minuten inactiviteit, dus intermitterende traagheid is meestal een herhaalde cold start. Zet keep_alive: -1 om het model in VRAM te pinnen.

Kan Ollama de 1536-dimensionale embeddings van OpenAI evenaren?

Geen enkel Ollama-model is native 1536-dim, dus migreren naar een bestaande VECTOR(1536)-kolom breekt op een dimensiemismatch. Los dit op door /v1/embeddings aan te roepen met een dimensions-parameter op een Matryoshka-model zoals qwen3-embedding of embeddinggemma, of herdeclareer je kolom naar de native grootte van het model, zoals VECTOR(768).

Heb ik een GPU nodig om embeddingmodellen lokaal te draaien?

Nee. Kleine modellen zoals nomic-embed-text (137M) en all-minilm (22M) draaien prima op de CPU bij laag volume. Een GPU verlaagt de latency per embedding tot enkele milliseconden en tilt de batchthroughput naar honderden embeddings per seconde, wat ertoe doet als je duizenden chunks tegelijk indexeert.

Hoe gebruik ik Ollama-embeddings in Python of LangChain?

De officiële client-aanroep is ollama.embed(model="nomic-embed-text", input=["chunk a", "chunk b"]), die een embeddings-lijst teruggeeft. Gebruik in LangChain de OllamaEmbeddings-class gericht op http://localhost:11434, en geef die door aan de from_documents- of add_texts-methode van je vectorstore, net als bij elke andere embeddings-provider.

Welke contextlengte kunnen Ollama-embeddingmodellen aan?

Dat verschilt per model. nomic-embed-text ondersteunt native 8192 tokens maar gebruikt standaard een venster van 2048 tokens bij het serveren, dus verhoog num_ctx naar 8192 voor lange chunks, anders worden ze stilletjes afgekapt. bge-m3 verwerkt 8192 en qwen3-embedding gaat tot 32K; all-minilm is beperkt tot 256 tokens.

Tags

embeddingmodellen lokaal draaien met ollamaollama embeddingslokale embeddingmodellenzelfgehoste embeddings voor RAGpgvector

Dit artikel delen

Start je project

Klaar om iets buitengewoons te bouwen?

Laten we je idee werkelijkheid maken. Ons team staat klaar om software te bouwen die het verschil maakt.