Governed Content Intelligence
In pharma, AI may only recommend or generate medically, legally and regulatory-approved content — and someone must prove which approved claim each sentence came from.
My role. Owned the content-lineage data product and GenAI market adaptation
- per-market dossier adaptation
- ~3 mo → 1 wkper-market dossier adaptation
- markets, incl. 6 low- & middle-income
- ~25markets, incl. 6 low- & middle-income
- lineage to source and approval
- Slide-levellineage to source and approval
- GenAI
- Knowledge graph
- Lineage
- Recommendation
- FastAPI
- python-pptx
Architecture reconstructed with synthetic data; proprietary implementation excluded.
01Problem
In pharma, AI may only recommend or generate content that has passed medical, legal and regulatory (MLR) review — and someone must be able to prove which approved claim each sentence came from. Market-access teams also present the same reimbursement evidence in a different format for every country: adapting one dossier took about three months, so smaller markets waited quarters before patients could get the drug reimbursed.
02Context
- Users: brand, field and market-access teams; MLR reviewers; regional affiliates.
- Constraint: generative AI is fast but ungoverned; regulated content is governed but slow. Without lineage, nothing generated is usable.
- Goal: recommendations and generated documents built only from approved content, with lineage that survives an audit.
03Data
- Customer signals: profile, specialty and engagement history.
- Content metadata: asset, key message, claim, supporting evidence, approval status and approval ID, market, expiry.
- Lineage edges: which slide or message used which claim, which claim rests on which evidence, which approval covers it.
04Architecture
- Customerprofile · specialty
- Interactionsengagement history
- Content / metadata graphasset → claim → evidence → approval
- Eligibility filterapproved · in-market · not expired
- Ranking / recommendationrelevance among eligible content
- Generated outputslides, dossiers, messages
- Evidence / content lineageevery sentence → source + approval ID
Eligibility comes before ranking and is deterministic. A model decides what is most relevant; it never decides what is allowed.
05What I built
- The content-lineage data product at Bristol Myers Squibb.
- GenAI market adaptation of reimbursement dossiers, replacing agency drafting so markets could file in parallel.
- Two public companions on synthetic data: a governance catalog with impact and provenance analysis, and a governed slide generator.
The generation gate from the public slide generator — a claim that is not approved never reaches a slide, and every slide that is rendered carries its approval:
lineage, skipped = [], []
for item in content["items"]:
if item["mlr_status"] != "Approved": # governance gate
skipped.append({"title": item["title"], "reason": f"MLR status {item['mlr_status']}"})
continue
_add_claim_slide(prs, item)
lineage.append({
"slide_title": item["title"],
"content_id": item["content_id"],
"mlr_approval_id": item["mlr_approval_id"],
"source_ref": item["source_ref"],
})06Modeling / AI approach
- Constrain, don't filter. The generator is populated only from approved content, instead of generating freely and checking afterwards.
- Lineage is a graph. Impact ("what changes if this claim is withdrawn?") is a descendants query; provenance ("where did this sentence come from?") is an ancestors query:
def build_lineage(edges):
g = nx.DiGraph()
for e in edges:
g.add_edge(e["from"], e["to"], via=e["via"])
return g
def impact(g, node):
return sorted(nx.descendants(g, node)) if node in g else []
def provenance(g, node):
return sorted(nx.ancestors(g, node)) if node in g else []
def sources_reached(g, node):
"""Upstream nodes that are themselves sources (no upstream of their own)."""
return [n for n in nx.ancestors(g, node) if g.in_degree(n) == 0] if node in g else []07Evaluation
- The governance checks run like tests: every dataset owned and classified, every KPI traced to a source, every generated slide traced through key message → MLR approval → content → source asset.
- In the public generator demo, three approved claims render and the one claim still in review is refused — a mechanism check, not a production benchmark.
- Withdrawing an approved claim lists exactly which assets it touches.
08Production considerations
- Served through an API (FastAPI in the public rebuild) so every downstream tool inherits the same gate.
- Lineage is written into the artifact itself (speaker notes) and a sidecar record, so it survives when a file is emailed out of the system.
09Results
- Per-market dossier adaptation: ~3 months → ~1 week.
- Rolled across ~25 markets, including 6 low- and middle-income countries that had previously waited longest.
- Slide-level lineage from generated output to source evidence and approval.
10Tradeoffs / lessons
- Lineage at the slide level, not the document level. Document-level lineage cannot answer the question an auditor actually asks.
- Generation is only as fast as review. Carrying the approval ID with every piece of content is what lets a reviewer check a draft instead of re-researching it.