← ALL POSTS

Building Discharge Summary Agent

In this article, I am going to explain how I made the discharge summary agent.

06.2026·5 MIN READ· Agentic RAGLLMAIMachine LearningPython

Problem statement

We are given a patient's folder containing different kinds of PDF data related to the course of actions during their admission in the hospital. We need to summarize it and tell what actually changed after the patient was discharged.

Why even need an agent for this?

You might be thinking: why do we need an agent? We can just give it to any LLM and it will do it, right? No. There are lots of problems here. First, LLMs do not understand the structure by themselves. Data may be lab reports, tables, handwritten notes, and more. An LLM could hallucinate or mix things up, so we need to provide very refined information and let it reason in a controlled fashion.

Safety Principles

We need to make sure our agent follows these rules. The data will pass through the agent and reach the LLM as a refined version.

  • never guess
  • never fabricate (never create anything by self)
  • unknown > wrong
  • if data is not available, say not available
  • conflicts: flag, do not decide
  • provenance for every fact (the source of truth must exist)
Safety principles for the discharge summary agent
Safety principles for the discharge summary agent

Ingestion

Our agent takes the PDF and extracts structured text from it. We start by dividing the pages and storing their text one by one where possible; otherwise, we flag the page for OCR extraction.

{
  page_number,
  text,
  has_text,
  ocr_applied
}

Data in the folder could be of two types: digitally typed documents and handwritten notes.

Evidence Extraction

After ingestion, we have an array containing long strings of text. We pass those strings to the LLM to generate an initial structured state. Gemini, or another model, can process one page at a time or in batches and return the following JSON format.

{
  "diagnoses": [{ "fact": "...", "source_text": "..." }],
  "medications": [{ "name": "...", "dosage": "...", "frequency": "...", "route": "...", "status": "...", "source_text": "..." }],
  "allergies": [{ "fact": "...", "source_text": "..." }],
  "procedures": [{ "fact": "...", "source_text": "..." }],
  "pending_results": [{ "fact": "...", "source_text": "..." }]
}
You are an expert clinical data extractor prioritizing safety over completeness. Unknown > Wrong. Never fabricate, never infer, never guess.

Extract diagnoses, medications (with dosage, frequency, route, and status), allergies, procedures, and pending results. For each entity, extract the exact source_text snippet that proves it. If a field or category is missing, use Not Documented. Respond strictly in the requested JSON format.

We take the output and push it to our state variable, then aggregate the states by grouping related information together. If page 4 says diabetes and page 15 says hypertension, we do not decide prematurely which one to keep. We collect and bundle the facts without reasoning too early, while tracking conflicts, review flags, missing fields, trace logs, and the agent-loop step count.

{
  "patient_info": {},
  "diagnoses": [],
  "procedures": [],
  "medications": { "admission": [], "discharge": [] },
  "allergies": [],
  "follow_up": [],
  "pending_results": [],
  "hospital_course": [],
  "conflicts": [],
  "missing_fields": [],
  "flags_for_review": [],
  "evidence": [],
  "trace": [],
  "step_count": 0
}

Agent Loop

After we have our initial state, we start our loop. It runs for a finite number of steps or until the complete state is validated.

Reconciliation

We check what changed during admission and after discharge, including medication changes. If we find a change that is not justified, such as medication being added or stopped, we store it in the state for review.

Conflict Detection

If we find conflicts, such as multiple diagnoses, we flag them for review and escalate instead of deciding on our own.

Validate

If fields are missing or a source does not exist, we mark them for review.

LLM

Finally, we pass the validated state to the LLM and let it generate the output with these guardrails.

You are an expert clinical documentation assistant.
Write a clear, structured Markdown Discharge Summary based ONLY on the provided clinical evidence.

CRITICAL RULES:
- NEVER infer, guess, or fabricate clinical information.
- If a field or category is missing or empty, explicitly state Not Documented.
- Organize into standard clinical headings: Diagnoses, Medications, Allergies, Procedures, Pending Results.
- Do not invent patient names, dates, or hospital locations unless they are strictly provided in the text.

Provided Evidence:
{state_text}

Architecture Design

Architecture design for the discharge summary agent
Architecture design for the discharge summary agent

Implementation: https://github.com/paramcodes/junior-doctor

Originally published here ↗ — migrated verbatim from my previous portfolio.