Skip to main content

Meridian

CI Release Python License: MIT Checked with mypy Code style: black Ruff

A from-scratch grounded RAG engine over biomedical literature (PubMed). Every ML component is trained in-house — tokenizer, dense retriever, reranker, faithfulness verifier (Polaris), and the cited-answer generator (Zenith). Every answer is cited, verified, or refused.

Research literature assistant. Not medical advice.

Status

Built in strictly ordered vertical slices; meridian ask answers end-to-end from v0.1.0. Every ML component is trained by a committed, seeded pipeline, and every benchmark section carries real measured numbers — retrieval, ANN, NLI verifier, faithfulness, calibration, end-to-end accuracy, and per-stage latency.

Component Measured result
BM25 retrieval (PubMedQA dev) R@5 0.987
Dense retriever (from scratch) R@5 0.38 ± 0.02 (4 seeds)
Cross-encoder rerank pure 0.029 → base-fused 0.983 (graceful degradation)
ANN index HNSW recall@10 0.996 @ 0.262 ms, below brute-force latency
NLI verifier (SNLI dev, chance 0.333) 0.783
Gate-1 calibration 0.801 coverage @ 0.000 error
Serving latency (P50) search 1.33 ms · embed 2.56 ms · verify 31.6 ms · rerank 421 ms

Three honest findings we publish rather than hide (RAG.md §9): a seed-averaged ablation shows MLM Stage-0 pretraining adds nothing measurable to retrieval (0.371 ± 0.022 vs 0.382 ± 0.023) — overturning our own hypothesis; BM25 beats the from-scratch dense retriever on this lexically-easy task; and the verifier, strong on SNLI, does not transfer to biomedical text (0.437 hallucination rate on verbatim quotes), which is a verifier-domain gap, not a generator failure. Three items are explicitly not run rather than estimated: the ~200K PubMed corpus, the Phase-7 generator pipeline, and verifier–human agreement. See BENCHMARKS.md and docs/scale-runs.md.

Results at a glance

Every chart is regenerated from committed measurement data (benchmarks/results/) by scripts/plot_summary.py — never drawn by hand.

From-scratch NLI verifier: what moved the number Per-stage serving latency
verifier progression latency breakdown

The verifier went 0.415 → 0.783 on SNLI dev (chance 0.333) by fixing three bottlenecks in order — tokenizer (+6 pts), data (+22 pts), and learning rate (+17.6 pts; the red bar is the same 384×6 model trained at too high an LR). Reranking is ~320× the cost of BM25, which is why it stays off by default here. More: retrieval ablation, ANN trade-off, risk-coverage.

Architecture (online path)

flowchart TD
    Q[query] --> BM[BM25 / dense bi-encoder / hybrid RRF]
    BM --> ANN[ANN index: brute-force / IVF / HNSW]
    ANN --> RR[cross-encoder reranker: top-100 -> top-k]
    RR --> G1{Gate 1: retrieval confidence}
    G1 -- low --> AB[ABSTAIN: show nearest passages]
    G1 --> G2{Gate 2: answerability}
    G2 -- no --> AB
    G2 --> GEN[Zenith generator: citation-constrained decoding]
    GEN --> V{Gate 3: NLI faithfulness verifier}
    V -- pass --> OK[respond: GROUNDED, cited]
    V -- fail --> EX[extractive fallback -> or ABSTAIN]

Every ML box is a from-scratch model: encoders/reranker/verifier are Polaris; the generator is Zenith; BM25, the ANN indexes, serving, and the eval harness are built in this repo on PyTorch/NumPy primitives.

Design principles

  • Zero external NLP-model dependencies. No Hugging Face models, no embedding APIs, no FAISS or vector DBs. Encoders come from polaris-nlp, generation from zenith-nlp (both pinned); everything else — BM25, IVF/HNSW ANN indexes, serving — is built in this repo on PyTorch/NumPy primitives.
  • Baselines before models. BM25 and brute-force search exist before any neural component, so every neural claim has an honest denominator.
  • Grounded or silent. Generation is citation-constrained, every claim sentence is verified by an NLI entailment check, and the system abstains when retrieval confidence or answerability is low.
  • The eval harness is the product. Every published number is reproducible from a committed, seeded script. See benchmarks/BENCHMARKS.md.

Quickstart (offline demo)

The repository ships a tiny synthetic corpus so the vertical slice runs with no downloads:

uv sync
uv run meridian ingest examples/sample_pubmed.xml --db build/corpus.sqlite
uv run meridian ask "Does metformin reduce cardiovascular mortality in type 2 diabetes?" \
    --db build/corpus.sqlite

You get cited sentences quoted verbatim from the corpus, a GROUNDED badge, and the "Not medical advice" banner — or an ABSTAIN when nothing relevant is retrieved. On the real corpus, replace the sample file with downloaded PubMed baseline files. (The sample is fabricated data for demonstration only.)

Repository layout

src/meridian/   library code
tests/          offline-only test suite (coverage gate ≥ 90%)
docs/adr/       Architecture Decision Records
docs/design/    per-phase design docs
benchmarks/     BENCHMARKS.md, measured results/ (JSON), figures/
scripts/        operational scripts (ingest, index builds, releases)

Development

Requires Python ≥ 3.12 and uv.

uv sync --extra dev
uv run pre-commit install
uv run pytest

Quality gates (enforced in CI and pre-commit): Black, Ruff, mypy --strict, pytest with ≥ 90% coverage. Tests never touch the network.

Serving

uv sync --extra serving
uv run python scripts/serve.py --db build/corpus.sqlite   # FastAPI on :8000
# or the whole demo stack (API + static UI):
docker compose up

/ask returns a cited answer (or abstains), /passages the retrieved passages, /ask/stream the same over SSE, /metrics per-stage latency. The zero-framework demo UI (demo/index.html) shows the answer, clickable PubMed citations, a GROUNDED/ABSTAIN badge, and the "not medical advice" banner.

Guardrails — what this is not

Mirrors the discipline of Polaris/Zenith; these are house rules, not marketing.

  • Not medical advice. A research-literature assistant. Answers are restricted to what retrieved literature states, with citations; personal-advice/off-domain questions abstain.
  • Production-inspired, never "production-grade." Laptop-scale corpus and small models (encoders ~10–30M, generator ~30–125M). The design compensates with grounding, extractive fallback, and abstention — the generator's quality is additive, not load-bearing.
  • No number without a script. A metric appears in the README/BENCHMARKS only if a committed, seeded script reproduces it, with its MLflow run id. TBD cells stay TBD until the real run — never estimated in prose.
  • Not a vector-DB wrapper. The ANN index (brute-force → IVF → HNSW) is implemented and benchmarked here against its own brute-force ground truth. Zero external NLP-model or vector-DB dependencies.

See MODEL_CARD.md for scope, intended use, and limitations.

License

MIT. Corpus and benchmark data carry their own terms — see docs/license-review.md.

Download files

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

Source Distribution

meridian_rag-1.0.1.tar.gz (69.3 kB view details)

Uploaded Source

Built Distribution

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

meridian_rag-1.0.1-py3-none-any.whl (90.9 kB view details)

Uploaded Python 3

File details

Details for the file meridian_rag-1.0.1.tar.gz.

File metadata

  • Download URL: meridian_rag-1.0.1.tar.gz
  • Upload date:
  • Size: 69.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for meridian_rag-1.0.1.tar.gz
Algorithm Hash digest
SHA256 80be6e3af91af9ad2655953f31c42e9097e9992f01a381bacefd8ee37785e0fc
MD5 74d40da4fdaca9c0347adef11d3c7492
BLAKE2b-256 b671d0b118dc232389a570ba60111227314728a2a0627e5bbff1dbd04f10d81a

See more details on using hashes here.

Provenance

The following attestation bundles were made for meridian_rag-1.0.1.tar.gz:

Publisher: publish.yml on cattolatte/meridian

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

File details

Details for the file meridian_rag-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: meridian_rag-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 90.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for meridian_rag-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 12bdba06f505466b3a769f7abb6f2771ea0ed1228cd473b6c5fd7b72facaf26e
MD5 04ae5f83832ec86eeb5985dca516dcfd
BLAKE2b-256 e83bc27778e1c89c90d22d95fe723aad12bcc4d0de1289409ef57de959c1ffb9

See more details on using hashes here.

Provenance

The following attestation bundles were made for meridian_rag-1.0.1-py3-none-any.whl:

Publisher: publish.yml on cattolatte/meridian

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page