← All workflows

Workflow · September 22, 2026

Turn Unstructured Clinical Notes into a Structured Research-Ready Data Extract

✓ TestedHealthcareFor Healthcare
Time saved~20 minutes per chart

The task

Clinical research coordinators and physician-scientists routinely pull variables out of free-text progress notes, H&Ps, and consult letters to populate a study database or a retrospective cohort. This workflow takes a de-identified note pasted as text and returns a validated, schema-conformant row you can drop into REDCap or a CSV. It's for the moment when you've got 40 charts to abstract before Friday's DSMB meeting and no data manager to help.

Before AI

A trained abstractor reads the note, hunts for each variable on the case report form, retypes values into the database, and flags ambiguities for adjudication. Realistic pace on a moderately complex oncology or ILD note is 20–40 minutes per chart, longer if the note references prior labs or imaging inline. Inter-abstractor disagreement is a known headache — recent work on LLM-based extraction from ILD notes benchmarks against exactly this manual baseline.

The workflow

Important: Only paste notes that have already been de-identified per your institution's HIPAA Safe Harbor process. Do not put PHI into a general-purpose LLM. If your organization has a BAA-covered deployment (Azure OpenAI, AWS Bedrock in a covered account, an on-prem Llama, etc.), use that endpoint.

Step 1 — Extract to a strict JSON schema with provenance

The prompt below locks the model to a fixed schema, forces null for missing fields (no hallucinated values), and requires a verbatim quote from the note for every non-null value. Provenance is what makes downstream QA possible.

Prompt
You are a clinical data abstractor supporting a retrospective cohort study. You will receive one de-identified clinical note. Extract the variables below into a single JSON object. Follow these rules exactly:

1. Output ONLY valid JSON. No prose, no markdown fences, no commentary.
2. If a variable is not explicitly stated or clearly inferable from the note, set it to null. Do NOT guess.
3. For every non-null value, include an "evidence" object with a "quote" field containing a short verbatim span (<=200 chars) copied from the note, and a "confidence" field of "high", "medium", or "low".
4. Use ISO 8601 for dates (YYYY-MM-DD). If only month/year is given, use YYYY-MM. If only year, use YYYY.
5. Normalize units: weight in kg, height in cm, labs in the units shown in the schema.
6. Medications: capture generic name, dose, route, frequency as separate fields. Do not merge.
7. Do not infer diagnoses from medications alone. A diagnosis must be stated as a diagnosis, assessment, or problem.

Schema:
{
  "demographics": {"age_years": int, "sex": "M|F|other|unknown"},
  "encounter": {"date": "YYYY-MM-DD", "type": "inpatient|outpatient|consult|other"},
  "primary_diagnosis": {"term": str, "icd10_if_stated": str, "evidence": {...}},
  "comorbidities": [{"term": str, "evidence": {...}}],
  "smoking_status": {"value": "never|former|current|unknown", "pack_years": number|null, "evidence": {...}},
  "vitals": {"weight_kg": number, "height_cm": number, "bmi": number, "spo2_percent": number, "evidence": {...}},
  "key_labs": [{"name": str, "value": number, "unit": str, "date": str, "evidence": {...}}],
  "imaging_findings": [{"modality": str, "finding": str, "date": str, "evidence": {...}}],
  "current_medications": [{"generic_name": str, "dose": str, "route": str, "frequency": str, "evidence": {...}}],
  "assessment_and_plan_summary": str
}

Return the JSON object only. The note follows after the line "===NOTE===".

===NOTE===
Sample input
De-identified Progress Note — Pulmonology Clinic
Patient: [REDACTED], 64-year-old female
Encounter date: 2026-03-14 (outpatient)

HPI: Ms. [REDACTED] returns for follow-up of idiopathic pulmonary fibrosis diagnosed 2024-08 on surgical lung biopsy (UIP pattern). She reports worsening exertional dyspnea over the past 6 weeks, now MMRC 3 (was 2 at last visit). Dry cough persists. No fevers, no hemoptysis. Uses 2L supplemental O2 with ambulation.

PMH: IPF, GERD, hypertension, osteoporosis. Former smoker, quit 2010, 25 pack-year history.

Meds: Nintedanib 150 mg PO BID, omeprazole 20 mg PO daily, amlodipine 5 mg PO daily, calcium/vitamin D.

Vitals: Wt 58.2 kg, Ht 162 cm, BMI 22.2, SpO2 92% on room air at rest, drops to 87% on 6MWT.

Recent studies: PFTs 2026-03-10 — FVC 1.94 L (58% predicted), DLCO 42% predicted, both down from FVC 2.15 L (64%) and DLCO 49% six months prior. HRCT 2026-02-28 — increased reticulation in bilateral lower lobes with new traction bronchiectasis, stable honeycombing, no ground glass to suggest exacerbation.

A/P: 1) IPF with objective progression on antifibrotic — continue nintedanib, dose-reduce if GI intolerance recurs; refer to lung transplant evaluation. 2) Chronic hypoxemia on exertion — increase ambulatory O2 to 3L, pulmonary rehab referral. 3) GERD — continue omeprazole. 4) HTN — well controlled.

Step 2 — Self-audit the extract against the source

LLMs will occasionally invent an ICD-10 code that wasn't in the note, or copy a lab value from the wrong date. This second pass rechecks each field against the original note text and returns a diff you can act on. The ILD extraction study found audit-style prompts materially reduced spurious values compared to single-shot extraction.

Prompt
You will receive: (a) a JSON extract produced in the previous step, and (b) the original clinical note it was extracted from. The extract is in the assistant's previous message. The note is the sample-input from the first user turn — treat it as the ground truth.

For every non-null value in the JSON, verify that the "quote" field is actually a substring of the source note (allowing minor whitespace differences) and that the extracted value is a faithful reading of that quote. Also check:

- Dates: does the ISO date match what the note says?
- Units: is the unit consistent with the schema?
- Diagnoses vs. history: is a listed comorbidity actually stated as a diagnosis or on the problem list, not just implied by a medication?
- Medications: are dose, route, and frequency each present when the note supplies them?
- Missing variables: scan the note for any schema field currently null that IS explicitly stated. List these as "should_be_populated".

Return a JSON object of this shape and nothing else:
{
  "verified_fields": int,
  "issues": [
    {"path": "e.g. key_labs[0].value", "problem": "hallucinated | wrong_date | wrong_unit | quote_not_in_note | misclassified | other", "note": "one-sentence explanation", "suggested_fix": "corrected value or 'set to null'"}
  ],
  "should_be_populated": [{"path": str, "suggested_value": str, "quote": str}],
  "overall_confidence": "high|medium|low"
}

Step 3 — Emit the final REDCap-ready row

Now flatten the corrected extract into a single CSV row matching the study's variable names. Keeping this as a separate step means your abstractor can review Step 2's diff before values ever hit the database.

Prompt
Apply every "suggested_fix" from the audit JSON to the original extract JSON, and populate any "should_be_populated" entries. Then flatten the corrected extract to a single CSV row using the header below. Use empty string for null. Multi-value fields (comorbidities, meds, labs, imaging) should be pipe-delimited (" | ") within their cell. Preserve ISO dates.

Header:
record_id,encounter_date,encounter_type,age,sex,primary_dx,icd10,comorbidities,smoking_status,pack_years,weight_kg,height_cm,bmi,spo2_rest,meds,fvc_l,fvc_pct,dlco_pct,hrct_findings,plan_summary

Output exactly two lines: the header, then one data row for this patient. Use record_id = "SAMPLE-0001". No commentary, no code fences.

Gotchas

  • PHI is non-negotiable. A public consumer chatbot is not HIPAA-appropriate even for "just testing." Use a BAA-covered endpoint or run this against synthetic/de-identified text only.
  • ICD-10 hallucination is the most common failure. If the note doesn't state a code, the model may confidently produce one that's close but wrong (e.g., J84.112 vs. J84.10 for IPF). Step 2 catches most of these; a human should still sign off before database entry.
  • Date attribution errors on inline labs. When a note mentions "PFTs six months ago showed…", the model sometimes anchors that lab to the encounter date. Spot-check date fields on any longitudinal variable.
  • Negation and history vs. active. "No hemoptysis" and "history of DVT, resolved" get misclassified more often than you'd expect. Add explicit negation-handling rules to Step 1 if your CRF depends on it.
  • Site-specific abbreviations. If your service uses local shorthand, add a short glossary to Step 1's system message. Generic models don't know that "SFA" means your sarcoidosis follow-up algorithm.
  • This does not replace an IRB-approved abstraction protocol. Treat the output as a first pass that a qualified abstractor reviews, not as the final source of truth.

Time saved

Manual abstraction of a moderately complex specialty note runs roughly 20–40 minutes when the CRF has 15–25 variables and requires cross-referencing labs and imaging. This workflow — extract, audit, flatten — takes about 2 minutes of model time plus 3–5 minutes of human review of the Step 2 diff. Call it ~20 minutes saved per chart, conservatively, with the biggest gains on notes where variables are scattered across HPI, PMH, and A/P sections. For a 200-chart retrospective cohort, that's a week of coordinator time reclaimed for the analyses that actually need a human.

What we got when we ran it

We executed every prompt above, in order, against the sample input (model: claude-sonnet-4-6). Outputs below are real and unedited apart from length truncation.

Step 1 output

{ "demographics": { "age_years": 64, "sex": "F" }, "encounter": { "date": "2026-03-14", "type": "outpatient" }, "primary_diagnosis": { "term": "Idiopathic pulmonary fibrosis", "icd10_if_stated": null, "evidence": { "quote": "returns for follow-up of idiopathic pulmonary fibrosis diagnosed 2024-08 on surgical lung biopsy (UIP pattern)", "confidence": "high" } }, "comorbidities": [ { "term": "GERD", "evidence": { "quote": "PMH: IPF, GERD, hypertension, osteoporosis.", "confidence": "high" } }, { "term": "Hypertension", "evidence": { "quote": "PMH: IPF, GERD, hypertension, osteoporosis.", "confidence": "high" } }, { "term": "Osteoporosis", "evidence": { "quote": "PMH: IPF, GERD, hypertension, osteoporosis.", "confidence": "high" } }, { "term": "Chronic hypoxemia on exertion", "evidence": { "quote": "2) Chronic hypoxemia on exertion — increase ambulatory O2 to 3L, pulmonary rehab referral.", "confidence": "high" } } ], "smoking_status": { "value": "former", "pack_years": 25, "evidence": { "quote": "Former smoker, quit 2010, 25 pack-year history.", "confidence": "high" } }, "vitals": { "weight_kg": 58.2, "height_cm": 162, "bmi": 22.2, "spo2_percent": 92, "evidence": { "quote": "Wt 58.2 kg, Ht 162 cm, BMI 22.2, SpO2 92% on room air at rest, drops to 87% on 6MWT.", "confidence": "high" } }, "key_labs": [ { "name": "FVC", "value": 1.94, "unit": "L", "date": "2026-03-10", "evidence": { "quote": "PFTs 2026-03-10 — FVC 1.94 L (58% predicted)", "confidence": "high" } }, { "name": "FVC % predicted", "value": 58, "unit": "%", "date": "2026-03-10", "evidence": { "quote": "PFTs 2026-03-10 — FVC 1.94 L (58% predicted)", "confidence": "high" } }, { "name": "DLCO % predicted", "value": 42, "unit": "%", "date": "2026-03-10", "evidence": { "quote": "DLCO 42% predicted, both down from FVC

…output truncated at 250 words.

Step 2 output

{ "verified_fields": 48, "issues": [ { "path": "current_medications[3].generic_name", "problem": "other", "note": "Calcium/vitamin D is listed as a single combined entry; these are two distinct supplements and dose, route, and frequency are absent from the note, but the combined name is acceptable given note phrasing.", "suggested_fix": "Acceptable as-is; flag that dose/route/frequency are not supplied in the note and cannot be populated." }, { "path": "current_medications[3].dose", "problem": "other", "note": "Dose is null because the note does not specify it for calcium/vitamin D — this is correct; no issue with extraction, just confirming null is appropriate.", "suggested_fix": "Retain null — not stated in note." }, { "path": "current_medications[3].route", "problem": "other", "note": "Route is null because the note does not specify it for calcium/vitamin D — null is appropriate.", "suggested_fix": "Retain null — not stated in note." }, { "path": "current_medications[3].frequency", "problem": "other", "note": "Frequency is null because the note does not specify it for calcium/vitamin D — null is appropriate.", "suggested_fix": "Retain null — not stated in note." } ], "should_be_populated": [ { "path": "primary_diagnosis.icd10_if_stated", "suggested_value": null, "quote": "No ICD-10 code is stated anywhere in the note — confirm null is correct." }, { "path": "key_labs[3]", "suggested_value": "{\"name\": \"FVC\", \"value\": 2.15, \"unit\": \"L\", \"date\": null}", "quote": "both down from FVC 2.15 L (64%) and DLCO 49% six months prior" }, { "path": "key_labs[4]", "suggested_value": "{\"name\": \"FVC % predicted\", \"value\": 64, \"unit\": \"%\", \"date\": null}", "quote": "both down from FVC 2.15 L (64%) and DLCO 49% six months prior" }, { "path": "key_labs[5]", "suggested_value":

…output truncated at 250 words.

Step 3 output

record_id,encounter_date,encounter_type,age,sex,primary_dx,icd10,comorbidities,smoking_status,pack_years,weight_kg,height_cm,bmi,spo2_rest,meds,fvc_l,fvc_pct,dlco_pct,hrct_findings,plan_summary SAMPLE-0001,2026-03-14,outpatient,64,F,Idiopathic pulmonary fibrosis,,GERD | Hypertension | Osteoporosis | Chronic hypoxemia on exertion,former,25,58.2,162,22.2,92,nintedanib 150 mg PO BID | omeprazole 20 mg PO daily | amlodipine 5 mg PO daily | calcium/vitamin D,1.94,58,42,Increased reticulation in bilateral lower lobes with new traction bronchiectasis; stable honeycombing; no ground glass to suggest exacerbation (HRCT 2026-02-28),IPF with objective progression on antifibrotic therapy (declining FVC and DLCO; worsening HRCT): continue nintedanib with dose reduction if GI intolerance recurs; refer to lung transplant evaluation. Chronic hypoxemia on exertion: increase ambulatory O2 to 3L; pulmonary rehab referral. GERD: continue omeprazole. Hypertension: well controlled.

---

This content is for informational purposes only and is not medical advice. AI tools used with patient data must meet your organization's HIPAA and privacy requirements.

Source: healthcaredive.com

More for Healthcare professionals →

Get the next one in your inbox

One daily brief. Every story gets a hype verdict.

No spam. Unsubscribe anytime.

Exact prompts included · Untested steps are marked · Corrections are public