Skip to content

Releases: cbib/TrialMatchAI

v0.6.0 - config-driven model swapping

Choose a tag to compare

@majdabd majdabd released this 13 Jul 17:01

v0.6.0 — config-driven model swapping

Swap the embedder, search backend, reranker, or CoT model with a config edit — no code changes.

  • Non-lossy config: undeclared knobs now reach their consumers (a new runtime knob needs no pydantic field); revived rag/query_expansion.no_think.
  • Plugin registry: build_search_backend / build_embedder factories replace by-name construction; a new backend is one @register line.
  • Self-describing embedders: dim / native_metric / is_asymmetric / fingerprint(); the vector metric now follows the embedder; fixed the asymmetric embed_queries instruction-drop bug.
  • Index provenance: _embedder.json sidecar + auto-reembed on an embedder swap (legacy indexes trusted, no rebuild).
  • Unified engine: the reranker builds through the shared vLLM loader (quantization / kv-cache / max-len parity, shared cache); scoring unchanged.
  • Model catalog: embedder: {model: "medcpt"} one-line swap.

+27 tests, full suite green, ruff clean. Existing configs and persisted indexes resolve identically (A/B validated: byte-identical retrieval and metrics). Full detail in commit 9ffb279.

v0.5.0

Choose a tag to compare

@majdabd majdabd released this 08 Jul 09:27

Added

  • Asymmetric dual-encoder embedders (embedder.query_model_name) — e.g. MedCPT article/query encoders; symmetric bge-m3 unchanged; same-dimension checked at load.
  • Configurable first-level vector similarity: search_backend.vector_metric = cosine (default) | dot (ANN index + re-ranker).
  • Configurable hybrid blend: search_backend.vector_weight (default 0.5) — score = (1-w)·text + w·vector.
  • First-level embedder benchmark harness (scripts/benchmark_embedder.py + benchmarks/embedders/registry.json): isolated per-embedder index, recall@k for grade-2 and grade-1+2, non-destructive.

Fixed

  • Cosine re-ranker keeps its single-pass path; dot buffers only for min-max normalization (all-equal → neutral 0.0).
  • vector_metric/vector_weight validated at backend construction; upsert_trials rebuilds the index with the configured metric.

v0.4.1

Choose a tag to compare

@majdabd majdabd released this 06 Jul 17:42

New-system release: the eligibility scoring and ranking work validated across TREC CT 2021/2022 (now above the legacy system on its own metrics). Includes all of 0.4.0.

Added

  • trialmatchai trec --rerank re-ranks a finished run from cached chain-of-thought outputs and re-evaluates against qrels — no build, match, or model inference — so a ranking-logic change can be re-applied to existing results in seconds instead of re-running the GPU pipeline.

Changed

  • Eligibility scoring credits "Unclear" criteria (neutral-Unclear). The band scored only Met/Not-Met and dropped Unclear (the dominant label), collapsing eligible and merely-relevant trials into one band; Unclear now counts at 0.5 (Met=1, Not Met=0). Irrelevant is still excluded; a Violated exclusion still hard-disqualifies.

From 0.4.0 (never released to PyPI)

  • Per-condition first-level channels for comorbidities; RRF shortlist fusion (search.shortlist_fusion); condensed precision aligned with nDCG; recall-aware ndcg_full@k reported alongside ndcg@k.

v0.4.0

Choose a tag to compare

@majdabd majdabd released this 05 Jul 22:03

Retrieval and evaluation release.

Added

  • Per-condition first-level query channels for comorbidities. Each distinct
    other_conditions term now gets its own focused first-level retrieval channel (weight
    0.25, below the primary condition) instead of only diffusing into the shared narrative
    channel. A single blended channel over many distinct conditions dilutes to noise, which
    starved retrieval on multi-morbid patients; per-condition channels restore their coverage
    without displacing single-condition patients. The channels are de-duplicated against the
    primary terms and bounded by a fixed cap.
  • Recall-aware nDCG reported alongside the condensed variant. TREC evaluation now emits
    both ndcg@k — normalized by the ideal over judged-and-ranked trials (pure ordering
    quality, independent of recall) — and ndcg_full@k — normalized by the ideal over the
    full judged pool (trec_eval-style), where a relevant trial that was never ranked
    lowers the score. Reporting both keeps ordering quality and retrieval coverage legible
    instead of conflating them in a single number. The DCG numerator is condensed (ignores
    unjudged trials) in both.

Changed

  • Second-level shortlist selection fuses rankings instead of summing raw scores.
    The pre-CoT shortlist previously ranked trials by first_level_score + second_level_score.
    Those two scores live on different scales (the first-level value is a reciprocal-rank
    fusion contribution; the second-level value is an aggregated reranker score), so the
    larger-scaled signal dominated the sum and a trial the retriever ranked highly could be
    dropped whenever the reranker scored its criteria low — or omitted entirely when no
    criterion cleared the aggregation threshold. Shortlist selection now combines the
    first-level and second-level rankings with reciprocal-rank fusion over the union of
    both, so a strong retrieval hit keeps a floor and rank fusion is scale-free. Behaviour is
    governed by search.shortlist_fusion (rrf, the new default, or score_sum for the
    previous behaviour), search.shortlist_rrf_k, and per-source weights
    search.shortlist_first_level_weight / search.shortlist_second_level_weight. The
    shortlist size is unchanged — it is still keyed to the number of reranked trials — so only
    which trials are selected changes, not how many.

Fixed

  • TREC precision was computed on the raw ranked list while its docstring — and nDCG —
    used the condensed (judged-only) list.
    evaluate now condenses the ranking to the
    judged pool before the P@k cutoff, so an unjudged trial the assessors never saw is no
    longer scored as a miss. This aligns precision with condensed_ndcg and with the
    function's own documented behaviour; the prior inconsistency understated P@k for a
    non-pooled system and made it incomparable to nDCG. Judged-but-non-relevant (grade 0)
    trials still count as negatives — only genuinely unjudged pairs are ignored. A regression
    test pins the condensing.

v0.3.3 — settings config-strip fix + vLLM fp8 KV cache

Choose a tag to compare

@majdabd majdabd released this 03 Jul 05:46

Fixed

  • Config knobs silently dropped by settings validation. VllmSettings / LLMRerankerSettings only keep declared fields, so LLM_reranker.tensor_parallel_size (added in 0.3.2) never survived load_config and the reranker stayed single-GPU. Now declared and reaches the engine; a regression test pins the round-trip.

Added

  • fp8 KV cache + concurrency cap for vLLM. vllm.kv_cache_dtype (fp8/fp8_e4m3/fp8_e5m2) halves KV-cache memory so a large window (e.g. 8192) fits on a single 48 GB card, and vllm.max_num_seqs caps concurrency. Validated: phi-4 loads at 8192 on one 48 GB L40 with ~44k tokens of KV.

See CHANGELOG.md.

v0.3.2 — healthcheck cold-start fix + multi-GPU reranker

Choose a tag to compare

@majdabd majdabd released this 02 Jul 18:40

Fixed

  • Healthcheck no longer aborts a cold-start build. The 0.3.1 hardening made health() flag a never-built (table-less) search index as unhealthy by default, so a pre-build preflight (trialmatchai healthcheck, run under set -e before the index exists) aborted a from-scratch run. The never-built check is now gated on require_tables=True: the lenient default preflight passes pre-build, while match-readiness (which already passes require_tables=True) still catches an unbuilt index.

Added

  • Multi-GPU reranker. LLM_reranker.tensor_parallel_size lets the vLLM reranker shard across GPUs, matching the CoT engine, so both engines can run tensor-parallel on a multi-GPU node (e.g. 2× L40) instead of contending for a single device.

See CHANGELOG.md.

v0.3.1 — deep robustness audit

Choose a tag to compare

@majdabd majdabd released this 02 Jul 16:07

A deep, line-by-line robustness audit. 82 verified defects were fixed across retrieval, constraint evaluation, entity linking, FHIR/OMOP ingest, TREC metrics, and the build/resume pipeline — each pinned by a regression test (the suite grew to 377). No public API changes; behaviour is more correct, not different in shape.

Highlights

  • Constraints — thousands-separator lab thresholds (10,000) no longer truncate to a wrong magnitude; a relative's disease in family_history no longer satisfies a patient-disease inclusion; bare gene names no longer emit spurious "present" biomarker constraints; cross-unit numeric comparisons abstain instead of mis-deciding; inclusion aggregation uses worst-case (mirroring exclusion); whole-word matching replaces raw substring containment.
  • Retrieval & search — criteria de-duplicated before trial aggregation (no inflation by query overlap); short query tokens no longer match inside unrelated words; scan fallback pushes its limit into LanceDB instead of loading the whole table; a never-built index is reported unhealthy.
  • Entity linking — length-ratio substring scoring (no more "carcinoma" → "hepatocellular carcinoma"); the annotation path wires the lexical reranker; OBO files keep their last term; empty mentions degrade to FTS-only.
  • Query expansion — CoT output is stripped of <think> blocks before JSON extraction, so a reasoning preamble can't poison the primary retrieval query.
  • Patient ingest — OMOP NOTE_NLP facts no longer silently dropped; NaN dates / float negations / concept_id 0 handled; ISO-8601 day/week ages preserved; FHIR valueRange keeps negative signs, valueRatio no longer emits "None", genomic resources with non-CodeableConcept types no longer dropped.
  • Ranking & TREC — the pure second-level reranker score (not first+second combined) reaches rank_trials; a score blend breaks coarse eligibility ties within-band; month/year-precision trial dates parsed deterministically.
  • Build/resume integrity — atomic temp-then-rename writes and completion sentinels; the index fingerprint no longer chains off a stale link fingerprint; per-trial resume re-embeds changed trials; the concept-store fingerprint includes the embedder identity; atomic-write temp files no longer match *.json globs.
  • Config & CLI — falsy-but-valid config values respected; trialmatchai run goes through corpus-fingerprint invalidation; failure accounting/exit codes no longer mask an all-failed resume run as success.
  • Verbose comments/docstrings tightened to intent-only; __version__ realigned with the packaged version.

See CHANGELOG.md for the full list.

v0.3.0

Choose a tag to compare

@majdabd majdabd released this 30 Jun 14:06
e32faa8

What's Changed

  • fix(P0): four shipping bugs from the test/codebase audit by @majdabd in #20
  • test(P1): prove crash-safe resume + atomic-write invariants by @majdabd in #21
  • test(P2): cover production paths + fix RRF dedup key by @majdabd in #22
  • fix: four medium-severity audit bugs (nDCG, OMOP zero, topic sex, age range) by @majdabd in #23
  • harden(P3): variant precision guard, embedder validators, metrics/interop tests by @majdabd in #24
  • trec: deepen analysis funnel to 1000/500/250 (configurable second->CoT thinning) by @majdabd in #25
  • feat(report): self-contained HTML match report (MVP) by @majdabd in #26
  • release: 0.3.0 by @majdabd in #27
  • docs: document the HTML match report (report subcommand + API) by @majdabd in #28

Full Changelog: v0.2.0...v0.3.0

TrialMatchAI v0.2.0

Choose a tag to compare

@majdabd majdabd released this 28 Jun 22:25

The deployment-readiness release: TrialMatchAI becomes one installable, idempotent, end-to-end pipeline behind a single CLI — with crash-safe resume, faithful TREC evaluation, a docs site, and PyPI packaging.

Highlights

  • Unified pipeline trialmatchai pipeline (prepare → concepts → index → ingest → expand → match → eval) — idempotent + resumable, with --only/--skip/--from/--to/--force (stage flags double as ablation knobs).
  • Single trialmatchai console script (12 subcommands).
  • LanceDB hybrid search + vLLM CoT eligibility reasoning + GLiNER2 NER + an entity-linking concept store from open vocabularies.
  • Tie-aware nDCG (McSherry–Najork) + P@10, with a TREC reproduction regression guard.
  • PyPI packaging + Trusted-Publishing release workflow; MkDocs docs site at https://cbib.github.io/TrialMatchAI/.
pip install trialmatchai

Full notes in CHANGELOG.md.

v0.01

v0.01 Pre-release
Pre-release

Choose a tag to compare

@majdabd majdabd released this 21 Jan 16:18

Initial release of TrialMatchAI