Реалізація Contextual Compression для RAG
Уявіть: ваша RAG-система городить контекст із 10 чанків по 800 токенів, а корисної інформації — на 100 токенів. LLM платить за шум, а відповіді — каша. Типовий кейс — підтримка технічної документації: 10 чанків, релевантні 2–3. Кожен чанк важить близько 800 токенів, а корисної інформації — на 100. LLM витрачає контекстне вікно на нерелевантний текст, що призводить до галюцинацій і неповних відповідей. Тратиться контекст, зростає вартість. Contextual Compression — техніка, яка викушує з кожного чанка лише релевантний запиту фрагмент. Знижуємо шум, скорочуємо токени, підвищуємо faithfulness. За час роботи в AI/ML ми впровадили це в 15+ проєктах — ділимося досвідом. Отримайте консультацію з оптимізації вашої RAG-системи.
Проблема без Contextual Compression
Стандартний RAG передає LLM повні чанки (512–1024 токена). Типова картина: чанк містить 600 токенів, з яких 80 дійсно відповідають на питання, решта — нерелевантний контекст. Це:
- Збільшує вартість (більше input tokens)
- Знижує точність (LLM «губиться» у нерелевантному тексті)
- Зменшує effective context window (менше місця для дійсно важливих чанків)
Як працює LLM-based Contextual Compression?
from langchain.retrievers import ContextualCompressionRetriever from langchain.retrievers.document_compressors import LLMChainExtractor from langchain_openai import ChatOpenAI # Компресор на основі LLM llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) compressor = LLMChainExtractor.from_llm(llm) compression_retriever = ContextualCompressionRetriever( base_compressor=compressor, base_retriever=vectorstore.as_retriever(search_kwargs={"k": 8}), ) compressed_docs = compression_retriever.invoke( "Який порядок погодження договорів?" ) # Кожен документ містить лише релевантний фрагмент for doc in compressed_docs: print(len(doc.page_content), "chars (vs оригінальних ~2000)") Згідно з документацією LangChain, LLMChainExtractor використовує ту саму LLM для вилучення релевантного контенту. Це дає високу точність, але збільшує latency.
Коли використовувати Embedding-based Compressor?
Швидший і дешевший варіант — фільтрація за косинусною схожістю. Ми часто використовуємо його як перший етап пайплайну:
from langchain.retrievers.document_compressors import EmbeddingsFilter from langchain_openai import OpenAIEmbeddings embeddings = OpenAIEmbeddings() embeddings_filter = EmbeddingsFilter( embeddings=embeddings, similarity_threshold=0.76, ) filtering_retriever = ContextualCompressionRetriever( base_compressor=embeddings_filter, base_retriever=vectorstore.as_retriever(search_kwargs={"k": 8}), ) Поріг 0.76 – емпіричне значення, яке дає хороший баланс між повнотою та точністю. Для вашого датасету його потрібно калібрувати.
Чому варто комбінувати Compression і Reranking?
EmbeddingsFilter відсікає явно нерелевантні чанки, але не ранжує решту. Cross-encoder reranker (наприклад, BAAI/bge-reranker-large) дає більш точне сортування за релевантністю, але дорожчий. Комбінація дає золоту середину: фільтр прибирає 40–60% чанків, reranker уточнює порядок top-N. Pipeline з Filter і Reranker дає faithfulness на 15% вищий, ніж без компресії, при цьому в 2,5 рази дешевший за LLM Extractor.
Порівняємо методи:
| Метод | Cost per query | Latency p99 | Faithfulness gain |
|---|---|---|---|
| Без compression | 1× | 1.8 с | — |
| EmbeddingsFilter | 0.2× | 0.3 с | +8% |
| LLM Extractor | 0.5× | 2.4 с | +19% |
| Pipeline (Filter + Reranker) | 0.4× | 0.9 с | +15% |
Як побудувати Pipeline з Compression і Reranking?
from langchain.retrievers.document_compressors import DocumentCompressorPipeline from langchain_community.document_transformers import EmbeddingsRedundantFilter from langchain.retrievers.document_compressors import CrossEncoderReranker from langchain_community.cross_encoders import HuggingFaceCrossEncoder cross_encoder = HuggingFaceCrossEncoder(model_name="BAAI/bge-reranker-large") reranker = CrossEncoderReranker(model=cross_encoder, top_n=3) compressor_pipeline = DocumentCompressorPipeline( transformers=[ EmbeddingsFilter(embeddings=embeddings, similarity_threshold=0.75), EmbeddingsRedundantFilter(embeddings=embeddings), reranker, ] ) pipeline_retriever = ContextualCompressionRetriever( base_compressor=compressor_pipeline, base_retriever=vectorstore.as_retriever(search_kwargs={"k": 10}), ) Який компресор обрати для вашого сценарію?
У production ми віддаємо перевагу гібридному підходу: EmbeddingsFilter для фільтрації шуму, потім LLM-компресор для ключових запитів, де важлива висока точність. Якщо latency критична — використовуємо лише EmbeddingsFilter з низьким порогом (0.7–0.75).
Кроки впровадження Contextual Compression
- Аудит поточної RAG-системи: метрики, вузькі місця, сценарії.
- Вибір та калібрування компресора (LLM / Embedding / Pipeline).
- Інтеграція через LangChain або кастомний код.
- Тестування: faithfulness, relevancy, latency, cost.
- Документація та навчання команди.
- Моніторинг та оптимізація threshold під нові дані.
Практичний кейс: з практики нашого клієнта
Завдання: асистент для технічних мануалів (чанки ~800 токенів). Після compression середній контекст зменшився з 4800 до 1200 токенів на запит.
| Метрика | Без Compression | З Compression (LLM) |
|---|---|---|
| Input tokens/запит | 5200 | 1450 |
| Faithfulness (RAGAS) | 0.79 | 0.94 |
| Answer Relevancy | 0.81 | 0.89 |
| Вартість (GPT-4o-mini) | 1× | 0.3× |
| Latency | 1.8с | 2.4с (+compression LLM) |
Стиснення знизило вартість у 3.3× при зростанні faithfulness на 19%. Наші інженери підібрали threshold та модель компресора за 2 дні, ще 2 дні пішло на інтеграцію.
Що входить у реалізацію
- Аудит поточної RAG-системи: метрики, вузькі місця, сценарії
- Вибір та калібрування компресора (LLM / Embedding / Pipeline)
- Інтеграція через LangChain або кастомний код
- Тестування: faithfulness, relevancy, latency, cost
- Документація та навчання команди
- Гарантія на результати оптимізації за KPI
Ми супроводжуємо проєкт після впровадження — фіксимо threshold під нові дані, додаємо моніторинг. Замовте оптимізацію вашої RAG-системи та отримайте зниження токенів до 4 разів. Зв'яжіться з нами для обговорення вашого кейсу.
Терміни та вартість
- Базова інтеграція: від 2 днів
- Калібрування та тестування: 2–3 дні
- Повний цикл (включаючи pipeline та reranker): 1 тиждень
Вартість розраховується індивідуально під обсяг даних та вимоги. Середня економія на токенах — 60–70%. Замовте оптимізацію вашої RAG-системи — наші інженери допоможуть підібрати правильний компресор.







