Dense Retrieval: Semantische Suche mit Embeddings
Beherrschen Sie Dense Retrieval für eine leistungsfähige semantische Suche. Embeddings, Modelle, vektorielle Indexierung und fortgeschrittene Optimierungen.
Dense Retrieval: Semantische Suche mit Embeddings
Dense Retrieval revolutioniert die Informationssuche, indem es die tiefere Bedeutung von Anfragen und Dokumenten erfasst. Im Gegensatz zur lexikalischen Suche, die Wörter vergleicht, vergleicht Dense Retrieval Konzepte. Dieser Leitfaden vertieft die Mechanismen, Modelle und Techniken zur Implementierung einer leistungsstarken semantischen Suche in Ihren RAG-Systemen.
Was ist Dense Retrieval?
Dense Retrieval stellt jeden Text als einen dichten Vektor reeller Zahlen dar, typischerweise mit 384 bis 4096 Dimensionen. Diese Vektoren, genannt Embeddings, erfassen die Semantik des Textes in einem mathematischen Raum, in dem ähnliche Konzepte nahe beieinander liegen.
Unterschied zum Sparse Retrieval
| Eigenschaft | Dense Retrieval | Sparse Retrieval |
|---|---|---|
| Darstellung | Dichte Vektoren (384-4096 Dim.) | Sparse-Vektoren (Vokabular) |
| Zuordnung | Semantisch | Lexikalisch |
| "Auto" = "Automobil" | Ja | Nein |
| Seltene Begriffe | Weniger leistungsfähig | Hervorragend |
| Tippfehler und Varianten | Robust | Empfindlich |
Dense Retrieval ist besonders stark, wenn der Nutzer seine Anfrage anders formuliert als der Quellinhalt. "Wie storniere ich meine Bestellung" findet "Verfahren zur Kaufrückabwicklung", selbst ohne gemeinsame Wörter.
Architektur eines Dense-Retrieval-Systems
┌──────────────────────────────────────────────────────────────┐
│ Pipeline Dense Retrieval │
├──────────────────────────────────────────────────────────────┤
│ │
│ Documents Modèle Base Vectorielle │
│ ┌─────────┐ Embedding ┌──────────────┐ │
│ │ Doc 1 │──┐ ┌───────┐ ┌───│ Qdrant │ │
│ │ Doc 2 │──┼───▶│ E5 │────┼───│ Pinecone │ │
│ │ Doc 3 │──┘ │ BGE │ │ │ Weaviate │ │
│ └─────────┘ └───────┘ │ └──────────────┘ │
│ │ │ │
│ Query │ │ ANN Search │
│ ┌─────────┐ │ ▼ │
│ │"Comment │────────────────────┘ ┌──────────────┐ │
│ │annuler" │ │ Top-K docs │ │
│ └─────────┘ └──────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
Embedding-Modelle: Der Vergleich 2024
Die Wahl des Embedding-Modells wirkt sich direkt auf die Qualität Ihres Retrieval aus. Hier sind die aktuellen Optionen, geordnet nach Performance in den MTEB-Benchmarks.
Open-Source-Modelle
DEVELOPERpythonfrom sentence_transformers import SentenceTransformer # BGE-M3 : Meilleur rapport qualité/performance multilingue model_bge = SentenceTransformer('BAAI/bge-m3') # E5-Large : Excellent pour le français model_e5 = SentenceTransformer('intfloat/multilingual-e5-large') # GTE-Large : Alternative performante model_gte = SentenceTransformer('thenlper/gte-large')
| Modell | Dimensionen | MTEB FR | Geschwindigkeit | Einsatz |
|---|---|---|---|---|
| BGE-M3 | 1024 | 62.3 | Mittel | Mehrsprachige Produktion |
| E5-Large-v2 | 1024 | 61.8 | Mittel | Französisch-Priorität |
| GTE-Large | 1024 | 60.2 | Schnell | Hohes Volumen |
| All-MiniLM | 384 | 52.1 | Sehr schnell | Prototyping |
Proprietäre Modelle
DEVELOPERpythonimport openai # OpenAI text-embedding-3 client = openai.OpenAI() response = client.embeddings.create( model="text-embedding-3-large", input="Comment annuler ma commande ?", dimensions=1536 # Configurable jusqu'à 3072 ) embedding = response.data[0].embedding # Cohere Embed v4 import cohere co = cohere.Client() response = co.embed( texts=["Comment annuler ma commande ?"], model="embed-v4.0", input_type="search_query" )
| Modell | Dimensionen | Performance | Kosten/1M Tokens |
|---|---|---|---|
| text-embedding-3-large | 3072 | Hervorragend | $0,13 |
| text-embedding-3-small | 1536 | Sehr gut | $0,02 |
| Cohere embed-v4 | 1536 | Hervorragend | $0,12 |
| Voyage-3.5 | 1024 | State of the Art | $0,06 |
(API-Preise: Juli 2026)
Qualität der Embeddings optimieren
Query-/Passage-Präfixe
Einige Modelle erfordern Präfixe, um Anfragen von Dokumenten zu unterscheiden:
DEVELOPERpythonfrom sentence_transformers import SentenceTransformer model = SentenceTransformer('intfloat/multilingual-e5-large') # IMPORTANT : Préfixer correctement query = "query: Comment fonctionne la garantie ?" passages = [ "passage: La garantie couvre les défauts pendant 2 ans.", "passage: Contactez le SAV pour toute réclamation." ] query_embedding = model.encode(query) passage_embeddings = model.encode(passages)
Ohne diese Präfixe kann die Performance in Benchmarks um 5 bis 15 Punkte sinken.
Normalisierung der Embeddings
Um das Skalarprodukt anstelle der Kosinusähnlichkeit zu verwenden (schneller):
DEVELOPERpythonimport numpy as np def normalize(embeddings): norms = np.linalg.norm(embeddings, axis=1, keepdims=True) return embeddings / norms # Embeddings normalisés embeddings_norm = normalize(embeddings) # Maintenant dot product = cosine similarity similarity = np.dot(query_norm, doc_norm.T)
Matryoshka Embeddings
Neuere Modelle unterstützen "Matryoshka Embeddings": Embeddings, bei denen die ersten Dimensionen am informativsten sind.
DEVELOPERpython# Avec text-embedding-3, vous pouvez réduire les dimensions response = client.embeddings.create( model="text-embedding-3-large", input=texts, dimensions=512 # Au lieu de 3072, avec perte minime ) # Recherche rapide avec dimensions réduites # puis reranking avec dimensions complètes
Dies ermöglicht einen konfigurierbaren Kompromiss zwischen Geschwindigkeit und Präzision.
Fortgeschrittene Vektorindexierung
ANN-Algorithmen (Approximate Nearest Neighbor)
Die exakte Suche (Brute Force) hat O(n). ANN-Algorithmen reduzieren auf O(log n) mit einem geringen Präzisionsverlust.
HNSW (Hierarchical Navigable Small Worlds)
Am häufigsten verwendet. Hervorragender Kompromiss zwischen Geschwindigkeit und Präzision.
DEVELOPERpythonfrom qdrant_client import QdrantClient from qdrant_client.models import VectorParams, HnswConfigDiff client = QdrantClient("localhost", port=6333) # Configuration HNSW optimisée client.create_collection( collection_name="documents", vectors_config=VectorParams( size=1024, distance="Cosine" ), hnsw_config=HnswConfigDiff( m=16, # Connexions par nœud (16-64) ef_construct=100, # Qualité de construction ) ) # À la recherche, ajuster ef pour précision/vitesse results = client.search( collection_name="documents", query_vector=query_embedding, limit=10, search_params={"ef": 128} # Plus haut = plus précis, plus lent )
IVF (Inverted File Index)
Teilt den Raum in Cluster. Schneller, aber weniger präzise.
DEVELOPERpython# Avec FAISS import faiss # Créer l'index IVF dimension = 1024 nlist = 100 # Nombre de clusters quantizer = faiss.IndexFlatL2(dimension) index = faiss.IndexIVFFlat(quantizer, dimension, nlist) # Entraîner sur les données index.train(embeddings) index.add(embeddings) # Recherche avec nprobe clusters index.nprobe = 10 # Plus haut = plus précis distances, indices = index.search(query_embedding, k=10)
Quantisierung zur Speicherreduzierung
Vektorgröße um 75% reduzieren bei minimalem Verlust:
DEVELOPERpython# Quantification scalaire (int8) from qdrant_client.models import QuantizationConfig, ScalarQuantization client.create_collection( collection_name="documents_quantized", vectors_config=VectorParams(size=1024, distance="Cosine"), quantization_config=QuantizationConfig( scalar=ScalarQuantization( type="int8", quantile=0.99, always_ram=True ) ) ) # 1M vecteurs 1024d : 4GB → 1GB # Perte de recall : ~1-2%
Bewertung des Dense Retrieval
Wesentliche Metriken
DEVELOPERpythondef evaluate_retrieval(queries, ground_truth, retriever, k_values=[1, 5, 10]): metrics = {} for k in k_values: recalls = [] precisions = [] for query, relevant_docs in zip(queries, ground_truth): retrieved = retriever.search(query, top_k=k) retrieved_ids = [doc.id for doc in retrieved] # Recall@k hits = len(set(retrieved_ids) & set(relevant_docs)) recall = hits / len(relevant_docs) recalls.append(recall) # Precision@k precision = hits / k precisions.append(precision) metrics[f"recall@{k}"] = np.mean(recalls) metrics[f"precision@{k}"] = np.mean(precisions) # MRR mrr_scores = [] for query, relevant_docs in zip(queries, ground_truth): retrieved = retriever.search(query, top_k=100) for i, doc in enumerate(retrieved): if doc.id in relevant_docs: mrr_scores.append(1 / (i + 1)) break else: mrr_scores.append(0) metrics["mrr"] = np.mean(mrr_scores) return metrics
Empfohlene Benchmarks
- BEIR: Multi-Domain-Benchmark für Retrieval
- MTEB: Massive Text Embedding Benchmark
- MS MARCO: Web-basierter Frage-Antwort-Benchmark
Häufige Fallstricke und Lösungen
1. Domain Shift
Generische Modelle zeigen bei spezialisiertem Vokabular eine schwache Performance.
Lösung: Kontrastives Fine-Tuning
DEVELOPERpythonfrom sentence_transformers import SentenceTransformer, InputExample, losses model = SentenceTransformer('BAAI/bge-m3') # Données d'entraînement : paires (query, positive_doc) train_examples = [ InputExample(texts=["Symptômes COVID", "Fièvre, toux sèche, fatigue"]), InputExample(texts=["Traitement grippe", "Repos, hydratation, paracétamol"]), ] # Loss contrastive train_loss = losses.MultipleNegativesRankingLoss(model) # Fine-tuning model.fit( train_objectives=[(train_dataloader, train_loss)], epochs=3, warmup_steps=100 )
2. Kurze Anfragen
Anfragen mit 1-2 Wörtern erzeugen wenig unterscheidungskräftige Embeddings.
Lösung: Query Expansion
DEVELOPERpythondef expand_query(query: str, llm) -> str: if len(query.split()) <= 3: expansion = llm.complete( f"Reformule cette recherche en une phrase complète: {query}" ) return f"{query} {expansion}" return query
3. Lange Dokumente
Embeddings von zu langen Dokumenten verlieren an Präzision.
Lösung: Late Interaction oder Chunking mit Aggregation
DEVELOPERpythondef embed_long_document(doc: str, model, chunk_size=512): chunks = split_into_chunks(doc, chunk_size) chunk_embeddings = model.encode(chunks) # Agrégation : moyenne pondérée par position weights = np.exp(-np.arange(len(chunks)) * 0.1) weights /= weights.sum() return np.average(chunk_embeddings, axis=0, weights=weights)
Integration in eine RAG-Pipeline
DEVELOPERpythonclass DenseRetriever: def __init__(self, model_name: str, collection: str): self.model = SentenceTransformer(model_name) self.client = QdrantClient("localhost", port=6333) self.collection = collection def index(self, documents: list[dict]): embeddings = self.model.encode( [doc["content"] for doc in documents], show_progress_bar=True ) points = [ PointStruct( id=doc["id"], vector=emb.tolist(), payload={"content": doc["content"], **doc.get("metadata", {})} ) for doc, emb in zip(documents, embeddings) ] self.client.upsert(collection_name=self.collection, points=points) def search(self, query: str, top_k: int = 5, filters: dict = None): query_embedding = self.model.encode(f"query: {query}") filter_conditions = self._build_filters(filters) if filters else None results = self.client.search( collection_name=self.collection, query_vector=query_embedding.tolist(), query_filter=filter_conditions, limit=top_k ) return [ {"content": hit.payload["content"], "score": hit.score} for hit in results ]
Nächste Schritte
Dense Retrieval ist leistungsstark, aber nicht universell einsetzbar. In bestimmten Fällen bleibt die lexikalische Suche überlegen. Erfahren Sie mehr in unseren verwandten Leitfäden:
- Sparse Retrieval und BM25 - Wann die lexikalische Suche besser ist
- Hybride Fusion - Dense und Sparse kombinieren
- Retrieval-Grundlagen - Überblick
FAQ
Starten Sie mit Dense Retrieval mit Ailog
Die Implementierung eines leistungsstarken Dense-Retrieval-Systems erfordert Expertise und Infrastruktur. Mit Ailog profitieren Sie von:
- Optimierten Embedding-Modellen für Französisch (BGE-M3, E5-Large)
- Automatischer HNSW-Indexierung mit Qdrant
- Intelligenter Quantisierung zur Optimierung von Kosten und Performance
- Unterstütztem Fine-Tuning auf Ihr Fachvokabular
Kostenlos testen und Ihre semantische Suche in Minuten bereitstellen.
Tags
Verwandte Artikel
Query Routing: Anfragen an die richtige Quelle weiterleiten
Implementieren Sie Query Routing, um jede Anfrage zur optimalen Datenquelle zu leiten. Klassifizierung, LLM-Routing und fortgeschrittene Strategien.
Filtern nach Metadaten: RAG-Suche verfeinern
Beherrschen Sie das Filtern nach Metadaten für präzise RAG-Suchen. Filtertypen, Indexierung, kombinierte Abfragen und Optimierung.
Ensemble Retrieval: Mehrere retrievers kombinieren
Implementieren Sie Ensemble Retrieval, um die Stärken mehrerer retrievers zu kombinieren. Voting, stacking und fortgeschrittene Fusionsstrategien.