Skip to main content

ragcompress

Extractive, provenance-preserving context compression for RAG pipelines.

ragcompress is a drop-in reranker/compression stage between your retriever and your generator LLM. Given a query and a list of retrieved chunks, it selects the minimal set of original, verbatim sentences needed to answer the query — instead of summarizing (which can hallucinate) or truncating to a fixed top-k (which wastes budget on irrelevant sentences inside relevant chunks).

retriever ──> [ragcompress] ──> generator LLM
              keeps only the sentences the query needs,
              verbatim, with per-sentence source attribution

Why

  • Extractive, never abstractive. Every output sentence exists verbatim in an input chunk. Nothing is paraphrased, so the compression stage cannot hallucinate — and citations stay valid.
  • Provenance built in. Each kept sentence carries its source doc_id and chunk_id, queryable on the result object and optionally inlined as [doc_id] markers in the context string.
  • Adaptive token budget. Instead of a fixed top-k, an elbow-detection budget keeps sentences until relevance falls off a cliff — short context for easy questions, longer for multi-hop ones.
  • Framework-native adapters. A LlamaIndex NodePostprocessor and a LangChain BaseDocumentCompressor (drop-in for ContextualCompressionRetriever).
  • CPU-friendly. The default scorer is a small pretrained cross-encoder (ms-marco-MiniLM-L-6-v2) plus a MiniLM embedder for redundancy removal — no fine-tuning, no GPU required.

Install

pip install ragcompress                # core
pip install ragcompress[llamaindex]    # + LlamaIndex adapter
pip install ragcompress[langchain]     # + LangChain adapter
pip install ragcompress[attention]     # + attention-based scorer (local HF models)
pip install ragcompress[benchmarks]    # + benchmark suite deps

Quickstart

from ragcompress import Chunk, Compressor, FixedBudget

chunks = [
    Chunk(doc_id="dune-wiki", chunk_id="c0", text="Dune is a novel by Frank Herbert. ..."),
    # ... more retrieved chunks
]

compressor = Compressor(budget=FixedBudget(max_tokens=500))
result = compressor.compress("Who wrote Dune?", chunks)

result.text  # compressed context, ready for your prompt
result.compression_ratio  # e.g. 0.18
result.sentences[0].source_doc_id  # provenance for every kept sentence
result.provenance()  # [(doc_id, chunk_id), ...] in output order

Swap in the adaptive budget:

from ragcompress import AdaptiveBudget, Compressor

compressor = Compressor(budget=AdaptiveBudget(min_tokens=64, max_tokens=1024))

How it works

  1. Split — chunks are segmented into sentences with provenance tags. Code fences, markdown tables, and list items are kept atomic (never split mid-fence).
  2. Score — each (query, sentence) pair is scored by a cross-encoder reranker; an MMR-style redundancy pass (cosine similarity between candidates) penalizes near-duplicates of higher-ranked sentences so diverse evidence wins.
  3. Budget — a controller selects sentences: FixedBudget (top-k and/or token cap) or AdaptiveBudget (elbow detection on the score distribution, bounded by a min_tokens/max_tokens range).
  4. Reassemble — survivors are deduplicated, restored to original reading order (doc → chunk → sentence position, which reads more coherently to the generator than score order), and joined into the final context with optional [doc_id] provenance markers.

Scoring backends

Scorer When to use
CrossEncoderScorer (default) Portable, CPU-friendly; any pretrained reranker from the HF hub
AttentionScorer (opt-in, [attention] extra) You run a local HF model and want AttnComp-style scores from query→sentence attention mass in one forward pass
from ragcompress.scoring import AttentionScorer

compressor = Compressor(scorer=AttentionScorer(model="path/or/hf-id-of-local-model"))

Framework adapters

LlamaIndex (pip install ragcompress[llamaindex]):

from ragcompress.adapters.llamaindex import RagCompressPostprocessor

postprocessor = RagCompressPostprocessor.from_compressor(compressor)  # mode="merge" | "filter"
query_engine = index.as_query_engine(node_postprocessors=[postprocessor])

LangChain (pip install ragcompress[langchain]):

from langchain.retrievers import ContextualCompressionRetriever
from ragcompress.adapters.langchain import RagCompressDocumentCompressor

retriever = ContextualCompressionRetriever(
    base_compressor=RagCompressDocumentCompressor(compressor=compressor),
    base_retriever=vectorstore.as_retriever(),
)

Runnable examples: examples/basic_usage.py, examples/llamaindex_pipeline.py, examples/langchain_pipeline.py.

Benchmarks

The suite in benchmarks/ compares against no-compression, naive top-k truncation, and LLMLingua-2 on HotpotQA, TriviaQA, and Natural Questions — measuring token reduction, latency, citation validity (does the compressed context still contain a gold-supporting sentence), and downstream EM/F1 when a generator LLM is configured:

pip install ragcompress[benchmarks]
python benchmarks/run_benchmark.py --dataset hotpotqa --n 500 --generator anthropic

Sample run — HotpotQA distractor (n=30), 500-token budget, CPU (Apple Silicon), default cross-encoder scorer, retention metrics (add --generator anthropic for downstream EM/F1; llmlingua2 skipped — run with the [benchmarks] extra installed to include it):

Method Token reduction Latency (ms) Citation validity
no_compression 0.0% 0.0 100.0%
top3_truncation 67.1% 0.0 43.3%
ragcompress_fixed 58.8% 718.8 100.0%
ragcompress_adaptive 84.2% 406.9 96.7%

Naive truncation at a similar budget silently drops a gold-supporting sentence in 57% of questions; ragcompress keeps it while cutting more tokens. Full report: benchmarks/results/hotpotqa_n30.md.

API sketch

@dataclass
class Chunk:
    doc_id
    chunk_id
    text
    metadata


@dataclass
class ScoredSentence:
    text
    score
    source_chunk_id
    source_doc_id
    sentence_index_in_chunk


@dataclass
class CompressedContext:
    text
    sentences
    original_token_count
    compressed_token_count
    compression_ratio

CompressedContext.provenance() returns (doc_id, chunk_id) per kept sentence; .sources() returns the contributing doc IDs.

Guarantees

  • Extractiveness invariant (tested): every output sentence is a verbatim substring of some input chunk — never paraphrased or altered.
  • Provenance invariant (tested): every output sentence's source_chunk_id/source_doc_id maps back to the chunk that contains it.

Development

git clone https://github.com/ragcompress/ragcompress && cd ragcompress
pip install -e ".[dev,langchain,llamaindex]"
pytest                                          # fast unit tests, no downloads
RAGCOMPRESS_RUN_MODEL_TESTS=1 pytest -m model   # real-model smoke tests
ruff check . && mypy

See CONTRIBUTING.md. Licensed under Apache-2.0.

Metadata

Release files for ragcompress 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ragcompress 0.1.0
File Size Uploaded Provenance Actions
ragcompress-0.1.0.tar.gz 42.6 kB Without provenance Details for ragcompress-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ragcompress 0.1.0
File Interpreter ABI Platform Actions
ragcompress-0.1.0-py3-none-any.whl Python 3 none any Details for ragcompress-0.1.0-py3-none-any.whl

Total release size: 78.2 kB

Release files / ragcompress-0.1.0.tar.gz

Download URL ragcompress-0.1.0.tar.gz
Size 42.6 kB
Tags Source
SHA-256 checksum
How to use checksums
839e1f24ab6864bdcd34ae1f67cb191d57bdfbc0d5b4e463b7f8c4947e4e18a7
BLAKE2b-256 checksum
How to use checksums
c281ae63bed62713278b4967d717d68803650a0a5876cc788b8cf4d5a5f25a43
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.7.13

Release files / ragcompress-0.1.0-py3-none-any.whl

Download URL ragcompress-0.1.0-py3-none-any.whl
Size 35.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0372d13b8404967da73b75f5eb029a768bb98c04e8f6f4c618402ec333dfc6c1
BLAKE2b-256 checksum
How to use checksums
2a1040304a8b54fed6c6abf2d162d76708ef396794b4157fd60125c5e250e6c3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.7.13

Security for ragcompress 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page