# LlamaIndex met de Gemini API [[TOC]] ## LlamaIndex en Gemini LlamaIndex is een framework dat specifiek is gebouwd voor RAG (Retrieval-Augmented Generation) en data-gebaseerde AI-applicaties. Waar LangChain algemener is, focust LlamaIndex op het efficient doorzoekbaar maken van grote hoeveelheden documenten voor gebruik als context in LLM-prompts. Je combineert Gemini hierin op twee plekken: als LLM dat de antwoorden genereert, en als embedding-model dat je documenten omzet naar vectoren voor retrieval. :::warn title="Pakketnamen zijn gewijzigd" De oude pakketten `llama-index-llms-gemini` en `llama-index-embeddings-gemini` worden niet meer onderhouden. Gebruik de nieuwe `llama-index-llms-google-genai` en `llama-index-embeddings-google-genai`, met de klassen `GoogleGenAI` en `GoogleGenAIEmbedding`. Oudere tutorials die nog `from llama_index.llms.gemini import Gemini` tonen, zijn verouderd. ::: ## Installatie ```bash pip install llama-index llama-index-llms-google-genai llama-index-embeddings-google-genai ``` ## Basisinstellingen ```python import os from llama_index.llms.google_genai import GoogleGenAI from llama_index.embeddings.google_genai import GoogleGenAIEmbedding from llama_index.core import Settings Settings.llm = GoogleGenAI( model="gemini-2.5-flash", api_key=os.environ["GEMINI_API_KEY"], temperature=0.1 ) Settings.embed_model = GoogleGenAIEmbedding( model_name="gemini-embedding-001", api_key=os.environ["GEMINI_API_KEY"], embed_batch_size=100 ) ``` :::info title="Welke modellen kies je in 2026?" `gemini-2.5-flash` is een stabiel, snel en betaalbaar model voor RAG-antwoorden. Voor zwaardere redeneertaken kun je een Pro-variant inzetten. Voor embeddings is `gemini-embedding-001` het GA-tekstmodel. Wil je ook afbeeldingen, audio of video in dezelfde vectorruimte doorzoekbaar maken, kijk dan naar het multimodale Gemini Embedding 2. Let op: `gemini-2.0-flash` en `text-embedding-004` zijn uitgefaseerd en niet meer geschikt voor nieuwe projecten. ::: ## Documenten indexeren ```python from llama_index.core import SimpleDirectoryReader, VectorStoreIndex documenten = SimpleDirectoryReader("./documenten/").load_data() index = VectorStoreIndex.from_documents( documenten, show_progress=True ) index.storage_context.persist(persist_dir="./opgeslagen_index") ``` `SimpleDirectoryReader` leest een hele map met documenten in en herkent automatisch veelvoorkomende bestandstypen. Met `persist` schrijf je de index naar schijf, zodat je niet bij elke run opnieuw hoeft te embedden. ## Query engine gebruiken ```python from llama_index.core import StorageContext, load_index_from_storage storage_context = StorageContext.from_defaults(persist_dir="./opgeslagen_index") index = load_index_from_storage(storage_context) query_engine = index.as_query_engine( similarity_top_k=3, response_mode="tree_summarize" ) response = query_engine.query("Wat zijn de openingstijden van de klantenservice?") print(response) print("Bronnen:") for node in response.source_nodes: print(f"Score: {node.score:.4f} | {node.metadata.get('file_name', 'onbekend')}") ``` De `source_nodes` op het antwoord laten zien welke chunks zijn gebruikt en met welke score. Dat is essentieel om te controleren of het model zijn antwoord echt op je documenten baseert en niet hallucineert. :::tip title="Kies de juiste similarity_top_k" Gebruik `similarity_top_k=3` tot `5` voor de meeste use cases. Te weinig chunks mist context, te veel voegt ruis toe en verhoogt je tokenkosten. Experimenteer met waarden tussen 3 en 8 voor jouw specifieke corpus en meet de antwoordkwaliteit. ::: ## Chat engine voor conversationele RAG ```python chat_engine = index.as_chat_engine( chat_mode="condense_plus_context", similarity_top_k=3, system_prompt="Je bent een expert over onze producten. Gebruik alleen informatie uit de documenten." ) response1 = chat_engine.chat("Wat is de garantie op laptops?") print(response1) response2 = chat_engine.chat("En geldt dat ook voor tablets?") print(response2) ``` De modus `condense_plus_context` herschrijft de vervolgvraag eerst tot een zelfstandige vraag (zodat "geldt dat ook voor tablets" begrijpelijk wordt) en haalt daarna pas relevante context op. Zo blijft een gesprek met meerdere beurten coherent. ## Documenten per type laden ```python from llama_index.core import Document from llama_index.readers.file import PDFReader from llama_index.readers.web import SimpleWebPageReader pdf_reader = PDFReader() pdf_docs = pdf_reader.load_data("handleiding.pdf") web_reader = SimpleWebPageReader() web_docs = web_reader.load_data(["https://docs.example.com/api"]) custom_doc = Document( text="Onze retourpolicy: 30 dagen retourneren zonder opgaaf van reden.", metadata={"bron": "retourbeleid", "datum": "2024-01"} ) alle_docs = pdf_docs + web_docs + [custom_doc] index = VectorStoreIndex.from_documents(alle_docs) ``` ## Metadata filtering Met metadata-filters beperk je het zoeken tot een specifieke deelverzameling, bijvoorbeeld alleen documenten in een bepaalde categorie. Dat maakt antwoorden preciezer en sneller. ```python from llama_index.core.vector_stores import MetadataFilters, ExactMatchFilter query_engine = index.as_query_engine( filters=MetadataFilters( filters=[ ExactMatchFilter(key="categorie", value="garantie") ] ), similarity_top_k=5 ) response = query_engine.query("Hoe lang is de garantietermijn?") ``` ## Geavanceerde retrieval: HyDE Hypothetical Document Embeddings (HyDE) verbetert retrieval door eerst een hypothetisch antwoord te genereren en dat te embedden. De embedding van een volzin lijkt vaak meer op je documenten dan de embedding van een korte vraag, waardoor je relevantere chunks terugvindt. ```python from llama_index.core.indices.query.query_transform import HyDEQueryTransform from llama_index.core.query_engine import TransformQueryEngine hyde_transform = HyDEQueryTransform(include_original=True) hyde_engine = TransformQueryEngine(query_engine, hyde_transform) response = hyde_engine.query("Welke producten hebben 2 jaar garantie?") ``` ## Index opslaan in een vectordatabase Voor productie wil je je vectoren niet op schijf in losse bestanden, maar in een echte vectordatabase. Hieronder een voorbeeld met Chroma. ```python import chromadb from llama_index.vector_stores.chroma import ChromaVectorStore from llama_index.core import StorageContext chroma_client = chromadb.PersistentClient(path="./chroma_db") collection = chroma_client.get_or_create_collection("kennisbank") vector_store = ChromaVectorStore(chroma_collection=collection) storage_context = StorageContext.from_defaults(vector_store=vector_store) index = VectorStoreIndex.from_documents( documenten, storage_context=storage_context ) ``` ## Praktisch voorbeeld: kennisbank-chatbot Een complete minimale flow voor een interne kennisbank ziet er zo uit: :::howto title="Van documenten naar werkende RAG-chatbot" 1. Installeer de pakketten en zet `GEMINI_API_KEY` in je omgeving. 2. Configureer `Settings.llm` (`GoogleGenAI`) en `Settings.embed_model` (`GoogleGenAIEmbedding`). 3. Lees je documenten in met `SimpleDirectoryReader` en bouw een `VectorStoreIndex`. 4. Sla de index op in Chroma zodat je niet opnieuw hoeft te embedden bij een herstart. 5. Maak een chat-engine met `chat_mode="condense_plus_context"` en een duidelijke `system_prompt`. 6. Controleer bij elk antwoord de `source_nodes` om hallucinaties te herkennen. ::: :::faq ### Wat is het verschil tussen LlamaIndex en LangChain voor RAG? LlamaIndex is ontworpen specifiek voor RAG, met betere data-connectors, meer retrieval-strategieen en eenvoudigere indexering. LangChain is algemener en sterker voor complexe multi-step agents. Kies LlamaIndex als RAG je hoofddoel is, en LangChain als je veel verschillende tools en agent-logica wilt combineren. ### Welk Gemini-model gebruik ik in 2026? Gebruik `gemini-2.5-flash` als snel en betaalbaar standaardmodel voor de generatie, en een Pro-variant voor zwaardere redeneertaken. Voor tekst-embeddings is `gemini-embedding-001` het stabiele GA-model. Het oudere `gemini-2.0-flash` en `text-embedding-004` zijn uitgefaseerd. ### Hoe groot mogen mijn chunks zijn? Standaard gebruikt LlamaIndex chunks van ongeveer 1024 tokens met een kleine overlap. Voor technische documentatie werkt 512 tot 1024 tokens goed. Voor verhalen en narratieve content zijn grotere chunks (richting 2048) vaak beter omdat de context dan minder versnipperd raakt. ### Kan ik LlamaIndex gebruiken met Vertex AI Gemini? Ja. De `google-genai`-integratie ondersteunt Vertex AI via een `vertexai_config` op zowel de LLM- als de embedding-klasse. Je authenticeert dan met Application Default Credentials in plaats van met een losse API-sleutel. ### Hoe ververs ik de index als documenten veranderen? Gebruik `index.refresh_ref_docs(bijgewerkte_docs)` om gewijzigde documenten te herindexeren zonder alles opnieuw te verwerken. LlamaIndex vergelijkt hash-waarden en embedt alleen de documenten die echt zijn veranderd, wat veel API-kosten bespaart. ### Hoe controleer ik of het model niet hallucineert? Inspecteer altijd `response.source_nodes`. Daar staan de chunks en hun scores die het antwoord onderbouwen. Lage scores of irrelevante bronnen zijn een signaal dat je retrieval (chunk-grootte, `similarity_top_k` of je embedding-model) moet bijstellen, of dat het antwoord niet in je corpus staat. :::