← Case Studies
Case 003healthcare202612 weeksBuilt at Heizen

Spoken Findings Into Real Radiology Reports — At a Cost That Survives

Radiologists speak findings at clinical pace. Turning speech into template-grounded reports had to be lossless, auditable, and cheap enough for every study — not only a pilot.

Stack
Soniox
LangGraph
NestJS
Next.js
Cerebras
PostgreSQL
Scale
2026
12w
01Context

Radiologists do not write the way they think. They look, they speak, they move on. The report — structured, template-shaped, ready for the care chain — is a second job on top of the first.

At Heizen I worked on a production radiology reporting product where that second job is the product: live speech → transcript → structured clinical sections → multi-step LLM draft against a study template. The radiologist still signs.

No hospital names. No public integration surface. Three constraints shaped everything: zero information loss from dictation, template-grounded generation (not freeform essays), and unit economics that survive volume — speech billed on audio used, models chosen and metered per stage.

02The Challenge

The naive path is a demo: speech-to-text, one LLM call, "write a radiology report," ship.

It fails three ways. Loss — dictation is dense (laterality, measurements, "surrounding oedema" that only makes sense attached to a lesion); a model that "cleans up" by dropping anatomy has already failed clinically. Shape — readers expect a study template and an editor, not a chatty essay. Cost — live dictation pauses for minutes; STT that bills open connection time punishes real reading rooms, and multi-step generation without per-step telemetry cannot stay sustainable.

Naive path — demos die under clinical load

Enhancement may clean speech. It may not invent anatomy. Structuring may polish grammar. It may not drop a measurement.

03Speech and Cost of Being Live

Live dictation is not a meeting bot. Radiologists pause, resume, issue voice commands, and need radiology vocabulary to land.

We used Soniox for real-time browser transcription. Billing mattered as much as accuracy: pay for audio used, not silent seconds the mic stayed open. When we evaluated a backup STT, the filter was pricing shape first — idle-time billing looks cheap on a rate card and expensive in a reading room.

Downstream assumes a transcript you can still read and correct before generation runs.

04The Generation Pipeline

Generation is not one prompt. It is a LangGraph flow on NestJS, with live progress back to the reading UI while the draft is built.

Two paths share the same outer lifecycle (valid session, non-empty transcript, generation limits) and differ only in how the template arrives:

  • Classic — radiologist or session chooses a saved study template or custom template body.
  • Automatic — no manual template; catalog retrieval ranks a study in parallel with transcript structuring, then joins before the report model runs.

Shared stages: load pipeline settings → structure transcript → resolve template → generate → optional instruction post-process → acceptance score → persist draft and usage.

Structuring is grammatical polish with a zero-loss bar: no new findings, no inferred study name from anatomy, no invented impression at this step, every measurement and laterality kept. Output is fixed clinical sections (study, indication, comparison, findings). If structuring fails, a fallback skeleton still puts the raw transcript under findings — incomplete, not inventing.

Generation always gets template body + structured transcript. Automatic runs cannot smuggle a hand-picked template; classic session locks cannot be silently overridden. After first success, refinements stay on the same template.

Post-process keeps dangerous edits deterministic where possible (volume from three dimensions; instruction replacements only when the original phrase matches exactly once). Acceptance scoring never blocks finalization if the scorer throws — metrics must not strand a radiologist without a draft.

Classic path — structure, template, generate, score
05Cost as Architecture

Sustainable cost was a design input, not a later optimise pass.

Stage-aware models: structuring, retrieval, and generation resolve provider/model pairs independently (Cerebras preferred on the main path; other providers available with allowlists that keep high-cost tiers off the default). Every run records per-step usage — model, tokens, duration — so cost regressions have a layer, not a monthly surprise.

If a step cannot justify its spend under real volume, it does not stay on the default path.

06The Result

Radiologists dictate in the flow of work, fix transcript when needed, and get template-grounded drafts — not a raw dump and not a freeform essay. Speech, structure, template choice, writing, and scoring are separate jobs. When something is wrong, the ticket is STT, structure, selection, generation, or post-process — not "the model is bad."

I would re-attach contradiction validation and flag extraction to the default graph earlier (even shadow mode), and treat preferred-stage cost regressions as CI failures the same way type errors fail. We already store per-step usage; the missing piece is failing the build when they blow up.

When volume is real and stakes are clinical, separate hearing from structuring from writing — and price each step on purpose.