Skip to main content

ragbisect

Bisect a RAG pipeline to find the broken stage. Stage-by-stage diagnostics for RAG pipelines, and the benchmark harness for ContextPull.

ragbisect (formerly stagewise) and ContextPull are one project in two packages, kept apart on purpose. ContextPull is the retrieval server; ragbisect is the neutral instrument that measures it against bm25, dense and hybrid pipelines on the same self-built eval set. ragbisect has no dependency on ContextPull and works on any pipeline you already have.

Other tools score your pipeline end to end and tell you it is bad. ragbisect scores retrieval, ranking and generation separately, on an eval set it builds itself from your corpus, and tells you which stage is losing the most quality, and which built-in alternative would recover it.

It is a measuring instrument, not a RAG framework. Zero runtime dependencies.

Install

uv add --dev ragbisect      # or: pip install ragbisect
export OPENAI_API_KEY=...   # used for question generation, judging and the built-in dense config

Any OpenAI-compatible endpoint works (OPENAI_BASE_URL). Anthropic models work for generation and judging (--model anthropic:claude-...); embeddings still need an OpenAI-compatible endpoint.

Use

Wrap your existing pipeline in one method:

class MyRetriever:
    def retrieve(self, query: str, k: int) -> list[str]:
        """Return chunk IDs, most relevant first."""

Optional extras on the adapter, all read if present: generate(query, chunk_ids) -> str to have faithfulness judged; stats() -> dict with tokens_in, tokens_out, tool_calls, queries (and usd) to fill the cost columns; a concurrency = N attribute to allow N parallel queries. Wall time per query is recorded for every config. --sample N evaluates a seeded subset, for expensive adapters.

Then point ragbisect at your corpus and your adapter:

ragbisect run --corpus ./docs --adapter ./my_pipeline.py:MyRetriever
config                             recall@5   mrr@5  ndcg@5|hit    faith     n
---------------------------------------------------------------------------------
your adapter                          0.812    0.667        0.885      n/a   214
  conceptual                          0.842    0.702        0.899      n/a   171
  exact_lookup                        0.698    0.528        0.831      n/a    43
bm25 (built-in)                       0.771    0.611        0.862      n/a   214
dense (built-in)                      0.836    0.688        0.893      n/a   214
hybrid dense+bm25 rrf (built-in)      0.897    0.741        0.912      n/a   214

Bottleneck for 'your adapter': retrieval — recall@5 is 0.81; 19% of questions never see their gold chunk in the top 5. Weakest shape: exact_lookup (recall 0.70, n=43).
'hybrid dense+bm25 rrf (built-in)' would raise recall@5 from 0.81 to 0.90 (+0.09).

What it does

  1. Parses and chunks your corpus (.md, .txt), or takes your own chunks as a JSONL of {"id", "text", "source"} so your IDs are the ground truth.
  2. Generates an eval set in five shapes. Conceptual and exact-lookup questions come from one chunk each via a model call. Comparison pairs are found by lexical near-duplicate detection across documents and phrased by the model; gold is both chunks. Aggregation questions count an identifier family (TX-4401, TX-4419, …) spread over several chunks; table questions target one cell of a pipe table. Those two are computed, not generated, and cost nothing. --shapes selects. Cached; re-runs are free until the corpus changes. Shapes a corpus cannot support are skipped and the report says why.
  3. Scores each stage: recall@k (retrieval), NDCG@k conditioned on a hit (ranking), and faithfulness via an LLM judge if your adapter also has generate(query, chunk_ids) -> str (generation).
  4. Localizes the fault: the stage furthest from its ceiling is the bottleneck. Built-in bm25 / dense / hybrid-RRF configs run on the same questions so you can see what a change would buy on your data.
  5. Prints what it spent in tokens.

Commands

ragbisect generate --corpus ./docs --n 200        # just build (and inspect) the eval set
ragbisect run --corpus ./docs                     # built-in configs only, no adapter
ragbisect run --corpus ./chunks.jsonl --adapter ./p.py:R --k 10 --dump-misses misses.jsonl

Everything lands in .ragbisect/: the cache, chunks.jsonl, and questions.jsonl. Hand-check the questions. If they are bad, everything downstream is worthless.

Status

Milestones from CLAUDE.md:

  • M1 eval set generator (conceptual, exact lookup)
  • M2 retrieval scoring; dense vs dense+BM25 RRF comparison
  • M3 CLI with stage table and one-line verdict
  • M4 comparison, aggregation and table query shapes
  • M5 ablation across candidate configs with a recommendation

Known limits (read before trusting a number)

  • Single gold chunk. Doc corpora explain the same thing in several places. When the retriever returns a chunk that also answers the question but is not the one it was generated from, that counts as a miss. On the uv docs about half of the exact-lookup misses looked like this, so recall@k here is a lower bound. Repeated identifiers are deduped and very common ones (present in >5% of chunks) are rejected, which reduces but does not remove the effect. --dump-misses lets you see for yourself.
  • Two of five query shapes. Comparison, aggregation and table questions are not generated yet, and those are the shapes naive RAG fails on hardest.
  • No PDF parsing. .md and .txt only.
  • Generation scoring is thin by design: one LLM judge on a sample.
  • Baseline chunker is the baseline. If you already chunk, pass your own .jsonl so ground truth uses your IDs.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ragbisect-0.1.0.tar.gz (38.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ragbisect-0.1.0-py3-none-any.whl (31.5 kB view details)

Uploaded Python 3

File details

Details for the file ragbisect-0.1.0.tar.gz.

File metadata

  • Download URL: ragbisect-0.1.0.tar.gz
  • Upload date:
  • Size: 38.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for ragbisect-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9f4af86e53d13872ae8ea888d6a57c3ef663debce77cd23bba4753a8c72bb609
MD5 b65039fb5a30c918641393bae084851e
BLAKE2b-256 97dd2b81ae8a81d4794277dd8f6ddfb1a422f113a68038a7fc7953fc9da5cc31

See more details on using hashes here.

Provenance

The following attestation bundles were made for ragbisect-0.1.0.tar.gz:

Publisher: publish-pypi.yml on mi2arun/ragbisect

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ragbisect-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: ragbisect-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 31.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for ragbisect-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f000e7aad4cd8922b409821123442df759e831c2c75acb0c3c1a5eb877835db3
MD5 6cee30ab20b179298477e4acffab6a06
BLAKE2b-256 befbcae101732515aab9b92e25eba1a476d57869627b2fee5a3ce378b0604617

See more details on using hashes here.

Provenance

The following attestation bundles were made for ragbisect-0.1.0-py3-none-any.whl:

Publisher: publish-pypi.yml on mi2arun/ragbisect

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.0

2 files

This release

0.1.0 This release

2 files

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