0Pricing
AI Engineering Academy · Pelajaran

Kompresi Kontekstual dan Penyaringan Relevansi

Terapkan kompresi kontekstual untuk menghapus kalimat yang tidak relevan dari potongan yang diambil sebelum memberikannya kepada LLM, sehingga mengurangi gangguan dan menghemat token.

Kompresi Kontekstual dan Penyaringan Relevansi adalah pelajaran AI Engineering Academy gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar AI Engineering Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus AI Engineering Academy mencakup 4 pelajaran total.

Masalah pada Potongan Hasil Pengambilan yang Berderau

Potongan hasil pengambilan sering berisi konten dengan relevansi campuran. Potongan sepanjang 500 token tentang pengindeksan basis data mungkin dapat menjawab dua kalimat pertama kueri, tetapi juga berisi enam kalimat materi yang tidak berkaitan tentang prosedur pencadangan. Mengirimkan seluruh potongan ini ke LLM membuang token, menurunkan rasio sinyal terhadap derau, dan dapat menyebabkan model menghasilkan jawaban yang didasarkan pada bagian yang tidak relevan, bukan pada kalimat yang relevan.

Apa Itu Kompresi Kontekstual?

Kompresi kontekstual adalah tahap setelah pengambilan yang mengambil setiap potongan hasil pengambilan dan mengekstrak hanya kalimat yang relevan dengan kueri sebelum meneruskan potongan tersebut ke LLM. Potongan asli dikompresi menjadi bagian-bagiannya yang paling relevan, sehingga mengurangi penggunaan token dan meningkatkan kualitas jawaban. ContextualCompressionRetriever milik LangChain membungkus retriever apa pun dengan komponen kompresor yang melakukan ekstraksi ini.

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: Penyaringan Relevansi

Alih-alih mengekstrak kalimat dari potongan, LLMChainFilter membuat keputusan biner: apakah potongan ini relevan dengan kueri atau tidak? Potongan yang tidak relevan dibuang sepenuhnya sebelum mencapai LLM. Cara ini lebih murah daripada ekstraksi karena panggilan ke LLM lebih singkat, serta berguna ketika potongan cukup pendek dan koheren sehingga ekstraksi sebagian tidak memberikan manfaat. Biasanya, 20–40 persen potongan yang awalnya diambil akan tersaring.

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')

Penyaringan Relevansi Berbasis Embedding

Menggunakan LLM untuk penyaringan menambah latensi dan biaya. Alternatif yang lebih murah adalah penyaringan berbasis embedding, yang menghitung kemiripan kosinus antara embedding kueri dan embedding setiap potongan, lalu membuang potongan yang berada di bawah ambang kemiripan. Cara ini deterministik, cepat, dan gratis—embedding yang telah dihitung selama pengambilan digunakan kembali tanpa panggilan LLM tambahan.

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')

Merangkai Beberapa Kompresor

Anda dapat merangkai beberapa kompresor secara berurutan menggunakan DocumentCompressorPipeline. Pola yang umum adalah terlebih dahulu menerapkan penyaring berbasis embedding yang cepat untuk menghapus potongan yang jelas tidak relevan, kemudian menerapkan pemisahan kalimat untuk memecah potongan panjang menjadi kalimat, dan terakhir menerapkan ekstraksi oleh LLM untuk mengambil kalimat yang paling relevan. Pendekatan berlapis ini menyeimbangkan biaya dan akurasi.

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,
)

Menghapus Potongan yang Berlebihan

Ketika beberapa potongan hasil pengambilan pada dasarnya menyampaikan hal yang sama, mengirimkan semuanya ke LLM membuang token tanpa menambahkan informasi. EmbeddingsRedundantFilter menghapus potongan yang hampir duplikat dengan menghitung kemiripan kosinus berpasangan dan membuang potongan yang terlalu mirip dengan potongan yang sudah dipilih. Cara ini sangat bermanfaat ketika korpus Anda memiliki banyak potongan yang saling tumpang tindih akibat pengaturan tumpang tindih yang tinggi selama proses penyerapan.

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')

Ekstraksi Relevansi Tingkat Kalimat

Untuk dokumen panjang yang konten relevannya tersebar di berbagai bagian, ekstraksi tingkat kalimat dengan cross-encoder memberikan presisi tertinggi. Nilai setiap kalimat dalam potongan hasil pengambilan terhadap kueri, pertahankan hanya kalimat yang berada di atas ambang, lalu susun kembali dokumen yang telah dikompresi. Pendekatan ini biasanya mengurangi ukuran konteks sebesar 40–70 persen sekaligus mempertahankan semua kalimat yang relevan.

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 chunk

Mengelola Anggaran Token melalui Kompresi

Kompresi kontekstual juga merupakan alat yang efektif untuk mengelola anggaran token. Jika Anda ingin meneruskan 5 dokumen ke model dengan jendela konteks terbatas, mengompresi masing-masing dokumen dari 500 token menjadi 100 token yang relevan memungkinkan Anda memuat informasi 5x lebih banyak. Hal ini sangat bermanfaat saat menggunakan model yang lebih kecil dan cepat seperti GPT-4o-mini, yang memiliki jendela konteks lebih pendek dan persyaratan latensi yang lebih ketat.

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 compressed

Mengukur Kualitas Kompresi

Kompresi menimbulkan risiko: Anda mungkin tidak sengaja menghapus kalimat yang penting untuk menjawab kueri. Ukur kualitas kompresi dengan membandingkan skor faithfulness sebelum dan sesudah kompresi menggunakan RAGAS atau penilai LLM khusus yang memeriksa apakah konteks terkompresi masih mendukung jawaban yang benar. Jika faithfulness menurun setelah kompresi, turunkan ambang atau gunakan ekstraksi alih-alih penyaringan.

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 sim

Kapan Harus Melewati Kompresi

Kompresi kontekstual tidak selalu bermanfaat. Untuk potongan pendek yang koheren (di bawah 200 token), seluruh potongan biasanya relevan sehingga kompresi hanya menambah latensi. Untuk dokumentasi teknis yang jawabannya bergantung pada semua bagian prosedur, misalnya urutan langkah bernomor, penyaringan setiap kalimat dapat menghapus langkah penting. Terapkan kompresi dengan bijaksana dan selalu validasi bahwa kompresi meningkatkan kualitas jawaban untuk kasus penggunaan tertentu.

Pipeline Kompresi Siap Produksi

Pipeline kompresi produksi yang tangguh menggabungkan penyaringan berbasis embedding (cepat dan murah), penghapusan redundansi (untuk menghindari pengulangan informasi yang sama), dan ekstraksi kalimat dengan cross-encoder opsional (akurat tetapi lebih lambat). Jalankan tahap-tahap cepat terlebih dahulu dan terapkan tahap berbasis LLM yang mahal hanya untuk kueri bernilai tinggi atau ketika tahap cepat masih menyisakan terlalu banyak potongan. Pendekatan adaptif ini mengoptimalkan biaya sekaligus kualitas.

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 docs

Pemeriksaan Singkat

Uji pemahaman Anda tentang kompresi kontekstual berdasarkan pelajaran ini.

Ringkasan Pelajaran

Dalam pelajaran ini Anda telah mempelajari: kompresi kontekstual mengurangi gangguan dengan mengekstrak atau menyaring konten yang tidak relevan dari potongan yang diambil sebelum mencapai LLM, DocumentCompressorPipeline menghubungkan beberapa kompresor (penyaring, penghapus duplikasi, pengekstrak) secara berurutan, dan penyaringan berbasis embedding menyediakan alternatif yang cepat dan murah dibandingkan kompresi berbasis LLM untuk sebagian besar skenario. Kompresi membantu mengelola anggaran token dan meningkatkan kualitas jawaban. Selanjutnya, kita akan mengukur dampak nyata pemeringkatan ulang terhadap kualitas pengambilan.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Kompresi Kontekstual dan Penyaringan Relevansi” gratis?

Ya — teks lengkap “Kompresi Kontekstual dan Penyaringan Relevansi” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus AI Engineering Academy, upgrade ke CoddyKit PRO. Kursus AI Engineering Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Kompresi Kontekstual dan Penyaringan Relevansi”?

Terapkan kompresi kontekstual untuk menghapus kalimat yang tidak relevan dari potongan yang diambil sebelum memberikannya kepada LLM, sehingga mengurangi gangguan dan menghemat token. Kamu berlatih AI Engineering Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai AI Engineering Academy?

Tidak diperlukan pengalaman sebelumnya. AI Engineering Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.

Berapa lama pelajaran “Kompresi Kontekstual dan Penyaringan Relevansi” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran AI Engineering Academy ini?

Ya. Setiap pelajaran AI Engineering Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Mengapa Pengambilan Dua Tahap Berhasil
  2. Pemeringkatan Ulang Cross-Encoder dengan Cohere dan BGE
  3. Kompresi Kontekstual dan Penyaringan Relevansi
  4. Mengukur Dampak Pemeringkatan Ulang
← Kembali ke AI Engineering Academy