Kontextuelle Komprimierung und Relevanzfilterung
Wenden Sie kontextuelle Komprimierung an, um irrelevante Sätze aus abgerufenen Chunks zu entfernen, bevor Sie sie an das LLM übergeben. So reduzieren Sie Störinhalte und sparen Tokens.
Kontextuelle Komprimierung und Relevanzfilterung ist eine kostenlose AI Engineering Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des AI Engineering Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.
Das Problem verrauschter abgerufener Chunks
Abgerufene Chunks enthalten häufig Inhalte mit gemischter Relevanz. Ein Chunk mit 500 Tokens über Datenbankindizierung könnte zwar die ersten beiden Sätze der Abfrage beantworten, aber auch sechs Sätze mit themenfremden Informationen über Sicherungsverfahren enthalten. Wenn Sie den gesamten Chunk an das LLM senden, verschwenden Sie Tokens, verringern das Signal-Rausch-Verhältnis und riskieren, dass das Modell eine Antwort auf Grundlage des irrelevanten Abschnitts statt der relevanten Sätze erzeugt.
Was ist kontextuelle Komprimierung?
Kontextuelle Komprimierung ist ein Schritt nach dem Retrieval, der aus jedem abgerufenen Chunk nur die für die Abfrage relevanten Sätze extrahiert, bevor der Chunk an das LLM weitergegeben wird. Der ursprüngliche Chunk wird auf seine relevantesten Teile komprimiert, wodurch der Token-Verbrauch sinkt und die Antwortqualität steigt. LangChains ContextualCompressionRetriever umschließt jeden Retriever mit einer Komponente, die diese Extraktion durchführt.
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor
from langchain_openai import ChatOpenAI
# LLMChainExtractor uses an LLM to extract the relevant portion
llm = ChatOpenAI(model='gpt-4o-mini', temperature=0)
compressor = LLMChainExtractor.from_llm(llm)
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=base_retriever,
)
results = compression_retriever.invoke('how does HNSW indexing work?')
for doc in results:
print(len(doc.page_content), 'chars:', doc.page_content[:150])LLMChainFilter: Relevanzfilterung
Statt Sätze aus Chunks zu extrahieren, trifft LLMChainFilter eine binäre Entscheidung: Ist dieser Chunk für die Abfrage relevant oder nicht? Irrelevante Chunks werden vollständig entfernt, bevor sie das LLM erreichen. Das ist günstiger als eine Extraktion, da der LLM-Aufruf kürzer ist, und eignet sich, wenn Chunks kurz und zusammenhängend genug sind, dass eine teilweise Extraktion keinen Vorteil bringt. Typischerweise werden 20–40 Prozent der zunächst abgerufenen Chunks herausgefiltert.
from langchain.retrievers.document_compressors import LLMChainFilter
filter_compressor = LLMChainFilter.from_llm(
llm=ChatOpenAI(model='gpt-4o-mini', temperature=0)
)
filtering_retriever = ContextualCompressionRetriever(
base_compressor=filter_compressor,
base_retriever=base_retriever,
)
# Fetch 10 docs, filter drops irrelevant ones
results = filtering_retriever.invoke('what are the pgvector distance operators?')
print(f'{len(results)} chunks passed the relevance filter')Relevanzfilterung auf Embedding-Basis
Die Verwendung eines LLM zur Filterung verursacht zusätzliche Latenz und Kosten. Eine günstigere Alternative ist die Filterung auf Embedding-Basis: Dabei wird die Kosinusähnlichkeit zwischen dem Embedding der Abfrage und dem Embedding jedes Chunks berechnet. Chunks unterhalb eines Ähnlichkeitsschwellenwerts werden entfernt. Dieses Verfahren ist deterministisch, schnell und kostenlos – es verwendet die während des Retrievals bereits berechneten Embeddings wieder, ohne einen zusätzlichen LLM-Aufruf.
from langchain.retrievers.document_compressors import EmbeddingsFilter
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings()
embeddings_filter = EmbeddingsFilter(
embeddings=embeddings,
similarity_threshold=0.76, # cosine similarity threshold
)
embedding_retriever = ContextualCompressionRetriever(
base_compressor=embeddings_filter,
base_retriever=base_retriever,
)
results = embedding_retriever.invoke('BM25 hyperparameter tuning')
print(f'Filtered to {len(results)} relevant chunks')Mehrere Kompressoren verketten
Mit DocumentCompressorPipeline können Sie mehrere Kompressoren nacheinander verketten. Ein häufig verwendetes Muster besteht darin, zunächst einen schnellen Filter auf Embedding-Basis anzuwenden, um eindeutig irrelevante Chunks zu entfernen. Anschließend werden lange Chunks durch Satzsegmentierung in Sätze aufgeteilt, bevor die LLM-Extraktion die relevantesten Sätze herausfiltert. Dieser mehrschichtige Ansatz schafft ein ausgewogenes Verhältnis zwischen Kosten und Genauigkeit.
from langchain.retrievers.document_compressors import DocumentCompressorPipeline
from langchain_community.document_transformers import EmbeddingsRedundantFilter
from langchain_text_splitters import CharacterTextSplitter
# Step 1: split chunks into individual sentences
sentence_splitter = CharacterTextSplitter(
chunk_size=200,
chunk_overlap=0,
separator='. ',
)
# Step 2: remove redundant sentences via embeddings
redundant_filter = EmbeddingsRedundantFilter(embeddings=OpenAIEmbeddings())
# Step 3: keep only relevant sentences
relevance_filter = EmbeddingsFilter(embeddings=OpenAIEmbeddings(), similarity_threshold=0.76)
pipeline = DocumentCompressorPipeline(
transformers=[sentence_splitter, redundant_filter, relevance_filter]
)
piped_retriever = ContextualCompressionRetriever(
base_compressor=pipeline,
base_retriever=base_retriever,
)Redundante Chunks entfernen
Wenn mehrere abgerufene Chunks im Wesentlichen dasselbe aussagen, werden durch das Senden aller Chunks an das LLM Tokens verschwendet, ohne zusätzliche Informationen zu liefern. EmbeddingsRedundantFilter entfernt nahezu doppelte Chunks, indem paarweise die Kosinusähnlichkeit berechnet und Chunks verworfen werden, die bereits ausgewählten Chunks zu ähnlich sind. Das ist besonders wertvoll, wenn Ihr Korpus aufgrund hoher Überlappungswerte bei der Aufnahme viele überlappende Chunks enthält.
from langchain_community.document_transformers import EmbeddingsRedundantFilter
from langchain_core.documents import Document
redundant_filter = EmbeddingsRedundantFilter(
embeddings=OpenAIEmbeddings(),
similarity_threshold=0.95, # treat docs with >95% cosine sim as duplicates
)
# Simulate near-duplicate documents
docs = [
Document(page_content='pgvector is a PostgreSQL extension for vector similarity search'),
Document(page_content='pgvector extends PostgreSQL to support vector similarity search'), # near duplicate
Document(page_content='HNSW and IVFFlat are the two index types in pgvector'),
]
filtered = redundant_filter.transform_documents(docs, query='')
print(f'Kept {len(filtered)} of {len(docs)} documents after deduplication')Relevanzextraktion auf Satzebene
Bei langen Dokumenten, in denen relevante Inhalte über den gesamten Text verteilt sind, bietet die Extraktion auf Satzebene mit einem Cross-Encoder die höchste Präzision. Bewerten Sie jeden Satz im abgerufenen Chunk im Verhältnis zur Abfrage, behalten Sie nur Sätze oberhalb eines Schwellenwerts und setzen Sie daraus ein komprimiertes Dokument zusammen. Dieser Ansatz reduziert die Kontextgröße typischerweise um 40–70 Prozent, während alle relevanten Sätze erhalten bleiben.
from sentence_transformers import CrossEncoder
import re
sentence_reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
def compress_with_cross_encoder(
query: str, chunk: str, min_score: float = 0.0
) -> str:
sentences = re.split(r'(?<=[.!?]) +', chunk)
if len(sentences) <= 1:
return chunk
pairs = [[query, s] for s in sentences]
scores = sentence_reranker.predict(pairs)
relevant = [
sentence
for sentence, score in zip(sentences, scores)
if float(score) >= min_score
]
return ' '.join(relevant) if relevant else chunkToken-Budget-Verwaltung durch Komprimierung
Kontextuelle Komprimierung ist außerdem ein effektives Werkzeug für das Management des Token-Budgets. Wenn Sie einem Modell mit begrenztem Kontextfenster fünf Dokumente übergeben möchten, können Sie fünfmal mehr Informationen unterbringen, indem Sie jedes Dokument von 500 auf 100 relevante Tokens komprimieren. Das ist besonders wertvoll bei der Arbeit mit kleineren, schnelleren Modellen wie GPT-4o-mini, die kürzere Kontextfenster und strengere Latenzanforderungen haben.
def compress_to_budget(
query: str,
docs: list[str],
total_token_budget: int = 2000,
tokens_per_char: float = 0.25,
) -> list[str]:
compressed = []
used_tokens = 0
for doc in docs:
compressed_doc = compress_with_cross_encoder(query, doc)
doc_tokens = int(len(compressed_doc) * tokens_per_char)
if used_tokens + doc_tokens <= total_token_budget:
compressed.append(compressed_doc)
used_tokens += doc_tokens
else:
break # stop when budget is exhausted
print(f'Using {used_tokens} tokens across {len(compressed)} docs')
return compressedQualität der Komprimierung messen
Komprimierung birgt ein Risiko: Sie könnten versehentlich einen Satz entfernen, der für die Beantwortung der Anfrage entscheidend ist. Messen Sie die Qualität der Komprimierung, indem Sie die Faithfulness-Werte vor und nach der Komprimierung vergleichen. Verwenden Sie dazu RAGAS oder einen benutzerdefinierten LLM-Judge, der prüft, ob der komprimierte Kontext weiterhin die korrekte Antwort stützt. Wenn die Faktentreue nach der Komprimierung sinkt, senken Sie den Schwellenwert oder wechseln Sie statt des Filterns zur Extraktion.
def measure_compression_faithfulness(query, original_docs, compressed_docs, llm):
# Use LLM to check if answer from compressed context matches
# answer from full context
def generate_answer(docs, q):
context = '\n'.join(docs)
resp = llm.invoke(f'Answer from context:\n{context}\nQ: {q}')
return resp.content
full_answer = generate_answer([d.page_content for d in original_docs], query)
comp_answer = generate_answer(compressed_docs, query)
# Check semantic similarity between answers
vecs = [embed(full_answer), embed(comp_answer)]
sim = cosine_similarity(vecs[0], vecs[1])
print(f'Answer similarity after compression: {sim:.3f}')
return simWann Sie auf Komprimierung verzichten sollten
Kontextuelle Komprimierung ist nicht immer vorteilhaft. Bei kurzen, zusammenhängenden Chunks (unter 200 Tokens) ist normalerweise der gesamte Chunk relevant, und die Komprimierung verursacht lediglich zusätzliche Latenz. Bei technischer Dokumentation, bei der die Antwort von allen Teilen einer Vorgehensweise abhängt (z. B. einer nummerierten Schrittfolge), kann das Filtern einzelner Sätze wichtige Schritte entfernen. Setzen Sie Komprimierung mit Bedacht ein und überprüfen Sie stets, ob sie die Antwortqualität für Ihren konkreten Anwendungsfall verbessert.
Produktionsreife Komprimierungspipeline
Eine robuste Komprimierungspipeline für den Produktionseinsatz kombiniert Embedding-basiertes Filtern (schnell und kostengünstig), Entfernen von Redundanzen (um Wiederholungen derselben Informationen zu vermeiden) und optional die Extraktion von Sätzen mit einem Cross-Encoder (präzise, aber langsamer). Führen Sie die schnellen Schritte zuerst aus und wenden Sie den aufwendigen LLM-basierten Schritt nur auf besonders wichtige Anfragen an oder wenn nach den schnellen Schritten zu viele Chunks verbleiben. Dieser adaptive Ansatz optimiert sowohl Kosten als auch Qualität.
class AdaptiveCompressor:
def __init__(self, embeddings, cross_encoder=None, threshold=0.76):
self.emb_filter = EmbeddingsFilter(embeddings=embeddings,
similarity_threshold=threshold)
self.dedup = EmbeddingsRedundantFilter(embeddings=embeddings)
self.cross_encoder = cross_encoder
def compress(self, query: str, docs, use_cross_encoder: bool = False):
# Stage 1: embedding filter
docs = self.emb_filter.compress_documents(docs, query=query)
# Stage 2: deduplication
docs = self.dedup.transform_documents(docs, query=query)
# Stage 3: optional sentence-level extraction
if use_cross_encoder and self.cross_encoder:
docs = [
type(d)(page_content=compress_with_cross_encoder(
query, d.page_content
), metadata=d.metadata)
for d in docs
]
return docsKurzer Test
Testen Sie Ihr Verständnis der kontextuellen Komprimierung aus dieser Lektion.
Zusammenfassung der Lektion
In dieser Lektion haben Sie gelernt: Kontextuelle Komprimierung reduziert Rauschen, indem irrelevante Inhalte aus abgerufenen Chunks extrahiert oder herausgefiltert werden, bevor diese das LLM erreichen. Die DocumentCompressorPipeline verkettet mehrere Komprimierer (Filtern, Deduplizieren, Extrahieren) in einer Abfolge, und Embedding-basiertes Filtern bietet in den meisten Szenarien eine schnelle und kostengünstige Alternative zur LLM-basierten Komprimierung. Komprimierung hilft bei der Verwaltung von Token-Budgets und verbessert die Antwortqualität. Als Nächstes messen wir die tatsächlichen Auswirkungen von Re-Ranking auf die Qualität des Retrievals.
Häufig gestellte Fragen
Ist die Lektion „Kontextuelle Komprimierung und Relevanzfilterung“ kostenlos?
Ja — der vollständige Text von „Kontextuelle Komprimierung und Relevanzfilterung“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des AI Engineering Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Kontextuelle Komprimierung und Relevanzfilterung“?
Wenden Sie kontextuelle Komprimierung an, um irrelevante Sätze aus abgerufenen Chunks zu entfernen, bevor Sie sie an das LLM übergeben. So reduzieren Sie Störinhalte und sparen Tokens. Du übst AI Engineering Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um AI Engineering Academy zu starten?
Keine Vorkenntnisse erforderlich. AI Engineering Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.
Wie lange dauert die Lektion „Kontextuelle Komprimierung und Relevanzfilterung“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser AI Engineering Academy-Lektion Code schreiben und ausführen?
Ja. Jede AI Engineering Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Warum zweistufiger Abruf funktioniert
- Cross-Encoder-Re-Ranking mit Cohere und BGE
- Kontextuelle Komprimierung und Relevanzfilterung
- Die Auswirkungen des Re-Rankings messen