RAG-Systeme: Funktionsweise und minimale Python-Implementierung
Sprachmodelle sind durch ihre Trainingsdaten eingeschränkt: Das Wissen ist statisch, deckt keine aktuellen Ereignisse ab und neigt zu Halluzinationen – erfundene Fakten. Das Kontextfenster verschärft das Problem, indem es Eingaben bei Überschreitung der Grenzen abschneidet. Retrieval-Augmented Generation (RAG) löst das, indem es relevante Kontexte aus externen Quellen während der Generierung holt, Fehler reduziert und Quellenangaben liefert.
RAG verknüpft Dokumente, Datenbanken oder Code-Repos, um Antworten nachprüfbar und aktuell zu machen. Es ist essenziell für Fachbereiche, auf die das Modell nicht trainiert wurde.
Dokumente zerlegen (Chunking)
Chunking teilt Texte in Fragmente (Chunks) für die Indizierung auf. LLMs verarbeiten nur eine begrenzte Anzahl Chunks, daher hängt die Faktenverfügbarkeit von der Chunk-Qualität ab.
Große Chunks erzeugen Rauschen, erhöhen Kosten und mindern die Suchgenauigkeit. Kleine Chunks zerstören den Kontext und trennen verwandte Ideen. Strategien:
- Feste Zeichen- oder Token-Länge.
- Semantische Grenzen (Absätze, Überschriften).
- Überlappung für Kontinuität.
Passen Sie Parameter empirisch an Ihr Korpus und Ihre Abfragen an.
Ablaufphasen eines RAG-Workflows
RAG umfasst Vorverarbeitung, Abruf und Generierung:
- Indizierung: Chunks werden zu Vektoren und in einer Vektordatenbank gespeichert.
- Abruf: Abfrage wird vektorisiert, top-relevante Chunks geholt.
- Aufbereitung: Ergebnisse gerankt, Duplikate und Rauschen bereinigt.
- Generierung: Kontext zur Abfrage für das LLM hinzugefügt.
Einfaches Naive RAG hält es unkompliziert. Erweiterte RAG fügt Abfrageschreibung und Reranking hinzu. Modulares RAG nutzt Module wie Routing und Ergebnisverschmelzung.
RAG vs. Fine-Tuning
RAG erweitert den Wissenszugang ohne Modelländerungen, im Gegensatz zu Fine-Tuning, das Daten und rechenintensive Ressourcen braucht. Prompt-Engineering passt Abfragen an, fügt aber keine externen Daten hinzu.
| Ansatz | Vorteile | Nachteile |
|--------------|---------------------------|----------------------------|
| RAG | Frische Daten, günstig, Quellenangaben | Abhängig von Abrufqualität |
| Fine-Tuning | Tiefgehende Anpassung | Ressourcenintensiv, veraltet schnell |
RAG glänzt bei dynamischen Daten; Fine-Tuning bei statischen Domänen.
Minimale RAG-Pipeline: Praxisnah umsetzen
Wir bauen ein Naive RAG in Python mit Wikipedia (500 Artikel) und Qwen2.5-3B-Instruct. Unter Einsatz von LangChain, Chroma und sentence-transformers.
Schritt 1: Laden und Zerlegen
import torch
from datasets import load_dataset
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.documents import Document
device = "cuda" if torch.cuda.is_available() else "cpu"
dataset = load_dataset(
"wikimedia/wikipedia",
"20231101.ru",
split="train[:500]"
)
documents = [
Document(
page_content=row["text"],
metadata={"title": row["title"]}
)
for row in dataset
]
splitter = RecursiveCharacterTextSplitter(
chunk_size=800,
chunk_overlap=100
)
chunks = splitter.split_documents(documents)
print("Chunks:", len(chunks))
Erzeugt ~17.892 Chunks à 800 Zeichen mit 100-Zeichen-Überlappung.
Schritt 2: Vektor-Index
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceEmbeddings
embedding_model = HuggingFaceEmbeddings(
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
model_kwargs={"device": device}
)
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embedding_model
)
Multilingual MiniLM für Embeddings, Chroma für Speicherung.
Schritt 3: Abruf
import textwrap
def search(query, k=3, width=80):
results = vectorstore.similarity_search(query, k=k)
for i, doc in enumerate(results, 1):
print(f"\n--- Ergebnis {i} ---")
print("Titel:", doc.metadata["title"])
print(textwrap.fill(doc.page_content[:1000], width))
search("Wer ist Puschkin?")
holt relevante Ausschnitte aus Puschkin-Artikeln.
Schritt 4: Generierung
Fügen Sie ein LLM hinzu, um aus abgerufenen Chunks zu generieren (Code aus Platzgründen gekürzt; vollständige Version im Quellcode).
Wichtige Erkenntnisse
- RAG reduziert Halluzinationen durch externen Kontext, ohne Modellanpassung.
- Erfolg hängt von Chunking und Embeddings ab: Passen Sie sie an Ihre Domäne an.
- Starten Sie mit Naive RAG, skalieren Sie zu Erweitert/Modular für Produktion.
- LangChain vereinfacht Prototyping.
- Testen Sie mit realen Datensätzen zur Optimierung.
— Editorial Team
Noch keine Kommentare.