Metadata-Version: 2.4
Name: mothrag
Version: 0.5.0
Summary: MothRAG: adaptive multi-arm subset routing for multi-hop retrieval-augmented generation — high-level Python API with auto-defaults.
Author-email: Julian Geymonat <juliangeymonat@gmail.com>
License: Apache-2.0
Project-URL: Homepage, https://github.com/juliangeymonat-jpg/mothrag
Project-URL: Repository, https://github.com/juliangeymonat-jpg/mothrag
Project-URL: Issues, https://github.com/juliangeymonat-jpg/mothrag/issues
Keywords: rag,retrieval-augmented-generation,multi-hop,question-answering,hotpotqa,ensemble,llm
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Text Processing :: Linguistic
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.24
Requires-Dist: requests>=2.31
Requires-Dist: typing-extensions>=4.8
Requires-Dist: python-dotenv>=1.0
Requires-Dist: tqdm>=4.66
Provides-Extra: gemini
Requires-Dist: google-genai>=0.3; extra == "gemini"
Provides-Extra: vertex
Requires-Dist: google-cloud-aiplatform>=1.50; extra == "vertex"
Provides-Extra: sentence-transformers
Requires-Dist: sentence-transformers>=2.7; extra == "sentence-transformers"
Provides-Extra: openai
Requires-Dist: openai>=1.40; extra == "openai"
Provides-Extra: retrieval
Requires-Dist: scikit-learn>=1.3; extra == "retrieval"
Requires-Dist: networkx>=3.0; extra == "retrieval"
Requires-Dist: rank-bm25>=0.2.2; extra == "retrieval"
Provides-Extra: faiss
Requires-Dist: faiss-cpu>=1.7; extra == "faiss"
Provides-Extra: active-learning
Requires-Dist: spacy<4,>=3.7; extra == "active-learning"
Provides-Extra: hybrid-graph
Requires-Dist: hipporag>=1.0; extra == "hybrid-graph"
Provides-Extra: pdf
Requires-Dist: pypdf>=4.0; extra == "pdf"
Provides-Extra: html
Requires-Dist: beautifulsoup4>=4.12; extra == "html"
Provides-Extra: loaders
Requires-Dist: mothrag[html,pdf]; extra == "loaders"
Provides-Extra: prod
Requires-Dist: mothrag[faiss,gemini,loaders,openai,retrieval,sentence-transformers]; extra == "prod"
Provides-Extra: enterprise
Requires-Dist: mothrag[faiss,loaders,openai,retrieval,sentence-transformers,vertex]; extra == "enterprise"
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-cov>=4.1; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: mkdocs>=1.5; extra == "dev"
Requires-Dist: mkdocs-material>=9.4; extra == "dev"
Provides-Extra: all
Requires-Dist: mothrag[dev,prod]; extra == "all"
Dynamic: license-file

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="assets/mothrag_logo_horizontal_dark.png">
    <source media="(prefers-color-scheme: light)" srcset="assets/mothrag_logo_horizontal_light.png">
    <img src="assets/mothrag_logo_horizontal_light.png" alt="MothRAG logo" width="360">
  </picture>
</p>

# MOTHRAG

> **Training-free multi-hop question answering at research-SOTA parity — on commodity LLM APIs alone.**

**Author:** Julian Geymonat · **Research supported by:** ItalySoft srl · **License:** Apache-2.0 · **Paper:** arXiv link pending · [Zenodo preprint DOI: 10.5281/zenodo.20668567](https://doi.org/10.5281/zenodo.20668567) · **Site:** [mothrag.com](https://mothrag.com)

Every component — reader, embedder, retrieval judges — sits behind a commodity pay-per-call API. No local GPU, no constrained decoding, no non-commercially-licensed model. Deployment is a package install plus API keys.

## Results (paper, n=1000 per dataset, Llama-3.3-70B reader, single uniform configuration)

| System | Deployment profile | HotpotQA | 2WikiMultiHopQA | MuSiQue | AVG |
|---|---|---|---|---|---|
| HippoRAG 2 (as published) | offline OpenIE graph + NV-Embed-v2 peak | 75.5 | 71.0 | 48.6 | 65.0 |
| CoRAG (training-based, as reproduced) | trained chain-retrieval | 75.1 | 75.1 | 52.9 | 67.7 |
| NeocorRAG (as published) | GPU-bound constrained decoding + NV-Embed-v2 | **78.3** | 76.1 | **52.6** | **69.0** |
| **MOTHRAG (ours)** | **commodity APIs only** | 78.1 | **76.3** | 50.5 | 68.3 |

F1, competitor numbers as published in the cited sources (same reader class). MOTHRAG attains the **highest average F1 among commercially-deployable frameworks** — within 0.7 points of the GPU-bound research state of the art (parity on HotpotQA at −0.2, an edge on 2WikiMultiHopQA at +0.2, an honest gap on MuSiQue at −2.1).

**Measured cost:** $0.032/query (reader + retrieval-judge, measured over 3,000 queries). A documented **economy tier** (one-flag retrieval-judge swap) runs at ≈$0.018/query (−44%) at statistical parity on HotpotQA and 2WikiMultiHopQA, with a measured trade-off only on MuSiQue (−2.12). All SOTA-parity claims attach to the full configuration.

Answers are **proof-tree-structured**: each output carries inspectable reasoning steps over the assembled evidence, with a γ-cap fallback when the grounding check cannot be satisfied within budget.

## Install

```bash
pip install mothrag

# Recommended baseline (Gemini embeddings + Groq Llama-3.3-70B reader):
pip install 'mothrag[gemini,openai]'

# Full production stack:
pip install 'mothrag[prod]'
```

| Extra | Pulls | Used by |
|---|---|---|
| `gemini` | `google-genai` | `GeminiEmbedder`, `GeminiReader` |
| `openai` | `openai` | `OpenAIReader`, `GroqReader` (Groq's OpenAI-compatible API) |
| `sentence-transformers` | `sentence-transformers` | local embedding fallback |
| `retrieval` | `scikit-learn`, `networkx`, `rank-bm25` | classic-RAG features |
| `faiss` | `faiss-cpu` | vector store for 100k–10M chunk corpora |
| `prod` | bundles the above + loaders | full stack |

## Quickstart

```python
from mothrag import MothRAG

# Works out of the box (degrades gracefully without keys);
# set GROQ_API_KEY + GEMINI_API_KEY for production quality.
m = MothRAG.from_documents([
    "Paris is the capital of France.",
    "The Eiffel Tower is in Paris.",
])
result = m.query("In which country is the Eiffel Tower?")
print(result.answer)         # the answer
print(result.arm_used)       # which reasoning arm won arbitration
print(result.confidence)     # arbitration confidence
```

API keys via environment (see `.env.example`): `GROQ_API_KEY` (reader), `GEMINI_API_KEY` (embedder + grounding judge), `ANTHROPIC_API_KEY` (premium retrieval judge; optional — the economy tier uses Gemini).

## How it works

Three separable stages; every model invocation is a commodity API call:

1. **Bridge retrieval substrate** — multi-query ANN fusion re-ranked by a tripartite LLM judge conditioned on retrieved bridge evidence, reshaping every retrieval (primary, sub-question, iterative). A post-retrieval **ChainFilter** re-scores the ranking by chain density over OpenIE triples, gated by input features only.
2. **Four-arm ensemble pool** — direct read, decomposition, iterative refinement (γ-driven re-retrieval), and **Pool-Duplicate Dispatch (PDD)**: a deterministic copy of the iterative arm's candidate that double-weights the grounding-checked voice in arbitration at zero extra inference. Pool cardinality is fixed at N=4 (five-arm pools regressed consistently).
3. **Deterministic arbitration** — fixed weights over grounding status (γ, 1.0), cross-arm agreement (0.5), and faithfulness (0.3). No learned components anywhere; all gates condition on input features of the question, never on dataset identity.

## Reproducing the paper

The paper numbers come from the evaluation configuration (`scripts/route_prospective.py` with the full flag set), not from the high-level quickstart API. See **[`paper/REPRODUCE.md`](paper/REPRODUCE.md)** for the verbatim CLI, required inputs, and expected outputs. The per-query outputs behind every table in the paper are released in **[`paper/results/`](paper/results/)** (six JSONs: three datasets × premium/economy tiers, n=1000 each).

## Citing

See [`CITATION.cff`](CITATION.cff). Until the arXiv ID is live, cite the Zenodo preprint:

```bibtex
@misc{geymonat2026mothrag,
  title  = {MOTHRAG: Training-Free Multi-Hop Question Answering at Research-SOTA Parity on Commodity LLM APIs},
  author = {Geymonat, Julian},
  year   = {2026},
  doi    = {10.5281/zenodo.20668567},
  url    = {https://doi.org/10.5281/zenodo.20668567}
}
```

## License

Apache-2.0. © 2026 Julian Geymonat. Research supported by ItalySoft srl.
