Inspiration
Medication errors are one of the most preventable causes of patient harm, but managing polypharmacy in real time is genuinely hard. A physician considering a new drug for a patient on ten medications with kidney disease can't realistically cross-reference every interaction and contraindication on the spot. We wanted to build a tool that takes a patient's record, a proposed drug, and a clinical question, and returns a structured, grounded safety report.
What it does
MedRAG lets a physician upload a FHIR R4 patient bundle, enter a proposed medication and their clinical question, and receive a structured safety report covering drug–drug interactions, contraindications, lab flags, and monitoring recommendations. Every claim is cited back to a retrieved source — openFDA drug labels, DDInter 2.0 interaction pairs, or openFDA FAERS adverse-event data — and the system explicitly flags what it doesn't know. The physician makes the final call.
How we built it
We built a RAG pipeline backed by Redis 8 native vector sets. An ingestion script pulls FDA drug labels, DDInter interaction pairs, and FAERS adverse-event signals for ~270 generics, chunks and embeds them with a local BGE model, and stores them in Redis. At query time, we parse the uploaded FHIR bundle, run source-balanced retrieval with per-source quotas to ensure interaction, label, and safety data are all represented, assemble a structured prompt, and send it to Claude Opus 4.8. The report comes back with numbered chunk citations that the Flask UI renders as clickable links to the original sources.
Challenges we faced
We ran the BGE embedding model entirely on CPU, which made ingestion slow and required careful optimization to get through ~20k chunks in a reasonable time. We also had no access to real patient data since it's private, so we relied entirely on synthetic FHIR bundles generated by Synthea to build and test the pipeline.
Accomplishments that we're proud of
We're also proud that the system is honest about its limits: it never tells a physician an interaction wasn't found when it really means the pair wasn't in the index.
What we learned
Local embeddings with BAAI/bge-large-en-v1.5 gave us strong retrieval quality at zero API cost, which made rapid iteration during development practical.
Log in or sign up for Devpost to join the conversation.