CAMPUX learn / ai / 09
Project 09 of 09
Two lists. Every difference cited.

Medication Reconciliation

An agent for Campux Health that lines up what the clinic thinks a patient takes against what the pharmacy actually filled, flags every dose, duplicate and interaction discrepancy with both sources cited, and writes the report a pharmacist signs. It never decides; it never sees a name.

build time
6 to 8 hours
cost
Under $8 if torn down the same day4
services
Foundry Agent Service, Azure AI Language (PII detection, Text Analytics for health), Azure SQL Database, Blob Storage, Entra ID, Azure Monitor
assumes
Project 07's PHI handling. You can explain managed identity and role assignment.
exams
Overlaps AI-103, AI-200
vocabulary
Reconciliation, medication list, discrepancy, duplicate therapy, interaction, sig, pharmacist sign-off

The problem

Every Campux Health patient has two medication lists that disagree: the one in the clinic's record, written at the last visit, and the one the pharmacy has actually been filling since.

A pharmacist reconciles them by hand before a visit, reading a note that says "continue metoprolol" against a fill history that says the dose changed in March and a second beta blocker appeared in June. It takes twenty minutes per patient and it is the twenty minutes that catches the dangerous combination. The chief pharmacist wants the lining-up done before she sits down, with every discrepancy pointing at exactly which line in which source, so she spends her time deciding, not searching. She does not want the system to decide. And she wants nothing with a name in it to reach a model.

definition
Discrepancy. A medication that appears in one list and not the other, or in both with a different dose, frequency or route, or twice under two names. Reconciliation is the act of listing every one and deciding, drug by drug, which list is right. The deciding is a clinician's job.

The architecture

Two sources in, one report out, and the agent may only say "these differ, here is where."

Medication Reconciliation architecture: a clinic record's notes are redacted by Azure AI Language PII detection and mined by Text Analytics for health; a pharmacy fill feed is normalised into the same shape; an agent in a Microsoft Foundry project compares the two lists against reference tables and logs every discrepancy with cited source lines; a pharmacist reviews and signs one patient at a time. the agent may only say: these differ, and here is the line in each source TWO SOURCES DE-IDENTIFY AND EXTRACT MICROSOFT FOUNDRY PROJECT PHARMACIST REVIEW Clinic recordorders, note Pharmacy feedfill history PII detectionAzure AI Languageredact first Medication entitiesText Analyticsfor health Agent · Foundry Agent Servicefour discrepancy kinds, cited Reference tablesfile search · interactions, dose ranges Audit logevery discrepancy, pseudonymous ID Reconciliation reportthree columns, no prose Pharmacist signs offone patient at a time, logged Microsoft Entra ID · split rolesagent: structured lists and reference tables only · reviewer: counts only · pharmacist: one-patient re-identification, signs · no keys 1 2 3 4 5 6 7 8
livepress play to reconcile one patient
Figure 10 The comparison is code; the agent reads prose into rows and cites. The pharmacist is the only tier that sees a name, one patient at a time, and the sign-off is hers.
  1. Redact. The clinic note goes through PII detection before anything else reads it.
  2. Extract. Text Analytics for health pulls medication, dose, frequency and route, and catches the stopped aspirin.
  3. Normalise. The pharmacy fill history is parsed into the same medication shape.
  4. Compare. The agent gets both lists under a pseudonymous ID and emits four kinds of discrepancy, each citing a line in each source.
  5. Check the reference. Interaction and dose-range flags must cite a row in the reference tables.
  6. Log it. Every discrepancy and its citations go to an append-only audit table.
  7. Report. The pharmacist's worksheet is built from the log, with no model prose in it.
  8. Sign. The pharmacist opens one patient, re-identified for that view, decides per discrepancy, and signs; the access is logged.
Service map, for readers coming from AWS
JobAWS versionThis buildSame idea?
ModelBedrock modelFoundry model deploymentYes
Agent runtimeBedrock AgentFoundry Agent ServiceYes
PHI redactionComprehend Medical PHI detectionAzure AI Language, PII detectionYes
Medication extractionComprehend Medical, medication entitiesText Analytics for health: medication, dosage, frequency, route1Yes
Reference tablesKnowledge baseFile search over interaction and dose-range tablesYes
Audit trailCloudTrail + a ledger tableAzure Monitor + an append-only log tableYes
IdentityIAMEntra ID + managed identity, split rolesDifferent. Read the trade-offs below

The build

In this order. Step 5 is the whole project: every discrepancy must cite a line in each source or it does not exist. Synthetic data throughout.

  1. Foundry project and model

    Create a Foundry project, deploy gpt-5-mini; same setup as Project 01.

    The model answers in the playground.
  2. Two synthetic sources that disagree

    Twenty fake patients. In Azure SQL, a clinic record per patient: a medication order list plus a short visit note that mentions medications in prose ("continue metoprolol, stop the aspirin"). In Blob Storage, a pharmacy fill CSV per patient: drug, strength, sig, fill date. Plant disagreements on purpose: a dose that changed, a duplicate under a brand and a generic name, a drug the note stopped that the pharmacy kept filling, and one known interaction pair.

    Clinic note, patient row 07:
    "Continue metoprolol 25 mg BID. Stop aspirin per cardiology.
    Pt reports taking a water pill her sister gave her."
    
    Pharmacy fills, patient row 07:
    metoprolol tartrate 50 mg, 1 tab BID, filled 2026-06-14
    Toprol-XL 50 mg, 1 tab daily, filled 2026-07-02
    aspirin 81 mg, filled 2026-07-20
    Twenty patients, at least twelve planted discrepancies, and a sheet listing each one with the lines that prove it. That sheet is your answer key.
  3. Reference tables

    Write two short PDFs: a synthetic interaction table (pairs and severity) and a dose-range table (drug, usual range). Upload to a file search vector store. These are the only things the agent may cite that are not one of the two sources.

    The vector store shows two files indexed, and you can name the interaction pair you planted.
  4. Redact, then extract

    Run PII detection over every note; keep the mapping table apart under its own role, exactly as in Project 07. Run Text Analytics for health over the redacted notes to pull medication name, dosage, frequency and route as entities, and normalise the pharmacy CSV into the same shape. Now each patient is a pseudonymous ID with two structured medication lists.

    For row 07, the note yields metoprolol 25 mg BID and a stopped aspirin. Verified: aspirin comes back marked negative with a "Stop" course relation. The sister's water pill comes back as a medication form with no name at all, "pill", and the extractor does not call it a diuretic; deciding it is an unidentified medication is the agent's job in step 5, not the extractor's.
  5. The agent

    Create an agent with file search over the reference tables. Instructions: for each patient, compare list A and list B and produce discrepancies of four kinds only, missing, dose or sig differs, duplicate therapy, interaction, each citing the exact line in each source and, for interactions, the reference table row. Never recommend a change. Never state a medication that is not in a source.

    Row 07 produces four discrepancies: dose differs (25 mg vs 50 mg), duplicate therapy (metoprolol tartrate and Toprol-XL), aspirin stopped but still filled, and an unidentified diuretic mentioned in prose with no pharmacy record. Each cites its lines.
  6. Audit every discrepancy

    Log each discrepancy to an append-only table: pseudonymous ID, kind, source A line, source B line, reference row if any, timestamp. No free text from the model in this table beyond the kind.

    After a full run, you can answer "why did we flag row 07's metoprolol" by reading one row that points at two lines.
  7. The pharmacist report

    Build the report from the audit table: per patient, three columns (clinic list, pharmacy list, discrepancies) with the citations, and nothing the model wrote in prose. A pharmacist role can open one patient at a time, re-identified only for that view, and sign off with a decision per discrepancy.

    The pharmacist opens row 07, sees four discrepancies with their lines, marks each keep, change or ask the patient, and signs. The sign-off is logged with her identity.
  8. Identity

    Three roles: the agent's identity (structured lists and reference tables only, no mapping table), a reviewer role (aggregate counts only), the pharmacist role (one patient at a time, re-identified, can sign). Remove any key used while building.

    grep -ri key .env* returns nothing. The reviewer role cannot open a patient; the pharmacist role can, and the access is logged.
  9. Score it against the answer key

    Compare the agent's discrepancies with the sheet from step 2. Count found, missed, and invented.

    A precision and a recall. "Invented" is zero, or you go back to step 5.
  10. Tear it down
    azd down

    Then check the resource group by hand, including the Azure AI Language resource.

    The resource group is empty. Today's cost is under $8.

Where it breaks

Cause each one on purpose. A reconciliation tool that invents a drug is more dangerous than the disagreement it was meant to find.

The trade-offs

Let the agent compare, or write the comparison in code?
Exact comparison of two normalised lists is code, and this build does it in code first. The agent earns its place on the prose: "continue metoprolol" in a note and "stop the aspirin" are not rows until something reads them. It reads; the code compares; the pharmacist decides.
Four discrepancy kinds, or free text?
Free text is richer and cannot be audited or scored. Four kinds with citations can be counted against an answer key and logged without a model's sentence in the log. Richness is the pharmacist's, on the sign-off.
Reference tables in file search, or the model's own knowledge?
The model knows drug interactions. It also knows some that are wrong, and you cannot tell which. A small reference table you control is smaller and honest. Real deployments buy a licensed drug database and put it behind the same tool.
Report, or alert?
An alert per discrepancy interrupts a pharmacist twelve times per patient. A report she opens before the visit is the workflow she asked for. Alerts are for the interaction pair, if anything.
HIPAA, or a non-US framework?
Written for HIPAA, on synthetic data. The shape, redact first, extract, compare, cite, human signs, travels; the legal basis for touching real medication histories does not, and a pharmacist sign-off is a regulated act in most places.3

In the interview

"Tell me about an agent that cross-checks records."

  • decisionA reconciliation agent: redact, extract medications from prose, compare two lists, emit four kinds of discrepancy with both source lines cited, and a pharmacist signs.
  • reasonThe comparison is code; the agent exists to read prose into rows.
  • watchedPrecision and recall against a planted answer key, with "invented" held at zero.

"How do you stop it recommending a change?"

  • decisionThe output shape is four discrepancy kinds and citations; there is no field for advice.
  • reasonA reconciliation tool that decides is practicing medicine.
  • watchedWhether any prose from the model reached the report. None does; the report is built from the audit table.

"Where do the interactions come from?"

  • decisionA reference table the agent must cite by row; nothing from the model's memory.
  • reasonA wrong interaction from training data is indistinguishable from a right one.
  • watchedThe one flag that had no reference row, before I forbade it.

Evidence

Row 07, three ways
The clinic note, the pharmacy fills, and the four discrepancies with their citations.
Precision and recall
The counts against the answer key, with "invented" shown as zero.
The repo
The synthetic generator with its answer key, the two reference PDFs, the instructions, the role script, and a README stating plainly that this uses synthetic data and does not recommend medication changes.
One sentence for the résumé
"Built a medication reconciliation agent that de-identifies clinical text, extracts medications with Text Analytics for health, compares two record sources, and reports every discrepancy with cited source lines for pharmacist sign-off, scored against a planted answer key."

Next

Notes

  1. Checked against Microsoft Learn on 2 September 2026, and run on this page’s own sample note on 3 September: "Stop aspirin" came back as the medication with certainty=negative and a CourseOfMedication relation to "Stop", and metoprolol arrived with its dosage and frequency as linked entities. Text Analytics for health extracts medication names with dosage, frequency and route, links them to standard vocabularies, and detects negation, which is what turns "stop the aspirin" into a stopped medication rather than an active one. Microsoft's own terms say it is not a medical device and its output needs human oversight; that is the pharmacist.
  2. The interaction and dose-range tables here are synthetic and short. A real deployment licenses a drug database and exposes it behind the same tool; the rule that an interaction must cite a row does not change.
  3. Not legal advice. Real medication histories are PHI; touching them needs a signed Business Associate Agreement with Microsoft, in-scope services, and your organization's own sign-off. A pharmacist's reconciliation sign-off is a regulated professional act; this project produces the worksheet, not the act.
  4. "Under $8" assumes twenty small records, two short reference PDFs, and teardown the same day. Azure AI Language billing and Foundry model tokens are the two line items that grow with real volume.