Skip to content

From synthetic clinical notes to a simple agent, in a few hours

This article introduces an application of the team's synthetic clinical notes dataset, published on Hugging Face. It is a very small agent example, built on purpose to demonstrate the open-source LangGraph framework and to show how little it takes to get started. This agent is engineered to handle autonomous summaries over clinical notes.

The motivation was the team's synthetic data publication.

Check out information in the previous post.

I'd thought it might be helpful to introduce how I went from synthetic clinical notes to a simple agent, in a few hours.

The agent

Image

The example I built is deliberately small.

A single straightforward workflow. No branching nodes.

It only gets to grips with the open-source LangGraph framework along the way.

g = StateGraph(State)
    g.add_node("deidentify_in", deidentify_in)
    g.add_node("agent", run_agent)
    g.add_node("reidentify_out", reidentify_out)
    g.add_node("compute_trust", compute_trust)
    g.add_edge(START, "deidentify_in")
    g.add_edge("deidentify_in", "agent")
    g.add_edge("agent", "reidentify_out")
    g.add_edge("reidentify_out", "compute_trust")
    g.add_edge("compute_trust", END)
    return g.compile()

The top-level graph is linear while the ReAct agent inside loops.

deidentify_in pseudonymises PII*, using [LABEL_n] surrogates like [PERSON_1], or [NHS_1].

agent drafts the summary.

reidentify_out restores the PII at the end.

compute_trust counts the identifiers-removed sets in deidentify_in.

*Please be reassured that Personally Identifiable Information (PII) are taken only from the team's synthetic clinical notes dataset in this example.

The de-identification is ordinary.

Patient data never leaves the NHS infrastructure under any circumstances. This policy strictly governs all ML/AI Engineering lifecycle stages, including testing, prototyping, and continuous learning purpose developments.

In this example, therefore, I've chosen redaction (see details) for de-identifying the information what can then feed to Gen AI and LLMs.

My go-to model gemini-2.5-flash drafts compact eDischarge card based on NICE/NHS guidance that are pulled via Tavily.

This is a LangGraph ReAct agent (Gemini + Tavily) wrapped so the model and tools only ever see de-identified text, therefore real identifiers are restored only in the final clinician-facing answer.

messy NHS note  ──►  NoteGuard de-id  ──►  de-identified text
(synthetic)           (NHS-aware rules       + identifiers removed count
                       + vault from CSV)     + residual leakage %
                                │
                  Tavily (NICE/NHS guidance) ──►│
                                                ▼
                                         Gemini drafts
                                         compact eDischarge card
                                         (sees ONLY de-identified text)
                                                │
                         NoteGuard re-id  ◄─────┘
                         (surrogates → real names, clinician only)
                                │
                         Trust panel (de-id correctness only):
                         de-id PASS/FAIL · identifiers replaced
                         residual PII (model input) · reversible

A practical tip if you try it: decide what travels between nodes first. Almost every bug I hit was a state-shape disagreement, not a logic error.

For a prototype, I designed the structure of the graph can carry a guarantee that a script only carries by convention. The deidentify_in is the only door into the rest of the graph as shown in the sample. It is, however, on the limitation as a few hours job that de-identification is not perfectly done. So there is some leaks downstream runs and later node has receive some identifier; which should be addressed in future developments in case someone found it interested in.

Why I'm sharing it?

Moving beyond basic "vibe coding," I spent a few hours developing a simple agent with an open-source framework on top of the team's synthetic dataset. It is genuinely giving much foods for thoughts. If you have heard about agents but not yet tried building your own, the synthetic notes are ready and risk-free place to start experimenting tools on top. My code for today's experiments is public, open to all feedback.