Standard-RAG (Retrieve → Generate) funktioniert für einfache Fälle. Aber komplexe Szenarien erfordern fortgeschrittene Patterns: HyDE, Parent-Child-Chunking, Agentic RAG und Graph RAG.
Das Problem: Die Query "Was sind Best Practices für API-Security?" hat ein anderes Embedding als ein Dokument, das diese Best Practices beschreibt.
Generiere eine hypothetische Antwort und nutze deren Embedding für die Suche:
def hyde_retrieve(question: str, retriever, llm):
# 1. Hypothetische Antwort generieren
hypothetical = llm.invoke(
f"Schreibe eine detaillierte Antwort auf: {question}"
)
# 2. Embedding der hypothetischen Antwort für Retrieval nutzen
results = retriever.invoke(hypothetical.content)
return results
| Szenario | HyDE hilfreich? |
|---|---|
| Frage nach Fakten | Nein — direkte Suche reicht |
| Konzeptuelle Fragen | Ja — bessere semantische Übereinstimmung |
| Fragen mit Fachbegriffen | Ja — hypothetische Antwort enthält verwandte Begriffe |
| Kurze, vage Fragen | Ja — HyDE erweitert den Query-Kontext |
Das Dilemma: Kleine Chunks liefern präzise Retrieval-Ergebnisse, aber zu wenig Kontext. Große Chunks liefern Kontext, aber unpräzise Ergebnisse.
# Parent-Chunks: Große Abschnitte (2000 Token)
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000)
parent_chunks = parent_splitter.split_documents(docs)
# Child-Chunks: Kleine Abschnitte (400 Token)
child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
child_chunks = []
for parent in parent_chunks:
children = child_splitter.split_documents([parent])
for child in children:
child.metadata["parent_id"] = parent.metadata["id"]
child_chunks.extend(children)
# Retrieval: Suche über Child-Chunks
# Context: Liefere Parent-Chunk an LLM
Suche über: [Child 1] [Child 2] [Child 3] ← Präzise Matches
↓
Liefere an LLM: [────── Parent Chunk ──────] ← Voller Kontext
Ein Agent entscheidet dynamisch über die Retrieval-Strategie:
def agentic_rag(question: str):
# Agent entscheidet: Welche Datenquelle? Wie viele Hops? Filter?
plan = agent.plan(question)
if plan.needs_structured_data:
results = sql_retriever.invoke(plan.sql_query)
elif plan.needs_multiple_sources:
results = multi_source_retrieve(plan.sources, question)
else:
results = vector_retriever.invoke(question)
if plan.needs_verification:
results = verify_and_filter(results, question)
return generate_answer(question, results)
Frage → Agent (Planer)
│
├── "Einfache Faktenfrage" → Vector Retrieval → Antwort
├── "SQL nötig" → Text-to-SQL → DB-Abfrage → Antwort
├── "Mehrere Quellen" → Multi-Source Retrieval → Merge → Antwort
└── "Nicht genug Info" → Web Search → Antwort
Graph RAG kombiniert Vektor-Suche mit Knowledge Graphs für strukturiertes Wissen:
Dokumente → Entity Extraction → Knowledge Graph
↕
Vektor-Datenbank
Query → Graph Traversal + Vector Search → Merged Context → LLM
| Aspekt | Standard RAG | Graph RAG |
|---|---|---|
| Beziehungen | Implizit in Chunks | Explizit im Graph |
| Multi-Hop | Schwierig | Natürlich (Graph Traversal) |
| Aggregation | LLM muss zusammenfassen | Graph-Queries aggregieren |
| Transparenz | Chunks als Quelle | Entities und Relations als Quelle |
Verschiedene Datentypen in unterschiedlichen Indizes:
indices = {
"docs": vectorstore_docs, # Dokumentation
"code": vectorstore_code, # Source Code
"tickets": vectorstore_tickets, # Support-Tickets
"faq": vectorstore_faq # FAQ
}
def smart_retrieve(question: str):
# Router entscheidet, welche Indizes relevant sind
relevant_indices = route_to_indices(question)
results = []
for index_name in relevant_indices:
results.extend(indices[index_name].similarity_search(question, k=3))
return rerank(results, question)
Praxis-Tipp: Implementieren Sie Advanced Patterns nur, wenn Standard-RAG nachweislich nicht reicht. Messen Sie die Retrieval-Qualität mit Metriken (siehe Lektion 5), bevor Sie HyDE, Graph RAG oder Agentic RAG einführen. Jedes Pattern erhöht Komplexität und Kosten.