Hoe een RAG-systeem in 10 regels Python te bouwen zonder frameworks
Ontgrendel de kracht van RAG (Retrieval Augmented Generation) met deze 10-regelige Python-codetutorial. Duik in informatieopvraging, bouw je eigen documentensysteem op en maak gebruik van LLM's voor robuuste reacties - alles zonder afhankelijk te zijn van complexe frameworks. Optimaliseer je content voor SEO en betrokkenheid.
24 februari 2025

Ontdek hoe je in slechts 10 regels Python-code een krachtig retrieval-augmented generation (RAG)-systeem van de grond af kunt opbouwen, zonder gebruik te maken van externe frameworks. Deze beknopte maar alomvattende aanpak geeft je een diepgaand inzicht in de kerncomponenten, waardoor je robuuste en aanpasbare AI-aangedreven oplossingen voor je documentgebaseerde toepassingen kunt creëren.
Begrijp het concept van Retrieval Augmented Generation (RAG)
Leer documenten op te delen in paragrafen
Documenteren en gebruikersquery's embedden met behulp van Sentence Transformers
Relevante chunks ophalen op basis van cosinus similariteit
Gebruikersquery verrijken met opgehaalde chunks en antwoord genereren met behulp van OpenAI GPT-4
Conclusie
Begrijp het concept van Retrieval Augmented Generation (RAG)
Begrijp het concept van Retrieval Augmented Generation (RAG)
Retrieval Augmented Generation (RAG) is een techniek die wordt gebruikt voor het ophalen van informatie uit uw eigen documenten. Het omvat een tweeledige aanpak:
-
Aanmaak van kennisbank: De documenten worden opgedeeld in kleinere subdocumenten, en embeddings worden berekend voor elk fragment. Deze embeddings en de oorspronkelijke fragmenten worden doorgaans opgeslagen in een vectoropslag.
-
Ophalen en genereren: Wanneer een nieuwe gebruikersquery binnenkomt, wordt een embedding berekend voor de query. De meest relevante fragmenten worden opgevraagd door de queryembedding te vergelijken met de opgeslagen fragmentembeddings. De opgevraagde fragmenten worden vervolgens toegevoegd aan de oorspronkelijke query en ingevoerd in een taalmodel (LLM) om de uiteindelijke reactie te genereren.
Deze opstelling wordt een "retrieval-augmented generation"-pijplijn genoemd, omdat de generatie van het LLM wordt verrijkt met de relevante informatie die uit de kennisbank is opgevraagd.
Hoewel er frameworks zoals Langchain en LlamaIndex zijn die de implementatie van RAG-pijplijnen vereenvoudigen, kunnen de kerncomponenten worden gebouwd met alleen Python, een embeddings-model en een LLM. Deze aanpak biedt een beter begrip van de onderliggende concepten en biedt meer flexibiliteit bij het aanpassen van de pijplijn.
Leer documenten op te delen in paragrafen
Leer documenten op te delen in paragrafen
Bij het bouwen van een retrieval-augmented generation (RAG)-systeem is een van de belangrijkste stappen het opdelen van de invoerdocumenten in kleinere, beter beheerbare stukken. In dit voorbeeld delen we het invoerdocument (een Wikipedia-artikel) op in alinea's.
De reden voor deze aanpak is dat alinea's vaak logische informatie-eenheden vertegenwoordigen die effectief kunnen worden opgevraagd en gebruikt om de gebruikersquery te verrijken. Door het document op deze manier op te delen, kunnen we de meest relevante secties beter identificeren om op te nemen in de uiteindelijke reactie.
De code voor deze stap is als volgt:
# Verdeel het document in alinea's
chunks = [paragraph.strip() for paragraph in text.split('\n') if paragraph.strip()]
Hier gebruiken we een eenvoudige aanpak waarbij we de invoertekst splitsen op regeleindetekens om de afzonderlijke alinea's te extraheren. We verwijderen vervolgens eventuele voorloop- of achterloopspaties van elke alinea om een schone weergave te krijgen.
De resulterende chunks
-lijst bevat de afzonderlijke alinea's, die vervolgens kunnen worden geëmbedded en opgeslagen in de vectoropslag. Hierdoor kunnen we de meest relevante alinea's efficiënt ophalen op basis van de gebruikersquery en opnemen in de uiteindelijke reactie die door het taalmodel wordt gegenereerd.
Documenteren en gebruikersquery's embedden met behulp van Sentence Transformers
Documenteren en gebruikersquery's embedden met behulp van Sentence Transformers
Om de documentfragmenten en de gebruikersquery te embedden, gebruiken we de Sentence Transformers-bibliotheek. Deze bibliotheek biedt vooraf getrainde modellen die hoogwaardige embeddings voor tekst kunnen genereren.
Eerst laden we het embeddings-model:
from sentence_transformers import SentenceTransformer
embedding_model = SentenceTransformer('all-mpnet-base-v2')
Vervolgens berekenen we de embeddings voor de documentfragmenten:
chunk_embeddings = embedding_model.encode(chunks, normalize_embeddings=True)
Hier is chunks
een lijst met de tekstfragmenten uit het document. De optie normalize_embeddings=True
zorgt ervoor dat de embeddings genormaliseerd worden, wat belangrijk is voor de latere similariteitsberekening.
Om de embedding voor de gebruikersquery te krijgen, voeren we eenvoudigweg uit:
query_embedding = embedding_model.encode([user_query], normalize_embeddings=True)[0]
Nu hebben we de embeddings voor de documentfragmenten en de gebruikersquery, die we kunnen gebruiken voor de ophaalprocedure.
Relevante chunks ophalen op basis van cosinus similariteit
Relevante chunks ophalen op basis van cosinus similariteit
Om de meest relevante fragmenten op basis van de gebruikersquery op te halen, moeten we eerst de cosinus-similariteit tussen de queryembedding en de embeddings van de documentfragmenten berekenen. Hier is hoe we dat kunnen doen:
- Bereken de embedding van de gebruikersquery met behulp van hetzelfde embeddings-model als de documentfragmenten.
- Bereken het dot-product tussen de queryembedding en elk van de embeddings van de documentfragmenten. Dit geeft ons de cosinus-similariteitsscores.
- Sorteer de documentfragmenten op basis van de cosinus-similariteitsscores en selecteer de K meest relevante fragmenten.
- Haal de tekstinhoud van de geselecteerde fragmenten op om te gebruiken als context voor het taalmodel.
De belangrijkste stappen zijn:
- Bereken queryembedding
- Bereken cosinus-similariteitsscores
- Sorteer en selecteer de K beste fragmenten
- Haal de tekstinhoud van de fragmenten op
Deze eenvoudige aanpak stelt ons in staat om efficiënt de meest relevante informatie uit de documentverzameling op te halen om de gebruikersquery te verrijken voordat deze wordt doorgegeven aan het taalmodel voor generatie.
Gebruikersquery verrijken met opgehaalde chunks en antwoord genereren met behulp van OpenAI GPT-4
Gebruikersquery verrijken met opgehaalde chunks en antwoord genereren met behulp van OpenAI GPT-4
Om een reactie te genereren met behulp van de opgevraagde fragmenten en de gebruikersquery, maken we eerst een prompt die de relevante fragmenten en de gebruikersquery bevat. Vervolgens gebruiken we het OpenAI GPT-4-model om een reactie te genereren op basis van deze prompt.
Hier is de code:
# Haal de gebruikersquery op
user_query = "What is the capital of France?"
# Haal de meest relevante fragmenten op op basis van de gebruikersquery
top_chunk_ids = [6, 8, 5]
top_chunks = [chunks[i] for i in top_chunk_ids]
# Maak de prompt
prompt = "Use the following context to answer the question at the end. If you don't know the answer, say that you don't know and do not try to make up an answer.\n\nContext:\n"
for chunk in top_chunks:
prompt += chunk + "\n\n"
prompt += f"\nQuestion: {user_query}"
# Genereer de reactie met behulp van OpenAI GPT-4
response = openai_client.chat.create(
model="gpt-4",
messages=[
{"role": "user", "content": prompt}
],
max_tokens=1024,
n=1,
stop=None,
temperature=0.7,
).choices[0].message.content
print(response)
In deze code halen we eerst de meest relevante fragmenten op op basis van de gebruikersquery door de 3 fragmenten met de hoogste similariteitsscores te vinden. Vervolgens maken we een prompt die deze fragmenten en de gebruikersquery bevat. Ten slotte gebruiken we het OpenAI GPT-4-model om een reactie te genereren op basis van deze prompt.
De gegenereerde reactie zal een beknopt en relevant antwoord op de gebruikersquery zijn, waarbij gebruik wordt gemaakt van de informatie uit de opgevraagde fragmenten.
Conclusie
Conclusie
In deze zelfstudie hebben we geleerd hoe we een volledig chatsysteem met een documentophaalsysteem kunnen bouwen met slechts 10 regels Python-code. We hebben de belangrijkste onderdelen van een Retrieval Augmented Generation (RAG)-pijplijn behandeld, waaronder de aanmaak van de kennisbank, het opdelen van documenten, embeddings, ophalen en genereren met behulp van een groot taalmodel.
De belangrijkste inzichten zijn:
- Je kunt een eenvoudige RAG-pijplijn implementeren zonder complexe frameworks zoals Langchain of LlamaIndex. Puur Python en een paar bibliotheken zijn voldoende.
- Het opdelen van je documenten op basis van de structuur (bijv. alinea's) is een eenvoudige maar effectieve strategie voor de meeste use cases.
- Het embedden van de documentfragmenten en de gebruikersquery, en vervolgens de similariteitsscores berekenen, stelt je in staat om de meest relevante informatie op te halen om de gebruikersquery te verrijken.
- Het integreren van de opgevraagde fragmenten met de gebruikersquery en deze invoeren in een groot taalmodel maakt het mogelijk om een relevant en informatief antwoord te genereren.
Hoewel dit voorbeeld een solide basis biedt, zijn er veel mogelijkheden om robuustere en geavanceerdere RAG-systemen op te bouwen. Frameworks zoals Langchain en LlamaIndex kunnen nuttig zijn bij de integratie met verschillende vectoropslagen en taalmodellen. Maar door te beginnen met een pure Python-implementatie kun je de kernconcepten en -onderdelen van een RAG-pijplijn beter begrijpen.
Als je geïnteresseerd bent in het verkennen van geavanceerdere RAG-technieken, raad ik je aan om mijn cursus "RAG Beyond Basics" te bekijken, waarin dieper wordt ingegaan op het bouwen van complexe, productie-klare RAG-systemen.
FAQ
FAQ