Skip to main content

Healthcare-specific LLM guardrails middleware for clinical safety

Project description

Medguard

Healthcare-specific LLM guardrails middleware for clinical safety.

Wraps any LLM (Anthropic, OpenAI, Ollama) with five safety layers before and after each inference call:

Layer What it does
PHI Detection Detects and redacts SSN, DOB, phone, email, MRN, and labeled names
Clinical Scope Blocks or warns when queries fall outside medical scope (legal, financial)
Drug Safety Checks drug-drug interactions and contraindications via OpenFDA + RxNorm
Hallucination Detection Flags fake drug names, impossible dosages, and overconfident claims
Output Annotation Inlines [WARNING: ...] markers on flagged response spans

Install

pip install medguard                          # core only
pip install "medguard[anthropic]"             # + Anthropic LLM
pip install "medguard[anthropic,openai]"      # + OpenAI-compatible
pip install "medguard[anthropic,openai,nlp]"  # + Presidio PHI engine

Quick start

from medguard import MedGuard

mg = MedGuard()

# Check text without calling an LLM
result = mg.check("Patient SSN: 123-45-6789 is taking warfarin and aspirin.")
print(result.phi_result.phi_detected)      # True
print(result.phi_result.processed)         # "Patient SSN: [REDACTED] is taking ..."
print(result.drug_result.highest_severity) # InteractionSeverity.HIGH

# Full guardrailed LLM chat
import asyncio
response = asyncio.run(mg.achat("What are side effects of metformin?"))

Run the API server

medguard serve               # default port 8080
medguard serve --port 9090   # custom port
python -m medguard serve     # alternative

Endpoints:

GET  /v1/health                     dependency status (RxNorm, OpenFDA)
POST /v1/chat                       guardrailed LLM chat (stream: true supported)
POST /v1/check/phi                  standalone PHI detection / redaction
POST /v1/check/drug-interactions    standalone drug interaction check
GET  /docs                          Swagger UI

Example requests

# PHI redaction
curl -X POST http://localhost:8080/v1/check/phi \
  -H "Content-Type: application/json" \
  -d '{"text": "Patient John Smith, SSN: 123-45-6789", "mode": "redact"}'

# Drug interaction check
curl -X POST http://localhost:8080/v1/check/drug-interactions \
  -H "Content-Type: application/json" \
  -d '{"drugs": ["warfarin", "aspirin"]}'

# Guardrailed chat
curl -X POST http://localhost:8080/v1/chat \
  -H "Content-Type: application/json" \
  -d '{"messages": [{"role": "user", "content": "What is the max dose of ibuprofen?"}]}'

Docker

ANTHROPIC_API_KEY=sk-... docker compose -f docker/docker-compose.yml up

All guardrails are configurable via environment variables:

MEDGUARD_GUARDRAILS__PHI_DETECTION__MODE=block          # redact | flag | block
MEDGUARD_GUARDRAILS__DRUG_SAFETY__SEVERITY_THRESHOLD=high
MEDGUARD_GUARDRAILS__SCOPE_ENFORCEMENT__ACTION=block    # warn | block
MEDGUARD_LLM__PROVIDER=openai
MEDGUARD_LLM__MODEL=gpt-4o

Configuration

Config is loaded from ~/.medguard/config.json (auto-created on first run).

{
  "guardrails": {
    "phi_detection":          { "enabled": true, "mode": "redact", "engine": "regex" },
    "drug_safety":            { "enabled": true, "severity_threshold": "moderate" },
    "scope_enforcement":      { "enabled": true, "action": "warn" },
    "hallucination_detection":{ "enabled": true, "confidence_threshold": 0.7 }
  },
  "llm": {
    "provider": "anthropic",
    "model": "claude-haiku-4-5-20251001",
    "api_key_env": "ANTHROPIC_API_KEY"
  },
  "api": { "host": "0.0.0.0", "port": 8080 }
}

PHI engine options:

  • "regex" — zero-dependency, ships with the library (default)
  • "presidio" — Microsoft Presidio + spaCy, higher recall (pip install "medguard[nlp]")

Architecture

User input
    │
    ▼
[PHI Detection] ──── redact / block
    │
[Scope Enforcement] ── warn / block
    │
[Drug Safety Check] ── warn / block  ◄── OpenFDA API + RxNorm + static table
    │
    ▼
   LLM
    │
    ▼
[Hallucination Detection] ── flag / block  ◄── RxNorm + SNOMED bundle
    │
    ▼
Annotated response

Each guardrail runs in an isolated try/except — an API timeout in drug safety never blocks the full request.

NeMo Guardrails integration

from nemoguardrails import RailsConfig, LLMRails
from medguard import MedGuard
from medguard.integrations.nemo import MEDICAL_COLANG_CONFIG

mg = MedGuard()
config = RailsConfig.from_content(colang_content=MEDICAL_COLANG_CONFIG)
rails = LLMRails(config)

for name, action in mg.as_nemo_actions().items():
    rails.register_action(action, name=name)

Extending medguard

Every guardrail implements a Protocol interface. Register custom engines via entry points:

# In your package's pyproject.toml
[project.entry-points."medguard.phi_engines"]
my_engine = "my_package:MyPHIEngine"

[project.entry-points."medguard.interaction_sources"]
drugbank = "medguard_drugbank:DrugBankClient"

Then select it in config: "phi_detection": {"engine": "my_engine"}.

Contribution targets:

  • New drug interaction sources (InteractionSourceProtocol)
  • New PHI engines (PHIEngineProtocol)
  • Curated drug interaction data (medguard/knowledge/data/drug_interactions.csv)
  • Clinical Colang flows (medguard/integrations/nemo.py)
  • Language-specific medical fact checkers

Development

git clone https://github.com/sarvanithin/Medguard
cd Medguard
pip install -e ".[anthropic,dev]"
pytest tests/ -m "not integration"   # unit tests (no network)
pytest tests/ -m integration         # hits real OpenFDA / RxNorm APIs

Data sources

Source Used for
RxNorm API Drug name normalization
OpenFDA Drug Labels Interaction + contraindication text
OpenFDA Adverse Events Adverse event counts
Bundled SNOMED-CT subset Medical terminology validation
Curated static table Highest-risk drug pairs (offline fallback)

License

Apache 2.0

Project details


Download files

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

Source Distribution

medguard_llm-0.1.0.tar.gz (56.3 kB view details)

Uploaded Source

Built Distribution

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

medguard_llm-0.1.0-py3-none-any.whl (53.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: medguard_llm-0.1.0.tar.gz
  • Upload date:
  • Size: 56.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for medguard_llm-0.1.0.tar.gz
Algorithm Hash digest
SHA256 48afc132423871ab391fe10dd9f84e45f3632c7162ea1c5c3821491e253cd198
MD5 3e010212295924c9e924c96ac3bcb42a
BLAKE2b-256 da0b4cf6a297f2f66abdc5bc6ced2b8bcff91b9871c398f7a17beba2baf7da6d

See more details on using hashes here.

Provenance

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

Publisher: publish.yml on sarvanithin/Medguard

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

File details

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

File metadata

  • Download URL: medguard_llm-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 53.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for medguard_llm-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 71524b8bf0b81b293ececdcf8c53e43c2a331d9d74179d7de67924b738a63885
MD5 7d541e0eff119bf2531666b15b4d244d
BLAKE2b-256 6d18519f5452ee879097f19909b395e120ba1bcb0d0208ead7267943142633dd

See more details on using hashes here.

Provenance

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

Publisher: publish.yml on sarvanithin/Medguard

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