Skip to content

Medical AI · Generative AI & LLMs · Lesson 2 of 7

Prompting for clinical tasks

Reviewed by Dr. Ram Kumar G, MBBS, MD (Internal Medicine), MPH (USA), on · Last updated

  • Intermediate
  • Technical focus
  • About 30 minutes
  • Includes exercise

Before this lesson: How large language models work

In short

A good clinical prompt states the role and task, gives the relevant context, sets explicit limits (use only the text provided, say 'not stated' rather than guess), specifies an exact output format and includes a worked example. Prompting is not a one-off craft: treat each prompt as a version to be tested on labelled synthetic cases, and validate every output in code before it is used.

You will learn to

  • Write a structured prompt with role, task, constraints, output format and examples
  • Build chat messages for a few-shot extraction task in Python
  • Validate model output against a schema and reject malformed results
  • Compare prompt versions on a labelled test set

The parts of a clinical prompt

Chat-based models take a list of messages. A system message sets standing instructions; user messages carry the task and data; assistant messages can show example answers. The most reliable prompts are explicit about each of the parts below.

PartPurposeExample
Role and taskSay what the output is for'You extract information from clinic notes for a diabetes registry.'
ConstraintsPrevent guessing and scope creep'Use only information written in the note. Do not guess.'
UnknownsGive the model a safe way to say it does not know'Return null if not stated.'
Output formatMake the result machine-checkable'Return only JSON with exactly these keys …'
ExamplesShow exactly what a good answer looks likeOne or more worked note-and-answer pairs (few-shot prompting)

Building a few-shot prompt

python
SYSTEM = """You extract information from clinic notes for a diabetes registry.
Return only JSON with exactly these keys:
  "diabetes_type": one of "type 1", "type 2", "gestational", "other", "not stated"
  "latest_hba1c_percent": a number, or null if not stated
  "on_insulin": true, false, or null if not stated
Use only information written in the note. Do not guess."""

EXAMPLE_NOTE = "54F, T2DM for 8 yrs on metformin. HbA1c today 8.1%. No insulin."
EXAMPLE_ANSWER = '{"diabetes_type": "type 2", "latest_hba1c_percent": 8.1, "on_insulin": false}'

def build_messages(note):
    return [
        {"role": "system", "content": SYSTEM},
        {"role": "user", "content": f"Note:\n{EXAMPLE_NOTE}"},     # one worked example
        {"role": "assistant", "content": EXAMPLE_ANSWER},
        {"role": "user", "content": f"Note:\n{note}"},
    ]

messages = build_messages("Synthetic note: 31M, type 1 since age 12, basal-bolus insulin. A1c 7.4% (Mar).")
for m in messages:
    print(f"[{m['role']}] " + m["content"].replace("\n", " ")[:70])

# [system] You extract information from clinic notes for a diabetes registry. Ret
# [user] Note: 54F, T2DM for 8 yrs on metformin. HbA1c today 8.1%. No insulin.
# [assistant] {"diabetes_type": "type 2", "latest_hba1c_percent": 8.1, "on_insulin":
# [user] Note: Synthetic note: 31M, type 1 since age 12, basal-bolus insulin. A
A system message, one worked example and the new synthetic note, as chat messages.
  • These messages can be sent to any chat-model API your organisation has approved. Read the API key from an environment variable, never write it into code or notebooks.
  • Many providers also offer 'structured output' or JSON modes that constrain the format. They reduce format errors but do not make the content correct.

Validating every output

A model's reply is untrusted input. Before anything is stored or shown, check that it parses, has exactly the expected fields and contains plausible values. The examples below are recorded outputs from an imaginary model, showing common failure modes.

python
import json

ALLOWED_TYPES = {"type 1", "type 2", "gestational", "other", "not stated"}

def validate(raw):
    """Return (record, problems). Never trust model output without checking it."""
    try:
        record = json.loads(raw)
    except json.JSONDecodeError:
        return None, ["not valid JSON"]
    problems = []
    if set(record) != {"diabetes_type", "latest_hba1c_percent", "on_insulin"}:
        problems.append(f"unexpected keys: {sorted(record)}")
    if record.get("diabetes_type") not in ALLOWED_TYPES:
        problems.append(f"diabetes_type not allowed: {record.get('diabetes_type')!r}")
    a1c = record.get("latest_hba1c_percent")
    if a1c is not None and not (isinstance(a1c, (int, float)) and 3 <= a1c <= 20):
        problems.append(f"implausible HbA1c: {a1c!r}")
    if record.get("on_insulin") not in (True, False, None):
        problems.append("on_insulin must be true, false or null")
    return record, problems

outputs = [
    '{"diabetes_type": "type 1", "latest_hba1c_percent": 7.4, "on_insulin": true}',
    'Sure! Here is the JSON: {"diabetes_type": "type 2"}',
    '{"diabetes_type": "Type II", "latest_hba1c_percent": 74, "on_insulin": "yes"}',
]
for raw in outputs:
    record, problems = validate(raw)
    print("OK" if not problems else "REJECT", problems)

# OK []
# REJECT ['not valid JSON']
# REJECT ["diabetes_type not allowed: 'Type II'", 'implausible HbA1c: 74', 'on_insulin must be true, false or null']
Schema and plausibility checks that reject malformed or implausible outputs.
  • The third output would have entered an HbA1c of 74, perhaps a value in mmol/mol mistaken for a percentage. Plausibility checks catch errors that format checks miss.
  • Validation catches malformed answers, not wrong ones: a well-formed record with an invented value passes. That is what evaluation on labelled cases is for.

Testing prompts on labelled cases

Changing a prompt changes behaviour in ways that are hard to predict; even formatting changes can shift performance substantially (Sclar et al., 2024). Keep a set of synthetic notes with correct answers written by a clinician, and score every prompt version against it.

python
gold = [
    {"diabetes_type": "type 1", "latest_hba1c_percent": 7.4, "on_insulin": True},
    {"diabetes_type": "type 2", "latest_hba1c_percent": None, "on_insulin": False},
    {"diabetes_type": "gestational", "latest_hba1c_percent": 5.6, "on_insulin": None},
    {"diabetes_type": "type 2", "latest_hba1c_percent": 9.2, "on_insulin": True},
]
prompt_v1 = [   # validated outputs from the first prompt version
    {"diabetes_type": "type 1", "latest_hba1c_percent": 7.4, "on_insulin": True},
    {"diabetes_type": "type 2", "latest_hba1c_percent": 7.0, "on_insulin": False},  # invented value
    {"diabetes_type": "type 2", "latest_hba1c_percent": 5.6, "on_insulin": False},  # wrong type, guessed
    {"diabetes_type": "type 2", "latest_hba1c_percent": 9.2, "on_insulin": True},
]
prompt_v2 = [   # after adding "Do not guess" and the null rules
    {"diabetes_type": "type 1", "latest_hba1c_percent": 7.4, "on_insulin": True},
    {"diabetes_type": "type 2", "latest_hba1c_percent": None, "on_insulin": False},
    {"diabetes_type": "gestational", "latest_hba1c_percent": 5.6, "on_insulin": None},
    {"diabetes_type": "type 2", "latest_hba1c_percent": 9.2, "on_insulin": False},  # missed insulin
]

def field_accuracy(predictions):
    fields = gold[0].keys()
    return {f: sum(p[f] == g[f] for p, g in zip(predictions, gold)) / len(gold) for f in fields}

for name, preds in [("prompt v1", prompt_v1), ("prompt v2", prompt_v2)]:
    print(name, field_accuracy(preds))

# prompt v1 {'diabetes_type': 0.75, 'latest_hba1c_percent': 0.75, 'on_insulin': 0.75}
# prompt v2 {'diabetes_type': 1.0, 'latest_hba1c_percent': 1.0, 'on_insulin': 0.75}
Field-level accuracy for two prompt versions on the same four labelled synthetic notes.
  • Version 2 stopped inventing values but still missed one insulin user. Field-level scores show where to improve next.
  • Four notes is a demonstration. Real evaluation sets need tens to hundreds of cases, including awkward ones: negations ('no insulin'), abbreviations, conflicting values and missing data.

Techniques and what the evidence says

TechniqueWhat it doesCaution
Few-shot examplesShows the exact format and judgement expectedExamples can bias answers toward their content; vary them
Step-by-step reasoningAsking the model to reason before answering can improve multi-step problems (Wei et al., 2022)Written reasoning may not reflect how the answer was produced; check the answer, not the explanation
Grounding in supplied text'Use only the note' reduces reliance on memorised knowledgeModels can still add information; validate against the source
Explicit unknownsAllowing 'not stated' or null reduces guessingCheck that the model actually uses it
Structured outputJSON or schema-constrained replies are easy to checkValid format does not mean correct content

Safety in practice

  • Clinical notes can contain text that looks like instructions ('ignore previous instructions…'). Treat note content as data, keep instructions in the system message, and never let model output trigger actions without checks (prompt injection).
  • Log prompts, model versions and outputs so that problems can be traced; re-run your test set whenever the model or prompt changes.
  • Keep a clinician responsible for any output that reaches a record or a patient.

Never paste identifiable patient information into public AI tools

  • Text sent to a public chatbot or API leaves your organisation. Use only tools your organisation has approved for clinical data, under a proper agreement, and follow its rules on what may be entered.
  • All examples in this course use synthetic notes written for teaching.

Exercise

Design, validate and evaluate a prompt that extracts diabetes information from synthetic clinic notes.

Data: Twenty synthetic clinic notes with clinician-style labels, written for the notebook (Created for this course; no real patient data)

  1. Write a system prompt and two few-shot examples for the three-field extraction task.
  2. Run the prompt through an approved model (or the recorded outputs provided in the notebook) on all 20 notes.
  3. Validate every output with the schema checks and count how many are rejected and why.
  4. Score field-level accuracy against the labels, then change one thing in the prompt and re-score.
  5. Add three adversarial notes (a negation, an mmol/mol HbA1c and an embedded instruction) and check how the prompt copes.

The runnable notebook and worked solution will be published soon. You can work through the steps with the code on this page in the meantime.

Key takeaways

  • State the task, limits, unknowns and exact output format, and include examples.
  • Treat every model output as untrusted and validate it in code.
  • Version prompts and test each version on labelled cases.
  • Keep note text as data, log everything, and keep a clinician accountable.

Terms used: Few-shot prompting, Hallucination, Large language model (LLM), Prompt injection

Related: How large language models work, Medical LLMs and their benchmarks, Clinical NLP track

FAQ

What is few-shot prompting?

Including one or more worked examples of input and ideal output in the prompt, so the model can copy the format and judgement.

Does asking the model to 'think step by step' help?

It can improve performance on multi-step problems, but the written reasoning is not a reliable account of how the model reached its answer. Evaluate the answers themselves.

How many test cases do I need to evaluate a prompt?

Enough to cover the variety and edge cases of real notes, typically tens to hundreds, labelled by people who know the domain. Small sets can mislead.

Can I use a public chatbot to extract data from real notes?

Not with identifiable information. Use only tools approved by your organisation for clinical data, under a data-processing agreement.

What is prompt injection?

Text in the input, such as a note or document, that contains instructions aimed at the model. It can make the model ignore its task, so input text must be treated as data.

Educational content only. This material teaches methods; it is not clinical advice. Code, models and examples here are not validated medical devices and must not be used to make decisions about real patients without proper clinical validation, governance and any required regulatory approval. Examples use synthetic or openly licensed de-identified data only. Never paste identifiable patient information into public AI tools. Mentions of models, tools or vendors are for identification, not endorsement.