AI Chief Resident · Medication fetch and match path
Medication matching:
before and now
The LLM states the clinical request. The backend decides if a real Photon treatment is a safe match.
This document describes medication fetch and match only. It does not include lab orders, plan rendering, prescription submission, or pharmacy fulfillment.
Rationale
Why this system needs every part
No one part has all the facts. The system combines model judgment, provider data, standard drug identity, schemas, and fixed backend rules.
The LLM can understand a discussion. The LLM cannot prove that a Photon row is the correct orderable treatment.
Photon supplies orderable treatments. A Photon display name is not sufficient proof of standard drug identity.
RxNorm supplies standard identity. NDC connects a Photon product or package to that identity.
Schemas check data shape. Fixed backend checks decide whether a row can continue.
Ownership
Which steps use an LLM and which steps use code
The model reads the discussion and proposes drug, brand, dose, route, supply, and instructions.
candidateActionSchema checks the model output shape.
The selection model creates the tool input. It later selects a returned handle or returns unmatched.
Fixed code searches RxNorm and Photon. It parses, maps, filters, and ranks rows.
The backend creates one opaque handle for each returned candidate.
The LLM decides clinical intent
- Generic drug name.
- Exact requested brand.
- Strength and route.
- Patient instructions.
- Days supply and quantity.
- Refill count.
- Clinical rationale.
- Which returned handle to select.
The backend decides catalog validity
- Which search term runs first.
- Which Photon rows have a valid shape.
- Which NDC maps to a usable RxNorm concept.
- Whether the RxCUIs agree.
- Whether strength, form, and route agree.
- Whether OTC policy permits the row.
- Whether the controlled-drug block removes the row.
- Which exact Photon ID belongs to a handle.
Data boundaries
Which parts are schemas
A schema is a fixed description of allowed data. A schema checks shape and required values.
| Schema | What it checks | Failure result |
|---|---|---|
candidateActionSchema | The structured action from the first LLM step. | The model output cannot enter the selection pipeline. |
searchPrescriptionsArgsSchema | The exact prescription-search tool input. | The tool call is rejected. |
searchClinicalTreatmentsResponseSchema | The Photon response envelope. | The external response is rejected when the envelope is invalid. |
clinicalTreatmentSchema | One Photon row: ID, name, NDC, strength, and dispense units. | The backend drops only that row. |
| RxNorm response schemas | The shape of NIH RxNorm results. | The mapping returns no usable identity. |
Rules and variation
Which parts are strict and which parts are flexible
Flexible parts
These parts can produce more than one reasonable result.
- The LLM interpretation of the discussion.
- The medication proposal.
- The wording of instructions and rationale.
- The approximate RxNorm name results.
- The related RxNorm concepts.
- The Photon search results.
- The number of valid Photon candidates.
Strict parts
These parts use fixed rules for the same inputs.
- Schema parsing.
- Brand-first and generic-fallback order.
- Per-row parsing.
- NDC-to-RxCUI lookup.
- Allowed RxNorm concept types.
- RxCUI identity comparison.
- Strength, form, route, and OTC checks.
- Handle creation and resolution.
Mapping rules
Which mappings are one-to-one
Some IDs point to one exact item. Search text and clinical relationships can point to many items.
One-to-one mappings
One input identifies one exact item.
| Mapping | Rule |
|---|---|
| RxCUI → RxNorm concept | One RxCUI identifies one RxNorm concept. |
| Photon treatment ID → Photon row | One provider ID identifies one orderable row. |
| Generated handle → registered candidate | One handle resolves to one candidate in that generation scope. An unknown handle fails. |
Mappings that are not one-to-one
One input can return no item, one item, or many items.
| Mapping | Why |
|---|---|
| Discussion → prescription candidate | The LLM interprets free text. |
| Drug name → RxCUIs | One name can match many strengths, forms, routes, and brands. |
| RxCUI → related concepts | One concept can have several related concepts. |
| Search term → Photon rows | One term can return many orderable treatments. |
| NDC → RxCUI across the catalog | One mapped NDC returns one RxCUI. Some NDCs have no mapping. Many NDCs can map to the same RxCUI. |
| Brand concept → generic concepts | The code accepts one or more related generic concepts. |
| Medication request → valid candidates | One request can match several packages or products. |
The main change
Before this branch
Photon ManagementReturn a handle
Return unmatched
Now
Photon ClinicalRank it and return a handle
Return unmatched and nearest useful result
Before: main failure and limits
The Photon Management catalog was not the catalog used by the main EHR prescription search.
For example, the provider UI showed Ivermectin Topical Cream 1 %. Photon Management returned no rows for the same request. The system then returned unmatched.
- No dedicated
brandNamefield. An exact brand request could be lost. - Brand and generic terms did not have a clear brand-first order.
- A name-matched row could be used without a verified RxNorm link.
- A missing requested strength could pass.
nearestused alphabetical order.
Now: match only verified results
The new system searches the Photon Clinical catalog. This is the same catalog used by the main EHR prescription search.
- Read the NDC from a Photon row.
- Ask RxNorm for the RxCUI for that NDC.
- Accept only a fully specified generic or brand drug concept.
- Map a brand concept to its related generic clinical drug concept.
- Compare that identity with the original request concepts.
The system then checks strength, dose form, route, OTC status, and the controlled-drug block. Photon Clinical provides form and route information in the full treatment name.
Detailed view
How the two RxNorm paths meet
The system builds one RxNorm identity from the medication request. It builds a second RxNorm identity from each Photon row. A Photon row can match only when the two identities agree.
Build the accepted request set
The backend sends the generic name and exact brand name to the RxNorm approximate name search.
The first results can be broad. The backend follows related concepts and keeps fully specified generic and brand drug concepts.
Drug, brand, strength, form, and route.
Returns possible RxCUIs.
Keep fully specified generic and brand concepts.
Check each Photon row separately
Photon Clinical can return many rows. The backend treats each row as an independent candidate.
Parse → NDC → RxNorm → compareCONTINUE
Parse → NDC → RxNorm → compareCONTINUE
The other rows remain available.DROP ROW 3
A row also stops when it has no NDC, no strength, no RxNorm mapping, or only a broad RxNorm concept.
What NDC does
An NDC is a National Drug Code. It identifies a marketed medication product or package.
Photon Clinical supplies the NDC. RxNorm maps the NDC to a standard drug concept.
The Photon name search finds possible treatments. The NDC step verifies what each treatment is.
Names are not sufficient proof. A name can use a brand, a generic name, an abbreviation, or a different text format.
Different NDCs can map to the same RxNorm drug concept. This connects different packages to one standard clinical identity.
Photon NDC 00002-3544-11 → standard generic RxCUI 2734623What the NDC step does
- Connects a Photon row to RxNorm.
- Checks identity without trusting the display name.
- Connects a brand drug to its generic drug concept.
- Rejects an incomplete RxNorm concept.
- Helps prevent a similar name from becoming the wrong prescription.
What the NDC step does not do
- It does not create patient instructions.
- It does not create days supply.
- It does not create dispense quantity.
- It does not create refill counts.
- It does not prove controlled-drug status.
Compare the two standard identities
If Photon gives a brand concept, RxNorm connects that brand concept to its generic clinical drug concept.
The row passes only when its standard RxCUI is also in the accepted request set.
Request set: accepted RxCUIsPhoton row: standard RxCUIRequest set contains the row RxCUI: continue
Request set does not contain the row RxCUI: reject the row
This is not the final safety check. The backend still checks strength, form, route, OTC status, and the controlled-drug block.
Exact brands now have a clear order
If the doctor names a brand, the system searches that brand first. If it has no verified match, the system searches the generic drug name. If no brand is named, it uses brandPreference. The normal default is generic first.
{
"intent": {
"genericName": "tirzepatide",
"brandName": "Zepbound",
"strength": "7.5 mg/0.6 mL",
"form": "pen injector",
"route": "subcutaneous"
},
"brandPreference": "brand"
}Zepbound example
Request
Brand: Zepbound
Generic drug: tirzepatide
Strength: 7.5 mg/0.6 mL
Form: pen injector
Route: subcutaneous
Verified Photon result
Zepbound KwikPen Subcutaneous Solution Pen-injector 7.5 MG/0.6ML
Its generic RxNorm identity contains 12.5 MG/ML. This is a concentration. The Photon product gives 0.6 mL for one dose.
12.5 mg/mL × 0.6 mL = 7.5 mg
The two strength forms describe the same dose. The full package has 2.4 mL.
2.4 mL ÷ 0.6 mL = 4 doses
Failure behavior now
| Condition | System result |
|---|---|
| The exact brand has a verified match | Return the brand result. |
| The exact brand has no verified match | Search the generic drug name. |
| One Photon row is malformed | Drop that row and continue. |
| One Photon row has no NDC or no strength | Drop that row and continue. |
| An NDC has no RxNorm mapping | Drop that row and continue. |
| An NDC maps only to a broad RxNorm concept | Drop that row and continue. |
| The row RxCUI does not match the request RxCUIs | Reject that row. |
| A row has the wrong strength, form, or route | Reject that row. |
| All rows fail | Return unmatched. |
| All rows fail, but one row is close | Show the most compatible row as nearest. Do not return it as a selectable match. |
| A row matches the controlled-drug block | Drop that row and record telemetry. |
Warning: controlled-drug status
Do not treat the current controlled-drug check as the final design. Photon Clinical does not provide an authoritative controlled-drug field.
The new system keeps controlled status as unknown. It uses the existing controlled-drug name list as a temporary block.
The next controlled-drug change must add an authoritative data source. That work is separate from this medication fetch change.
Final comparison
| Question | Before | Now |
|---|---|---|
| Photon catalog | Photon Management. | Photon Clinical. |
| Exact brand in candidate | No dedicated field. | Yes. |
| Exact brand order | Not explicit. | Brand first, then generic fallback. |
| Name match proves identity | A name-only row could stand without a verified row. | No. A Clinical row needs an NDC-to-RxNorm identity link. |
| One malformed row | The Management path dropped only that row. | The Clinical path also drops only that row. |
| Missing requested strength | Could pass. | Does not pass. |
nearest | Alphabetical order. | Compatibility with brand, drug, strength, form, route, side, and OTC setting. |
| What AI Chief Resident selects | A returned handle. | A returned handle. |
Glossary
- LLM
- The model that reads the discussion and writes a structured medication request.
- Photon Management catalog
- A Photon API that manages catalog data. It did not return the treatments shown by the main EHR search.
- Photon Clinical catalog
- The Photon API that supplies choices in the main EHR prescription search.
- RxNorm
- A standard US drug dictionary.
- RxCUI
- An ID for one drug concept in RxNorm.
- NDC
- A medication product or package code. The system uses it to connect a Photon treatment to RxNorm.
- Fully specified drug concept
- A drug identity with drug, strength, and dose form. It can be generic or brand.
- SCD
- A fully specified generic drug concept in RxNorm.
- SBD
- A fully specified brand drug concept in RxNorm. RxNorm connects it to its related SCD.
- Handle
- A short internal ID for one verified Photon result.
Test command
Use this read-only command to run the real Chief Resident medication search with a structured request. It prints the exact tool input and the exact search result.
pnpm -C apps/api chief-resident:test-prescription-search \ --generic-name tirzepatide \ --brand-name Zepbound \ --strength "7.5 mg/0.6 mL" \ --form "pen injector" \ --route subcutaneous \ --brand-preference brand