# Embedding-model kiezen voor RAG [[TOC]] ## Wat doet een embedding-model? Een embedding-model converteert tekst naar een vector: een array van getallen (typisch 768 tot 3072 dimensies) die de semantische betekenis van de tekst representeert. Twee teksten met een vergelijkbare betekenis krijgen vergelijkbare vectoren en liggen daardoor dicht bij elkaar in de vectorruimte. De kwaliteit van je RAG-systeem staat of valt met de kwaliteit van de embeddings. Een goed embedding-model: - Begrijpt de semantische betekenis, niet alleen trefwoordovereenkomst. - Werkt goed in jouw domein (technisch, juridisch, medisch). - Ondersteunt jouw taal, in dit geval Nederlands of meertalig. - Heeft een acceptabele dimensionaliteit, want dat beinvloedt opslagkosten en zoeksnelheid. ## Overzicht van populaire modellen De tabel hieronder geeft de stand van zaken in juni 2026. Prijzen zijn per miljoen input-tokens en kunnen wijzigen, dus controleer altijd de actuele prijslijst van de provider. | Model | Provider | Dimensies | Max tokens | Talen | Kosten | |-------|---------|-----------|------------|-------|--------| | gemini-embedding-001 | Google | 3072 (MRL) | 2048 | Meertalig (100+) | $0,15/1M | | text-embedding-3-large | OpenAI | 3072 | 8191 | Meertalig | $0,13/1M | | text-embedding-3-small | OpenAI | 1536 | 8191 | Meertalig | $0,02/1M | | embed-v4 | Cohere | 1536 | 128k | Meertalig + beeld | $0,12/1M | | text-multilingual-embedding-002 | Google | 768 | 2048 | Meertalig (18) | $0,01/1M | | E5-NL (base/large) | Universiteit (open) | 768 tot 1024 | 512 | Nederlands | Gratis (zelf hosten) | | nomic-embed-text-v2-moe | Nomic | 768 | 512 | Meertalig (100+) | Gratis (zelf hosten) | :::info title="Wat is MRL?" gemini-embedding-001 en de text-embedding-3-modellen gebruiken Matryoshka Representation Learning. Daarmee kun je de vector inkorten tot bijvoorbeeld 1536 of 768 dimensies zonder grote kwaliteitsverlies, zodat je opslag en zoeklatentie bespaart. ::: ## Meertalige modellen voor Nederlands Voor Nederlandstalige RAG heb je grofweg drie sporen: een sterke commerciele meertalige API, een algemeen open-source model dat je zelf host, of een model dat specifiek voor Nederlands is getraind. - **Hoogste kwaliteit via API:** gemini-embedding-001 staat in juni 2026 bovenaan de meertalige MTEB-leaderboard en doet het goed op Nederlands. text-embedding-3-large van OpenAI zit daar net onder en is een prima alternatief. - **Nederlands-specifiek:** sinds 2025 bestaan er dedicated Nederlandse modellen, de E5-NL-familie, geevalueerd op de MTEB-NL-benchmark. Voor puur Nederlandse corpora kunnen die compacte modellen grotere meertalige modellen verslaan, tegen lagere kosten omdat je ze zelf host. - **Meertalig en open:** nomic-embed-text-v2-moe dekt meer dan honderd talen en draait lokaal via Ollama. :::tip title="Verifieer op je eigen data" Benchmarks zoals MTEB en MTEB-NL geven richting, maar niet het laatste woord. Bouw een kleine testset met echte vragen en de bijbehorende relevante documenten uit jouw domein, en meet de retrieval-kwaliteit per model. Dat voorspelt je productieresultaat beter dan een gemiddelde leaderboard-score. ::: Een minimaal voorbeeld met de OpenAI-API, inclusief batching om rate limits te respecteren: ```typescript async function embedWithOpenAI(texts: string[]): Promise { const response = await openai.embeddings.create({ model: "text-embedding-3-large", input: texts, encoding_format: "float", }); return response.data.map(item => item.embedding); } async function embedBatch(texts: string[], batchSize = 100): Promise { const results: number[][] = []; for (let i = 0; i < texts.length; i += batchSize) { const batch = texts.slice(i, i + batchSize); const embeddings = await embedWithOpenAI(batch); results.push(...embeddings); if (i + batchSize < texts.length) { await new Promise(resolve => setTimeout(resolve, 100)); } } return results; } ``` ## Lokale modellen met Ollama Voor privacygevoelige data of kostenbesparing bij grote volumes kun je een open-source model lokaal draaien. De data verlaat je server dan niet. ```typescript async function embedWithOllama(texts: string[]): Promise { const results = await Promise.all( texts.map(async (text) => { const response = await fetch("http://localhost:11434/api/embeddings", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ model: "nomic-embed-text-v2-moe", prompt: text }), }); const data = await response.json(); return data.embedding as number[]; }) ); return results; } ``` :::warn title="Houd indexeren en zoeken op hetzelfde model" Embeddings van verschillende modellen zijn niet uitwisselbaar. Als je tijdens het experimenteren van model wisselt, moet je je hele index opnieuw opbouwen. Leg daarom vroeg vast met welk model en welke dimensie je naar productie gaat. ::: ## Dimensie-reductie De gemini-embedding-001- en text-embedding-3-modellen ondersteunen dimensie-reductie zonder grote kwaliteitsverlies, dankzij Matryoshka Representation Learning: ```typescript const response = await openai.embeddings.create({ model: "text-embedding-3-large", input: texts, dimensions: 512, }); ``` Kleinere dimensies verlagen opslagkosten en zoeklatentie aanzienlijk. Test de kwaliteitsimpact op jouw data voor je de dimensies verkleint, want vanaf een bepaald punt gaat het wel ten koste van de recall. ## Embedding-modellen evalueren Een eenvoudige offline evaluatie met een testset van vragen en bekende relevante documenten: ```typescript interface EmbeddingEvalResult { model: string; avg_retrieval_score: number; latency_ms: number; cost_per_million_tokens: number; } async function evaluateEmbeddingModel( model: EmbedFunction, testQueries: { query: string; relevant_doc_ids: string[] }[], documents: Document[] ): Promise { const docEmbeddings = await model(documents.map(d => d.content)); let totalScore = 0; for (const test of testQueries) { const queryEmbedding = await model([test.query]); const scores = docEmbeddings.map((emb, i) => ({ id: documents[i].id, score: cosineSimilarity(queryEmbedding[0], emb), })); scores.sort((a, b) => b.score - a.score); const top5 = scores.slice(0, 5).map(s => s.id); const relevantFound = test.relevant_doc_ids.filter(id => top5.includes(id)).length; totalScore += relevantFound / test.relevant_doc_ids.length; } return { model: model.name, avg_retrieval_score: totalScore / testQueries.length, latency_ms: 0, cost_per_million_tokens: 0, }; } ``` ## Afwegingen per prioriteit Welk model het beste past hangt af van wat je belangrijkste eis is. Gebruik onderstaande opsomming als snelle gids. - **Kwaliteit voorop:** gemini-embedding-001 (Google) of text-embedding-3-large (OpenAI). Sterke Nederlandse taalondersteuning en hoge nauwkeurigheid via een eenvoudige API. - **Kosten voorop:** text-embedding-3-small of text-multilingual-embedding-002 van Google. Een veelvoud goedkoper dan de large-varianten, met een redelijke kwaliteit. - **Privacy voorop:** de Dutch-specifieke E5-NL-modellen of nomic-embed-text-v2-moe via Ollama. Je host zelf en de data verlaat je server niet. - **Beeld en tekst samen:** Cohere embed-v4 of het multimodale gemini-embedding-2-preview als je naast tekst ook afbeeldingen wilt embedden. :::faq ### Moet ik hetzelfde model gebruiken voor indexeren en zoeken? Ja, altijd. Embeddings van verschillende modellen zijn niet compatibel, want de vectorruimten zijn anders georienteerd. Als je van model wisselt, moet je de hele index herbouwen. ### Hoe ga ik om met lange documenten die het tokenmaximum overschrijden? Knip je documenten in chunks zodat elk chunk onder het tokenmaximum blijft. Kap nooit zomaar een document af en embed dat, want dan verlies je de informatie aan het einde. ### Kan ik meerdere embedding-modellen combineren? Ja, met late fusion: bereken scores met model A en model B en combineer die, bijvoorbeeld als gemiddelde of gewogen som. Dat kost meer rekenkracht maar geeft vaak een betere recall. ### Hoe update ik embeddings na een model-upgrade? Je bouwt de volledige index opnieuw op. Plan dit als een migratietaak: indexeer parallel naar een nieuwe collectie en zet de applicatie pas over als de nieuwe index compleet is. ### Welk model kies ik specifiek voor Nederlands? Voor de hoogste kwaliteit via een API kies je gemini-embedding-001 of text-embedding-3-large. Wil je lokaal draaien, dan zijn de E5-NL-modellen interessant omdat ze speciaal voor Nederlands zijn getraind en op de MTEB-NL-benchmark goed scoren. ### Zijn duurdere modellen altijd beter? Nee. Een hogere MTEB-score betekent niet automatisch betere resultaten op jouw data. Meet altijd met een eigen testset, want een goedkoper of kleiner model is soms net zo goed voor jouw domein en taal. :::