Zurück zur Startseite

RAG-Systeme erklärt: Python-Implementierung

Dieser Artikel erklärt Retrieval-Augmented Generation (RAG) als Lösung für statisches Wissen und Halluzinationen in Sprachmodellen. Er vergleicht RAG mit Fine-Tuning und führt durch eine minimale Python-Implementierung mit LangChain, Chroma und Wikipedia-Daten. Praktische Schritte umfassen Chunking, Indizierung, Abruf und Generierung.

RAG in Python: So bauen Sie es selbst!
Advertisement 728x90

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.

Google AdInline article slot

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:

Google AdInline article slot
  • 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 |

Google AdInline article slot

|--------------|---------------------------|----------------------------|

| 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

Advertisement 728x90

Weiterlesen