Wat is RAG en waarom is het game-changing voor MKB?
RAG staat voor Retrieval Augmented Generation. Het is een techniek waarbij een AI-model niet alleen vertrouwt op zijn eigen getrainde kennis, maar ook actief relevante informatie opzoekt in een database van jouw eigen documenten. Het resultaat: een AI-assistent die vragen beantwoordt op basis van jouw specifieke bedrijfskennis, niet op basis van algemene internetkennis.
Stel je voor: je hebt honderden pagina's aan productdocumentatie, interne procedures, klantcontracten en FAQ-documenten. Met een RAG-applicatie kun je een chatbot bouwen die precies die informatie raadpleegt wanneer een medewerker of klant een vraag stelt. Geen hallucinations over dingen die het model niet weet, maar feitelijke antwoorden uit jouw eigen documenten.
Voor MKB is dit game-changing. Kennisbeheer is een van de grootste uitdagingen: kennis zit in de hoofden van medewerkers, verspreid over Dropbox-mappen, e-mailthreads en Word-documenten. Een RAG-applicatie ontsluit die kennis en maakt het doorzoekbaar via een conversatie-interface. En met LangChain in Python bouw je zo'n applicatie in minder dan een middag.
Stap 1: Omgeving opzetten
We beginnen met een schone Python-omgeving. Zorg dat je Python 3.11 of hoger hebt geinstalleerd. Maak een virtuele omgeving aan en installeer de benodigde packages.
Toelichting op de packages: langchain is het kernframework, langchain-openai bevat de OpenAI-integratie, langchain-community bevat document loaders en vector store integraties. faiss-cpu is de vector database van Meta voor similarity search. pypdf is nodig voor het lezen van PDF-bestanden. python-dotenv laadt je API-sleutels uit een .env-bestand.
Stap 2: API keys instellen
Maak een .env-bestand aan in je projectmap met je API-sleutels. Voeg dit bestand toe aan je .gitignore zodat je sleutels nooit per ongeluk in je repository terechtkomen.
Laad de sleutels in Python met python-dotenv. Voeg dit bovenaan elk script toe:
Stap 3: Documenten laden
LangChain heeft een uitgebreide bibliotheek van DocumentLoaders voor vrijwel elk bestandsformaat. Hieronder de meest gebruikte voor MKB-toepassingen.
Tip: zorg dat je documenten goede bestandsnamen hebben. LangChain slaat de bestandsnaam op als metadata, zodat je later kunt zien uit welk document een antwoord afkomstig is.
Stap 4: Documenten chunken
Documenten zijn te lang om in een keer als context mee te sturen. We verdelen ze in kleinere stukken (chunks). De grootte van die chunks heeft grote invloed op de kwaliteit van je RAG-applicatie.
Over chunk_size en chunk_overlap: kleinere chunks geven preciezere retrieval maar minder context per chunk. Grotere chunks geven meer context maar kunnen ruis bevatten. Begin met chunk_size=1000 en chunk_overlap=200 en experimenteer op basis van de kwaliteit van de antwoorden.
Stap 5: Embeddings genereren
Embeddings zijn numerieke representaties van tekst waarmee je semantische gelijkheid kunt berekenen. We zetten elk chunk om naar een embedding-vector.
Budget-tip: OpenAI's text-embedding-3-small kost vrijwel niets. Voor 1.000 pagina's bedrijfsdocumenten betaal je minder dan 0,50 euro voor de embeddings. De gratis HuggingFace optie is prima als je geen externe API wilt gebruiken.
Stap 6: Vector store aanmaken en opslaan
We slaan de embeddings op in een FAISS vector store. FAISS (van Meta) is razendsnel en draait volledig lokaal. We slaan de index op schijf op zodat we hem niet elke keer opnieuw hoeven te bouwen.
De FAISS index bouwen duurt even (afhankelijk van het aantal documenten), maar daarna laad je hem in seconden. Als je documenten toevoegt of wijzigt, verwijder je de index en bouw je hem opnieuw.
Stap 7: Retriever instellen
De retriever zoekt in de vector store naar de meest relevante chunks voor een gegeven vraag. Er zijn twee hoofdstrategieen: similarity search (de meest semantisch gelijkende chunks) en MMR (Maximal Marginal Relevance, die diversiteit toevoegt om herhaling te voorkomen).
Stap 8: RAG-chain bouwen
Nu combineren we de retriever met een LLM om de volledige RAG-chain te bouwen. We voegen een systeemprompt toe die het model instrueert om in het Nederlands te antwoorden en alleen informatie uit de documenten te gebruiken.
De parameter return_source_documents=True zorgt ervoor dat je ook kunt zien welke documenten zijn gebruikt voor het antwoord. Dit is waardevol voor verificatie en voor het bouwen van vertrouwen bij gebruikers.
Stap 9: Chatbot interface bouwen
Nu de RAG-chain werkt, bouwen we een gebruiksvriendelijke interface. Gradio maakt het mogelijk om in minuten een web-UI te bouwen die je kunt delen met collega's.
Start de Gradio interface met python app.py en open http://localhost:7860 in je browser. Je ziet direct een werkende chatbot die vragen beantwoordt op basis van jouw eigen documenten.
Stap 10: Deployen als FastAPI endpoint
Voor productiegebruik bouwen we een REST API met FastAPI. Zo kan de chatbot worden geintegreerd in bestaande systemen, websites of tools als n8n en Make.
Start de API met python api.py. De API is beschikbaar op http://localhost:8000. Test met: curl -X POST http://localhost:8000/ask -H 'Content-Type: application/json' -d '{"question": "Wat is het retourbeleid?"}'
Troubleshooting: 5 veelvoorkomende problemen
Probleem 1: Rate limit errors van OpenAI. Oplossing: voeg exponential backoff toe met de tenacity library. Pip install tenacity en decoreer je API-aanroepen met @retry(wait=wait_exponential(min=1, max=60), stop=stop_after_attempt(6)).
Probleem 2: Lege retrieval (relevante documenten worden niet gevonden). Controleer of je documenten correct zijn geladen en gechunkt. Test de retriever direct: resultaten = retriever.invoke(je_vraag). Als de resultaten leeg zijn, is de vector store mogelijk leeg. Verwijder de FAISS-index en bouw hem opnieuw.
Probleem 3: Hallucinations (model verzint informatie die niet in de documenten staat). Verlaag de temperature naar 0 en maak de systeemprompt strenger: voeg toe 'Als het antwoord NIET in de context staat, antwoord dan: Ik heb geen informatie over dit onderwerp in de beschikbare documenten.'
Probleem 4: Encoding errors bij het laden van documenten. Voeg encoding='utf-8' toe aan de TextLoader. Voor PDF-bestanden met speciale tekens gebruik je PyMuPDF als alternatief: pip install pymupdf en from langchain_community.document_loaders import PyMuPDFLoader.
Probleem 5: Trage performance bij grote documentcollecties. Gebruik FAISS met GPU-ondersteuning (pip install faiss-gpu) of overweeg een persistente vector database als ChromaDB of Qdrant voor grote collecties. ChromaDB ondersteunt incrementeel toevoegen van documenten zonder de hele index te herbouwen.
Uitbreidingen: verder bouwen
Claude als alternatief LLM: vervang ChatOpenAI door ChatAnthropic. Claude Haiku is vergelijkbaar qua kosten met GPT-4o-mini maar sterkt in instructievolging en nuance. Ideaal voor klantenservice-toepassingen waarbij toon en nauwkeurigheid belangrijk zijn.
Chroma als alternatieve vector store: ChromaDB is een open-source vector database die persistentie ingebouwd heeft en incrementeel bijwerken ondersteunt. Beter dan FAISS voor situaties waarbij je regelmatig nieuwe documenten toevoegt. Installeer met pip install chromadb en vervang FAISS.from_documents door Chroma.from_documents.
Streaming responses: voor een betere gebruikerservaring voeg je streaming toe zodat het antwoord woord voor woord verschijnt. Gebruik llm = ChatOpenAI(streaming=True) en verwerk de stream in je Gradio of FastAPI endpoint.
Conversatiegeheugen: de huidige implementatie heeft geen geheugen van eerdere vragen in hetzelfde gesprek. Voeg dit toe met ConversationalRetrievalChain in plaats van RetrievalQA, gecombineerd met ConversationBufferMemory. Zo kan de gebruiker doorvragen op eerdere antwoorden.
Met deze handleiding heb je alle bouwstenen voor een productie-klare RAG-applicatie. Begin klein: laad een paar documenten, test de kwaliteit van de antwoorden, en breid daarna stap voor stap uit. De investering in technische setup betaalt zich terug in tijdsbesparing voor medewerkers die dagelijks vragen stellen over bedrijfsinformatie.