Drug Knowledge-Graph — Phased Build Plan¶
Date: 2026-06-29
Owner: Gene Lang, PharmD (Director of Pharmacy Operations) · Rx360
Status: 🟡 SCOPE / SEQUENCE / EFFORT — this is the build plan, not the build.
Grounded in: AI_Foundation/KB/01_Knowledge_Layer_KB_KG.md (node/edge model + terminology spine) · 02_Retrieval_RAG_GraphRAG.md · 03_Guardrails_Safety_Layer.md · 05_Data_Governance_MLOps.md · Product_Specs/Curated_Drug_KB_and_Tagging_Schema_2026-06-04.md (the fact schema) · Product_Specs/Medication_Intelligence_Engine_PHASED_PLAN_2026-06-04.md.
Why now. The real clinical knowledge-graph was deliberately deferred "until after the 2026-06-26 patent filing." That date has passed. The architecture is fully designed in the AI_Foundation KB; this plan turns that design into an actionable, staged build — what to build, in what order, with what data, and roughly how much effort — so it can be resourced and handed to engineering (Faraz) without re-deriving the design.
What this is (and isn't)¶
- Document KG (already shipped, on the docs site): nodes = our deliverables, edges = relationships. Navigational. Done.
- Drug/clinical KG (this plan): nodes = drugs / classes / conditions / risk markers / interactions / forgiveness profiles / members / events; edges = clinical relationships. This is the substrate the medication-intelligence product reasons over (duplicate-therapy detection, FRID load for the Fall Barometer, interaction screening, forgiveness-aware Smart Scheduling).
Two different graphs. This builds the second.
North-star architecture (from the KB, recapped)¶
- Terminology spine — anchor everything to standard codes: RxNorm/RXCUI (drug identity) · RxClass (ATC / MeSH / NDF-RT / FDA EPC / ENZYME for classes) · SNOMED CT + ICD-10-CM (conditions) · OpenFDA / DailyMed SPL (NDC, strength, label rules).
- Property graph (Neo4j or Amazon Neptune-PG). Node types: Drug · Clinical Drug · Ingredient · Drug class · Condition/Indication · Risk marker (FRID, Beers PIM, anticholinergic burden, NTI, controlled, LASA) · Interaction · Forgiveness/tolerance profile · Member (PHI, access-controlled) · Event (med-input, confirmation, dismissal, fall-signal, med-change, refill, escalation).
- Edge types:
Drug ─IS_A→ Class·Class ─SUBCLASS_OF→ Class·Drug ─HAS_INGREDIENT→ Ingredient·Class ─CARRIES_RISK→ RiskMarker {marker, weight, beersRec, effectiveDate, kbEntryId}·Drug ─INTERACTS_WITH→ Drug {severity, mechanism, management, source, clinicalLineFlag}·Drug ─HAS_TOLERANCE_PROFILE→ ForgivenessProfile {tier, foodRule, missPolicy, kbEntryId, version}·Drug ─INDICATED_FOR / CONTRAINDICATED_FOR→ Condition·Member ─TAKES→ Drug {since, provenance, confidence}·Member ─HAD_EVENT→ Event. - Knowledge-as-data, not code: every clinical edge/fact carries the
Curated Drug KB tagging-schema
provenance —
kb_entry_id,status(preliminary|validated),author/approver(no self-approval),clinical_line,evidence_strength,effective_date,version,supersedes. No clinical fact reaches a member without akb_entry_id+ pharmacist sign-off.
Phases¶
Phase 0 — Foundations (decision + scaffolding)¶
Goal: the spine and the governance rails exist before any clinical content lands.
- Decision: graph DB. Neo4j (mature Cypher, AuraDB managed, GraphRAG tooling) vs Amazon Neptune
(AWS-native, fits a BAA/private-cloud posture). Recommend Neo4j AuraDB for velocity unless the
AWS-BAA constraint dominates → then Neptune. (Gene/Faraz call.)
- Terminology ingest: load RxNorm (RRF), RxClass, SNOMED CT + ICD-10-CM, OpenFDA/DailyMed into a
staging store; build the RXCUI↔NDC and RXCUI↔class crosswalks (these already exist partially in the
Smart Add / NCPDP work for Faraz — reuse).
- Provenance/governance schema from KB 05: every node/edge gets the tagging-schema provenance
block; author≠approver enforced; status gates production use; a de-identification gateway sits in
front of any Member/Event data (PHI never in the curated layer).
- Effort: ~2–3 wks (mostly ingest plumbing + DB choice). Dependencies: none. Risk: SNOMED
licensing (UMLS account) — start the license request now.
Phase 1 — Seed the clinical graph from what we already have¶
Goal: a usable graph for the highest-value reasoning, seeded from existing curated assets — not built from scratch.
- Sources to ingest as nodes/edges (all already authored):
- Smart_Scheduling/KB/02_Drug_Forgiveness_Tolerance_Data.md (27 classes) → ForgivenessProfile
nodes + HAS_TOLERANCE_PROFILE edges. (status: preliminary → flag for Dr. B sign-off.)
- Rx360_Shared_Drive/02_Clinical_Data_and_Risk_Analysis/Rx360_Medication_Risk_Database_v1.md +
the Fall Barometer FRID tagging → RiskMarker nodes + CARRIES_RISK edges (FRID, Beers, ACB, NTI).
- Product_Specs/Scanner_Label_Requirements_KB/ → label/jurisdiction reference (kept as structured
side-tables, linked by NDC; not core clinical edges).
- Curated Drug KB tagging schema → the per-fact provenance contract (already the standard).
- Build the FRID-load query first — it's the single highest-value graph operation (feeds the Fall
Barometer's medication category). Validate it reproduces the current Balance Meter med-scoring inputs.
- Effort: ~3–4 wks. Dependencies: Phase 0. Risk: preliminary clinical content — everything
ships status: preliminary until pharmacist-reviewed; the graph must refuse to surface unreviewed
facts to members (Phase 3 rail).
Phase 2 — Retrieval layer (structured-first → vector → GraphRAG)¶
Goal: the engine answers medication questions by querying the graph, not a free LLM.
- Per KB 02: deterministic/structured retrieval first (Cypher/graph lookups serve from the table —
identity, class, FRID, interaction, forgiveness), then vector (pgvector→Qdrant/Milvus) for
semantic fallback, then GraphRAG for multi-hop ("what about this combination?").
- Self-RAG / CRAG grounding: every generated answer must cite the kb_entry_id(s) it used; ungrounded
answers are refused.
- Effort: ~4–6 wks. Dependencies: Phase 1 (graph populated). Risk: the temptation to let the
LLM "fill gaps" — the rail (Phase 3) must make that impossible for clinical content.
Phase 3 — Deterministic clinical rail (the blast door)¶
Goal: fail-closed safety — the wellness/clinical line is enforced in code, not prompts.
- Per KB 03: defense-in-depth (input moderation → retrieval grounding → output rail). The clinical
rail is deterministic: if a response touches clinical_line: true content, it must (a) be served
from a status: validated KB entry, (b) carry its provenance, (c) respect member_facing
(never | wellness-safe), and (d) fall back to "discuss with your pharmacist" when uncertain — never
improvise dosing/clinical advice.
- This is the same posture as the existing Medication_Matching_Guardrails + Guardrails_Flow_Map,
now enforced at the graph-retrieval layer.
- Effort: ~3–4 wks. Dependencies: Phase 2. Risk: this is the load-bearing safety work —
do not de-scope it to ship faster.
Phase 4 — Product integration + learning loop¶
Goal: the graph powers the actual products and improves over time.
- Medication Intelligence Engine: Smart Add / med-input resolves to RXCUI → graph enriches with
class/FRID/interaction/forgiveness (the engine stops re-deriving these per-app).
- Smart Scheduling: consumes ForgivenessProfile for tolerance-aware reminder timing.
- Fall Barometer: consumes the FRID-load query + the cross-engine medication-change event
(FRID add/remove/dose change → bounded sensitivity watch-window). (Trade-secret scoring stays in
the Barometer; the graph supplies inputs, not the score.)
- Learning loop (KB 05): Kafka event-stream + FHIR R4/US-Core; member events feed analytics behind
the de-identification gateway; pharmacist sign-off remains the gate for any new clinical fact.
- Effort: ~6–8 wks (phased per product). Dependencies: Phases 1–3.
Sequencing & rough total¶
| Phase | Focus | Effort | Gating dependency |
|---|---|---|---|
| 0 | DB choice + terminology spine + governance | 2–3 wks | UMLS/SNOMED license |
| 1 | Seed graph from existing KBs (FRID-load first) | 3–4 wks | Phase 0 |
| 2 | Retrieval (structured→vector→GraphRAG) | 4–6 wks | Phase 1 |
| 3 | Deterministic clinical rail | 3–4 wks | Phase 2 |
| 4 | Product integration + learning loop | 6–8 wks | Phases 1–3 |
~5–6 months end-to-end at a steady pace; Phases 0–1 (≈6–7 wks) already deliver standalone value (the FRID-load query + a queryable drug/class/risk graph) and can ship before the rest.
Decisions needed from Gene / Faraz¶
- Graph DB: Neo4j AuraDB (velocity) vs Amazon Neptune (AWS-BAA fit).
- Pharmacist reviewer + cadence for moving seeded facts
preliminary → validated(Dr. B? Matilda?). The graph is only as shippable as its sign-off pipeline. - Scope of v1: ship Phases 0–1 (queryable graph + FRID load) as a milestone, or hold for the full retrieval+rail stack before any product wiring.
- BAA posture for the Member/Event layer (governs where the graph + any PHI-adjacent analytics run).
Risks¶
- SNOMED/UMLS licensing lead time — start now (Phase 0 blocker).
- Preliminary clinical content — the seeded forgiveness/FRID data is design-tier until pharmacist sign-off; the rail (Phase 3) must prevent unreviewed facts from reaching members.
- Scope creep into the LLM — the discipline is structured-first, LLM-last, rail-always.