rad-decider (0.8B)

One open model for the small decisions that run a radiology workflow β€” from the order, through the report, to what happens after sign-off. It answers a typed question in one forward pass with a calibrated probability, and writes no text.

Give it the case (order, DICOM header fields, clinical history, report sections) and a typed question β€” yes/no, choose one, or an ordered scale β€” and it returns a probability for every option. It reads the logits of the option letters at a fixed answer slot, so it can only answer with one of the options you allowed. It is a LoRA adapter (r = 32) on Qwen/Qwen3.5-0.8B: small enough to run next to a PACS or RIS.

Research artifact β€” not for clinical use. This release is provided for research and evaluation. It is not a medical device and must not be used to inform patient care. Licensed Apache-2.0, matching the Qwen3.5 base model.

The problem

Radiology loses time on decisions that are simple to state and easy to miss at volume: Does the exam fit the clinical question? Right side, right contrast? Is the history enough to read? Does the report describe the side that was ordered? Does it describe contrast that was not given? Did a critical result get called? Who should recheck a rejected report? Missed, each one costs more than it would have to fix: a rescan, a call-back, a reassignment, an addendum, a repeat scan. rad-decider turns each of these into a typed question with a calibrated probability, so a workflow can flag before sign-off and sort the worklist on arrival instead of correcting afterwards.

Three decisions that pay for themselves

Each is compared with the untuned base model (Qwen/Qwen3.5-0.8B, same prompt, same letter readout). These three span the whole cycle: before the report, while it is written, and after sign-off.

Before the report β€” emergency worklist triage. A stroke-like CT head order should go to the top of the list, not into a first-come queue.

modality: CT   ordered_procedure: CT head without contrast   patient_class: Emergency   order_priority: STAT
reason_for_exam: Sudden left-sided weakness and slurred speech, onset 40 minutes ago
Q (ordered scale): How urgently should this study be read?  routine < urgent < stat < critical_suspected
rad-decider -> critical_suspected (0.87)      untuned base -> routine (wrong)

On the held-out synthetic test (1,200 cases): rad-decider 0.90 vs untuned base 0.67 accuracy. Saves: critical cases read first.

While reporting β€” wrong-side check that does not cry wolf. Left knee ordered, the report is about the left knee and mentions the right knee only as a normal comparison. That is not a conflict; flagging it wastes radiologist time.

exam: XR knee left   ordered_side: left   dicom_laterality: L
findings: Mild osteoarthritis of the left knee. The right knee is normal.
Q (yes/no): Does the report describe a side that conflicts with the ordered side or the DICOM laterality?
rad-decider -> no (1.00)                      untuned base -> yes (false alarm)

On real reports, side-vs-examination (694 reports, 48 flagged, a question never seen in training): rad-decider AUROC 0.98 vs untuned base 0.55. Saves: no false addendum, no needless call-back.

After sign-off β€” a rejected report goes to the right team. The client says the prior was not retrieved. The model says why, and who should fix it.

exam: CT KUB non-contrast   client_message: "Comparison study on your platform; not retrieved."
Q (choice): Why did the client reject this report?        rad-decider -> missing_comparison (1.00)   base -> wrong_patient_or_exam (wrong)
Q (choice): Who should handle the recheck?                rad-decider -> operations (1.00)          base -> original_radiologist (wrong)

On the held-out synthetic test (1,196 cases): reason accuracy rad-decider 0.99 vs base 0.13; recheck routing 0.94 vs 0.53. Saves: fixed by the right team first time.

One model across the whole workflow

All rows below are the same single adapter; the question text (instruction + options) is the only thing that says what to do. Each row is one main category of the workflow, and its score is the average accuracy over the questions in that category on the held-out synthetic test set (about 1,200 cases per question), compared with the untuned Qwen/Qwen3.5-0.8B base model's majority answer. 22 of the questions sit before the report is written β€” the cheapest places to catch a problem: fixed before the scan or before reading, it costs minutes; after sign-off it costs an addendum, a call-back or a repeat scan.

Category What it decides What it prevents Rad_decider accuracy Qwen base accuracy
Ordering, protocol & pre-scan safety Whether the requested exam, modality, protocol and contrast fit the clinical question, plus the pre-scan safety checks (renal function, pregnancy, contrast allergy, MRI implant). Wrong exam, modality, contrast or side; duplicate scans; contrast in at-risk kidneys; unscreened pregnancy; allergic reactions; unsafe MRI. 0.95 0.69
Intake, triage & assignment Body region, contrast actually used, laterality conflict and reading urgency on arrival; whether the clinical history is complete; subspecialty, complexity, reader credentialing, SLA class and second-read need. Mis-routed studies, a wrong-side study, critical cases queued, holds and re-reads, the wrong reader, missed turnaround targets, missed double reads. 0.96 0.56
Report integrity, consistency & comparison Contrast, side, impression support and follow-up while the report is dictated; whole-payload internal consistency; whether the report matches the examination ordered; and whether the prior and comparison statement are correct. Wrong-side or wrong-contrast reports, unsupported impressions, contradictory reports, a report of another examination, comparing with the wrong prior. 0.98 0.78
Report error review & support Whether a candidate report differs from a reference and what kind of error (omission, severity, location, comparison, uncertainty); sentence-level errors; whether the report supports a claim (incl. negation and hedging); and whether structure and completeness are satisfied. Changed, dropped or hallucinated findings; mis-coded reviews; unsupported claims; incomplete or broken reports. 0.99 0.70
Clinical communication, follow-up & summaries Whether a critical/actionable finding is present, its urgency and whether the call is documented; incidental findings and follow-up recommendations; and whether the patient-facing summary is faithful and well-toned. A critical result never called or treated as routine; a missed incidental finding; a lost follow-up; an alarming or misleading summary. 0.99 0.60
Post-sign-off review, delivery & alerts Which reports to peer-review and how significant the discrepancy is; why a client rejected a report and who should recheck it; addendum type and clinician notification; and whether an AI/QC alert is valid. Missed risky reports; rejections bouncing between teams; wrong or unnecessary amendments; alert fatigue. (peer-review discrepancy label is simulated) 0.98 0.56
Beyond radiology (non-radiology exemplars) Critical lab values, medication-order checks and referral routing β€” the same one-model design applied outside radiology. A critical value not triaged; an unsafe order proceeding; a referral sent to the wrong clinic. 0.94 0.54

How it works

  • Readout, not generation. The prompt letters the options and ends at an answer slot; the model's next-token distribution over the option letters is the answer. It cannot write anything but one of the options you allowed.
  • Calibrated. Per-question temperature scaling is fitted on validation data (calibration.json); custom / unseen questions are served uncalibrated (T = 1.0).
  • Shuffled during training. Option order and field order are shuffled, so the letter-to-option mapping is per example and the model follows the question text rather than position.

How to use

pip install "transformers>=5.18" peft torch huggingface_hub
python inference.py            # downloads Qwen/Qwen3.5-0.8B + this adapter and runs a few example decisions
from inference import RadDecider

rd = RadDecider("Rology/rad-decider")

# 1) Yes/No (noul) β€” laterality check
state = {
    "exam": "XR knee left",
    "ordered_side": "left",
    "dicom_laterality": "L",
    "findings": "Mild osteoarthritis of the left knee. The right knee is normal.",
    "impression": "Degenerative change of the left knee."
}
q_noul = {
    "type": "noul",
    "instructions": "Does the report describe a side that conflicts with the ordered side or the DICOM laterality? "
                    "A normal comparison of the other side is not a conflict."
}
res = rd.ask(state, q_noul)
print(res)  # {'answer': 'no', 'probabilities': {...}, 'calibrated': False}

# 2) Choose one (choice) β€” rejection reason
state = {
    "exam": "CT KUB non-contrast",
    "client_message": "Comparison study on your platform; not retrieved."
}
q_choice = {
    "type": "choice",
    "instructions": "Why did the client reject this report?",
    "options": [
        ("missing_comparison", "Prior/comparison study missing or not retrievable"),
        ("wrong_patient_or_exam", "Wrong patient or wrong examination"),
        ("quality_issue", "Technical/quality issue"),
        ("other", "Other")
    ]
}
res = rd.ask(state, q_choice)
print(res)

# 3) Ordered scale (score) β€” urgency triage
state = {
    "modality": "CT",
    "ordered_procedure": "CT head without contrast",
    "patient_class": "Emergency",
    "order_priority": "STAT",
    "reason_for_exam": "Sudden left-sided weakness and slurred speech, onset 40 minutes ago",
    "age_years": 72,
    "sex": "M"
}
q_score = {
    "type": "score",
    "instructions": "How urgently should this study be read, based on clinical history, patient class and priority?",
    "options": [
        ("routine", "Outpatient or follow-up, no acute concern"),
        ("urgent", "Acute symptoms, read within hours"),
        ("stat", "Emergency, read immediately"),
        ("critical_suspected", "History suggests a life-threatening finding")
    ]
}
res = rd.ask(state, q_score)
print(res)

Notes:

  • To get calibrated probabilities, use a trained question_key from questions.json and pass question_key="<key>" to rd.ask(...). Untrained/custom questions are served uncalibrated (calibrated: False).
  • noul is shorthand for yes/no. choice takes an ordered list of (option_key, definition). score is an ordered scale (lower/higher as written).
  • questions.json lists every trained question with its exact instruction and options; use them verbatim (and the matching question key) to get calibrated probabilities. The prompt format, the letter readout and the calibration in inference.py are exactly those used in training.

Training and provenance

  • Data: RadJev-Synth, fully synthetic (no patient records). Labels are computed from the facts that generated each case, never by a model. Report text was varied by a locally run open model (Qwen3.8-27B, Apache-2.0) and every rewrite had to pass exact fact checks (side, negation, hedge, numbers and units, severity, contrast). No proprietary-model output.
  • Recipe: LoRA r = 32 / alpha 64 on all language-model linear layers, 1 epoch (9,000 steps, effective batch 32), restricted-softmax cross-entropy over the valid option letters, option order and field order shuffled during training, 16+ paraphrases per question; per-question temperature scaling on validation data.

Scope and limitations

  • Research artifact β€” not for clinical use. Licensed under Apache-2.0 (the license permits commercial use, but the model is a research artifact and is not validated for clinical or commercial deployment).
  • Not a medical device. Decision support for workflow and quality control; every flag needs a human decision. Medical rules in the questions (e.g. the follow-up policy) are encodings of published facts and assumed policies β€” verify them with your radiologists.
  • The numbers are synthetic. They are on held-out synthetic cases and are not real-world performance. Some real-data evidence exists for the after-report checks only (contrast mismatch AUROC 0.96, wrong side 0.98, on a small de-identified quality-control sheet of real reports). Nothing before the report (orders, DICOM headers) has been validated on real data yet.
  • The base comparison is the majority-answer baseline. The "Qwen base accuracy" column is the majority-class accuracy on the same held-out test set (the score from always answering the most common option) β€” the untuned Qwen/Qwen3.5-0.8B answers these lettered questions at roughly this level, and it is the baseline to beat, not a tuned one.
  • English only. Text only (no images).

Coverage notes

  • This adapter answers 97 typed questions over 25 decision areas; the table above groups them into 7 main categories by workflow phase.
  • RADS categorisation (TI-RADS, Lung-RADS) and a few questions are generated but not part of this adapter (pending radiologist sign-off): they are not counted above.
  • All comparisons in this card are with the untuned Qwen/Qwen3.5-0.8B base model, same prompt and readout.

Citation

If you use this model, please cite it:

@software{raddecider2026,
  title  = {rad-decider: a small decision model for the radiology workflow},
  author = {Rology},
  year   = {2026},
  url    = {https://huggingface.co/Rology/rad-decider}
}

The readout design β€” typed questions answered over a shared state by scoring the option-letter logits at the answer slot, with no text generation β€” follows the open System One / Jev-style family of decision models. This release contributes its own synthetic radiology data, question catalogue, training recipe and evaluation. Base model: Qwen/Qwen3.5-0.8B (Apache-2.0).

Contact

Rology β€” open radiology AI. Released under Apache-2.0 as a research artifact; not validated for clinical use.

Downloads last month
30
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for Rology/rad-decider

Adapter
(438)
this model