Transformer-based clinical safety signal detection for behavioral health systems
Project description
bh-sentinel-ml
Transformer-based clinical safety signal detection for behavioral health systems.
bh-sentinel-ml is the Layer 2 add-on for bh-sentinel-core. It runs ONNX-Runtime zero-shot NLI inference over clinical sentences to catch signals that deterministic pattern matching misses: implied distress, indirect language, contextual meaning.
The core package always runs without bh-sentinel-ml installed. L2 is opt-in.
Installation
pip install bh-sentinel-ml
This pulls in bh-sentinel-core>=0.1.1, onnxruntime, tokenizers, huggingface-hub, and platformdirs.
Optional extras:
pip install "bh-sentinel-ml[eval]" # adds numpy + scikit-learn for calibrate/evaluate CLIs
Compatibility
bh-sentinel-ml |
Requires bh-sentinel-core |
Python |
|---|---|---|
0.2.x |
>=0.1.1,<1 |
>=3.11 |
bh-sentinel-ml 0.2.0 depends on the Pipeline(transformer_model_path=..., transformer_auto_download=...) kwargs that were added in bh-sentinel-core 0.1.1. Pairing it with bh-sentinel-core 0.1.0 will break at import/construction time.
Enforcement:
- Install time:
pip install bh-sentinel-mlresolvesbh-sentinel-core>=0.1.1,<1from the wheel metadata. This is the primary guard. - Import time:
import bh_sentinel.mlverifies the installedbh-sentinel-coreversion viaimportlib.metadataand raisesImportErrorwith an actionable upgrade message if it's too old. This catches the--no-deps, vendored, and editable-monorepo cases that bypass the pip resolver.
Quick Start
from bh_sentinel.core import Pipeline, AnalysisConfig
pipeline = Pipeline(enable_transformer=True) # auto-downloads the pinned model on first run
result = pipeline.analyze_sync("I just can't see the point anymore.")
for flag in result.flags:
print(flag.flag_id, flag.severity, flag.confidence, flag.corroborating_layers)
Model distribution
bh-sentinel-ml uses a hybrid distribution strategy. The ~140MB INT8 ONNX model is not bundled in the wheel.
Release note (v0.2.0 → v0.2.1): v0.2.0 ships the full L2 infrastructure (classifier, merge, calibration, CLI) but the default
ml_config.yamlstill has a placeholdermodel_revision: mainand an all-zerosmodel_sha256. Neithervalhalla/distilbart-mnli-12-3nor any of the common ONNX mirrors publish a pinned INT8 artifact the SHA of which we can commit to. The follow-upbh-sentinel-ml 0.2.1will:
- Ship a canonical ONNX export (pinned revision + pinned SHA256).
- Provide
scripts/export_onnx.pyfor users who want to re-export against their own base model.- Publish reproducible L1-vs-L2 reports against the shared corpus via the
bh-sentinel-examplesrepo.Until
0.2.1lands, the default auto-download path will fetch the HF repo's currentmainrevision (unpinned) and the SHA check will fail -- meaning the productionBH_SENTINEL_ML_OFFLINE=1rail is the only currently-supported deployment path, with the operator responsible for pinning their own SHA. See thebh-sentinel-examplesREADME for the one-off reproduction flow.
Dev / CI (unrestricted network):
pip install bh-sentinel-ml → first analyze() call fetches the pinned HuggingFace revision into a local cache directory. One-time ~30s, zero config.
Production / VPC-isolated / Lambda:
Pre-bake the model into your container image at docker build time. Lambda cold starts must never hit HuggingFace Hub.
FROM python:3.12-slim
RUN pip install bh-sentinel-ml
RUN bh-sentinel-ml download-model \
--revision <PINNED_SHA> \
--output /opt/bh-sentinel-ml/model \
--verify-sha256 <PINNED_ONNX_SHA256>
ENV BH_SENTINEL_ML_OFFLINE=1
At runtime the pipeline reads the baked-in model:
from pathlib import Path
from bh_sentinel.core import Pipeline
pipeline = Pipeline(
enable_transformer=True,
transformer_model_path=Path("/opt/bh-sentinel-ml/model"),
transformer_auto_download=False,
)
Production safety rails
BH_SENTINEL_ML_OFFLINE=1-- set once in the Dockerfile. When set,auto_download=Trueis forced toFalse;huggingface_hubis never even imported. Any accidental future code change that tries to download over the network will fail immediately with a static PHI-safe error.- Verify-on-load SHA256.
TransformerClassifiercomputes the SHA256 of the ONNX file at pipeline construction and compares it to the pinned digest inml_config.yaml. Mismatch raisesModelIntegrityErrorbefore anyInferenceSessionis created -- a stale or tampered container bake fails fast, not silently. - Graceful L2 failure. If the model is missing, the SHA mismatches, or inference throws, the pipeline still returns a 200-shaped response with L1+L3+L4 flags and
PipelineStatus.layer_2_transformer == FAILED. No exception ever propagates.
Calibration (Phase A)
Architecture §4.8 prescribes FixedDiscount(0.85) for v0.2 -- raw softmax probabilities multiplied by a conservative factor. This is the default in ml_config.yaml.
TemperatureScaling is fully implemented and wired into the calibrate CLI, but it is not validated against clinical data in v0.2. ECE numbers produced today reflect the fixture data, not clinical reality; treat them as mechanism tests, not calibration claims. Real calibration ships in v0.3 once clinical labels are available per the roadmap.
bh-sentinel-ml calibrate --labels labels.jsonl --out calibration.json
Evaluation
Run the pipeline against a fixture file and get a per-entry report (human-readable, matches the style of core's bh-sentinel test-patterns).
bh-sentinel-ml evaluate --fixtures my_fixtures.yaml
bh-sentinel-ml evaluate --corpus config/eval/real_world_corpus.yaml --enable-transformer
The shared real-world corpus at config/eval/real_world_corpus.yaml (public-domain literature + synthetic clinical vignettes + true negatives) is what the L1 vs L2 diagnostic runs against.
Clinical Use Notice
This is clinical decision support software. It is not a diagnostic tool, not a substitute for clinical judgment, and not FDA-cleared or approved. Organizations deploying this software in clinical settings are responsible for their own clinical validation, regulatory compliance, and patient safety protocols. See CLINICAL_DISCLAIMER.md in the main repository.
Documentation
See docs/architecture.md for the full Layer 2 design, docs/release-process.md for release mechanics, and the main repository for everything else.
License
Apache License 2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bh_sentinel_ml-0.2.0.tar.gz.
File metadata
- Download URL: bh_sentinel_ml-0.2.0.tar.gz
- Upload date:
- Size: 24.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ed3c0ac6899ebd84c550c91e611ed02a3ccbc9a434e3b9da43a76d7de3ab5490
|
|
| MD5 |
eb65d7b2bce7e8b93097749dd6338fea
|
|
| BLAKE2b-256 |
80ac5d5d3d0d74b70f574cd06210e5eaef2d055fa3f784f3e44f39a3ab5a6858
|
Provenance
The following attestation bundles were made for bh_sentinel_ml-0.2.0.tar.gz:
Publisher:
publish-ml.yml on bh-healthcare/bh-sentinel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bh_sentinel_ml-0.2.0.tar.gz -
Subject digest:
ed3c0ac6899ebd84c550c91e611ed02a3ccbc9a434e3b9da43a76d7de3ab5490 - Sigstore transparency entry: 1344909187
- Sigstore integration time:
-
Permalink:
bh-healthcare/bh-sentinel@043b964b8840038812831902ece33cb54717ce91 -
Branch / Tag:
refs/tags/ml-v0.2.0 - Owner: https://github.com/bh-healthcare
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-ml.yml@043b964b8840038812831902ece33cb54717ce91 -
Trigger Event:
push
-
Statement type:
File details
Details for the file bh_sentinel_ml-0.2.0-py3-none-any.whl.
File metadata
- Download URL: bh_sentinel_ml-0.2.0-py3-none-any.whl
- Upload date:
- Size: 27.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
01f43780263f3112f32557933fe69c57db1440ff88ab3bfc91532afd4704676d
|
|
| MD5 |
493f0fe29a459042211858c92b597ef2
|
|
| BLAKE2b-256 |
27702725207369359732b4e1a22df889cbc7fdbf1f7c4bf1ca0ec8a0a9f2e183
|
Provenance
The following attestation bundles were made for bh_sentinel_ml-0.2.0-py3-none-any.whl:
Publisher:
publish-ml.yml on bh-healthcare/bh-sentinel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bh_sentinel_ml-0.2.0-py3-none-any.whl -
Subject digest:
01f43780263f3112f32557933fe69c57db1440ff88ab3bfc91532afd4704676d - Sigstore transparency entry: 1344909280
- Sigstore integration time:
-
Permalink:
bh-healthcare/bh-sentinel@043b964b8840038812831902ece33cb54717ce91 -
Branch / Tag:
refs/tags/ml-v0.2.0 - Owner: https://github.com/bh-healthcare
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-ml.yml@043b964b8840038812831902ece33cb54717ce91 -
Trigger Event:
push
-
Statement type: