ragrefine
Evidence-first post-retrieval refinement for RAG systems.
ragrefine improves an existing retriever's candidate set before it reaches an
LLM. It reranks, fuses, deduplicates, and selects context while preserving the
original evidence and recording an auditable trace.
retriever -> Top-N candidates -> ragrefine -> refined Top-K + trace -> LLM
The core library is framework- and retriever-agnostic. Haystack and LangChain support are available as optional integrations.
Core deliverables
| Capability | Delivered behaviour |
|---|---|
| Candidate contract | Immutable candidates retain IDs, text, metadata, retrieval rank, and retrieval score |
| Ranking channels | Independent original, neural, lexical, and configurable pattern rankings over the same candidate pool |
| Rank fusion | Deterministic reciprocal-rank fusion without mixing incompatible raw-score scales |
| Context refinement | Exact/near-duplicate suppression and rank-preserving Top-K/token-budget selection |
| Traceability | Per-channel evidence, fusion contributions, stage timings, configuration, and explicit failure records |
| Neural reranking | Optional SentenceTransformers CrossEncoder adapter with batched inference |
| Haystack integration | Serializable component profiles and a retriever-to-generator pipeline builder |
| LangChain integration | RagRefineCompressor, a LangChain BaseDocumentCompressor that refines retrieved documents and exposes the trace |
| Evaluation | Frozen BEIR candidate pools, checksummed artifacts, reproducibility commands, and a paired Ragas harness |
Output candidates always originate from the supplied input pool; ragrefine
does not invent or rewrite evidence.
Quick start
Python 3.12+ is required.
pip install ragrefine
Or, from this checkout:
uv sync
from ragrefine import Candidate, CandidateSet, Refiner
candidates = CandidateSet(
name="my-retriever",
candidates=(
Candidate(
id="doc-1",
text="Python 3.12 improves f-string parsing.",
retrieval_rank=1,
retrieval_score=0.91,
),
Candidate(
id="doc-2",
text="Python 3.11 introduced exception groups.",
retrieval_rank=2,
retrieval_score=0.84,
),
),
)
result = Refiner().refine(
query="Which Python version improves f-string parsing?",
candidate_set=candidates,
top_k=1,
)
print(result.candidates[0].candidate.id)
print(result.trace)
Refiner() preserves the original ranking. Explicit RefinerConfig settings
enable lexical, pattern, neural, or fused profiles. See the
technical design for the configuration contract.
Haystack integration
uv sync --extra haystack
The optional integration provides document conversion, a serializable
RagRefineComponent, registered refiner profiles, prompt construction, and a
complete Haystack pipeline builder. The RAG pipeline guide
contains the runnable recipe and customization points.
LangChain integration
pip install "ragrefine[langchain]"
This requires LangChain 1.x (langchain-core>=1.6.9). With the repository's
current pins it cannot be installed in the same environment as the ragas extra
(the ragas extra pins langchain-openai<1.0).
from ragrefine import Refiner, RefinerConfig
from ragrefine.config import ChannelConfig
from ragrefine.integrations.langchain import RagRefineCompressor
from ragrefine.ranking.lexical import LexicalRanker
refiner = Refiner(
lexical_ranker=LexicalRanker(),
config=RefinerConfig(
original=ChannelConfig(enabled=False), lexical=ChannelConfig(enabled=True)
),
)
compressor = RagRefineCompressor(refiner=refiner, top_k=5)
# documents only
docs = compressor.compress_documents(retrieved_docs, "my query")
# documents + RefinementTrace
docs, trace = compressor.refine("my query", retrieved_docs)
- Returned documents are the original objects. They are never copied or edited, and the output is always a subset of the input.
- Documents without an
idget a positional idlc:<n>. Duplicate ids raiseValueError. - Original retrieval scores are not read from LangChain metadata, so they are not carried into the trace.
- To plug into a retriever, use
ContextualCompressionRetriever(base_compressor=compressor, base_retriever=retriever)(that class now ships in thelangchain-classicpackage), or wrap the compressor in a runnable:RunnableLambda(lambda x: compressor.compress_documents(x["documents"], x["query"])).
This integration is plumbing only; it makes no retrieval-quality claim. See the evaluation section for what has been measured.
Evaluation summary
Post-retrieval comparisons reuse the same frozen first-stage Top-50 candidates. Retrieval is not regenerated between profiles, and candidate-pool Recall@50 is a fixed ceiling rather than a refinement gain.
| Experiment | SciFact result | Decision |
|---|---|---|
| B0 — frozen dense baseline | nDCG@5 0.4592 | Baseline |
| B1-reference — MiniLM-L6/CUDA | nDCG@5 0.6262 | Retained neural profile |
| B1-light — TinyBERT-L2/CPU | nDCG@5 0.6112 | Retained measured profile |
| B2-L — lexical/CPU | nDCG@5 0.5432 | Retained lightweight profile |
| B2-P — patterns/CPU | nDCG@5 0.4559 | Not retained |
| B3 — equal-weight fusion | Best profile nDCG@5 0.5715 | Not retained; below B1-reference |
The end-to-end Ragas A/B used 13 paired DeepSeek queries. It is statistically inconclusive: the positive directional score differences have 95% paired bootstrap confidence intervals spanning zero, and both context metrics are saturated at 1.0. The run establishes neither an end-to-end benefit nor a regression. See the retained A/B report.
Machine-readable artifacts are the source of truth. No experiment is described as improved unless its recorded measurements support that claim.
Documentation
Detailed material removed from this README remains in the repository's focused documents:
- Product requirements — supported scope and product boundary
- Technical hypotheses — testable claims and current evidence
- Technical design — architecture, configuration, selection, and tracing contracts
- Evaluation contract — frozen-pool rules, metrics, profiles, and reporting policy
- Benchmark guide — execution and reproduction commands
- Retained artifact manifest — checksummed benchmark inputs and verification
- Haystack pipeline guide — integration and serialization
- Ragas evaluation guide — paired A/B design and analysis
- v0.2 release record — delivered scope, validation, and limitations
Scope
ragrefine owns post-retrieval candidate refinement, context selection, and
tracing. It deliberately does not own ingestion, parsing, chunking, embeddings,
vector databases, first-stage retrieval, LLM generation, agents, or deployment.
Development
uv sync --extra haystack --extra ragas
uv run ruff check .
uv run ruff format --check .
uv run mypy src/
uv run pytest
uv build
Heavy model and benchmark dependencies remain optional so the core package has no runtime dependencies.
License
Metadata
Release files for ragrefine 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| ragrefine-0.3.0.tar.gz | 25.6 kB | With provenance | Details for ragrefine-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| ragrefine-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for ragrefine-0.3.0-py3-none-any.whl |
Total release size: 64.4 kB
Release files / ragrefine-0.3.0.tar.gz
| Download URL | ragrefine-0.3.0.tar.gz |
|---|---|
| Size | 25.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
727a636fcb815476ddab2889b90ac938f743d2fe0cf4c1cc17251ecf15deec72
|
|
BLAKE2b-256 checksum How to use checksums |
715c90e1e55e2a8d00af4a32c119c089b591b2552e5d8a54a0d6c4fa75e54e4c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logRelease files / ragrefine-0.3.0-py3-none-any.whl
| Download URL | ragrefine-0.3.0-py3-none-any.whl |
|---|---|
| Size | 38.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5f2a9771d8093da0539382b10c0b4141046ba81ffc4cb3fc93a588067de4dc90
|
|
BLAKE2b-256 checksum How to use checksums |
1463611cd00974d562b7fe3c09fe747e2548f1f6c1f0c30a554f6cea4e18f854
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logSecurity for ragrefine 0.3.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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for ragrefine-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logA 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.