Реализация 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-системы — наши инженеры помогут подобрать правильный компрессор.







