Agent Skillsmaziyarpanahi/openmed › structuring-radiology-reports

structuring-radiology-reports

GitHub

将放射科自由文本报告转化为结构化数据,提取解剖、测量、侧别及随访建议。结合OpenMed NER实现标准化输出,支持BI-RADS等分类映射,用于辅助决策而非诊断。

skills/structuring-radiology-reports/SKILL.md maziyarpanahi/openmed

触发场景

用户拥有CT/MRI/X-ray等影像报告需结构化解析 需要提取病灶测量值、侧别或BI-RADS/Lung-RADS评估类别 需追踪偶然发现及后续随访建议 提及RadLex, DICOM-SR, ACR等专业术语

安装

npx skills add maziyarpanahi/openmed --skill structuring-radiology-reports -g -y
更多选项

不安装直接使用

npx skills use maziyarpanahi/openmed@structuring-radiology-reports

指定 Agent (Claude Code)

npx skills add maziyarpanahi/openmed --skill structuring-radiology-reports -a claude-code -g -y

安装 repo 全部 skill

npx skills add maziyarpanahi/openmed --all -g -y

预览 repo 内 skill

npx skills add maziyarpanahi/openmed --list

SKILL.md

Frontmatter
{
    "name": "structuring-radiology-reports",
    "license": "Apache-2.0",
    "metadata": {
        "pairs": "after",
        "project": "OpenMed",
        "version": "1.0",
        "category": "imaging-ocr"
    },
    "description": "Converts free-text radiology narratives into structured findings and impression — with measurements, laterality, anatomy, and follow-up recommendations — after OpenMed NER. Use when the user has a CT\/MRI\/X-ray\/ultrasound\/mammography report and needs the sections split (technique, comparison, findings, impression), lesion measurements and laterality captured, BI-RADS \/ Lung-RADS assessment categories pulled, or incidental findings and recommended follow-up tracked. Trigger keywords: radiology report, findings, impression, RadLex, DICOM-SR, BI-RADS, Lung-RADS, ACR, laterality, measurement, nodule, incidental finding, follow-up, structured reporting. Pairs after OpenMed: run openmed.analyze_text on the report (Anatomy\/Disease\/measurement entities), then assemble structured findings. De-identify the report first. Decision-support only — not a diagnostic medical device."
}

Structuring radiology reports

A radiology report is prose, but its meaning is structured: a technique, a comparison, a list of findings (each with anatomy, laterality, and a measurement), and an impression that may carry an assessment category (BI-RADS, Lung-RADS) and a follow-up recommendation. This skill turns the narrative into that structure so findings are trackable — especially incidental findings that need downstream follow-up.

OpenMed extracts the anatomy, disease/finding, and measurement spans on-device; this skill organizes them into sectioned, coded findings. It is decision-support, not a diagnostic device — every structured finding must be attributable back to its source sentence for radiologist review.

When to use

  • You have a CT/MRI/X-ray/US/mammography report and need {technique, comparison, findings[], impression} with measurements and laterality.
  • You must capture BI-RADS (breast) or Lung-RADS (lung screening) assessment categories and the recommended action.
  • You need to track incidental findings and the follow-up interval/modality the report recommends.
  • You are mapping findings toward RadLex terms or a DICOM-SR structured report.

Quick start

import openmed

report = (
    "TECHNIQUE: CT chest without contrast.\n"
    "COMPARISON: CT 2023-11-02.\n"
    "FINDINGS: A 8 mm solid nodule is noted in the right upper lobe, "
    "unchanged. No pleural effusion.\n"
    "IMPRESSION: 8 mm right upper lobe nodule, stable. Lung-RADS 2. "
    "Recommend annual low-dose CT screening."
)

# 1) De-identify the report on-device first (synthetic example shown).
deid = openmed.deidentify(report, policy="hipaa_safe_harbor")
text = deid.deidentified_text

# 2) Run NER for anatomy / finding / measurement spans.
ents = openmed.analyze_text(
    text,
    model_name="anatomy_detection_superclinical",   # Anatomy category
    output_format="dict",
)["entities"]

# 3) Split sections by header, then attach entities + measurements per finding.
import re
SECTION = re.compile(r"(?im)^(TECHNIQUE|COMPARISON|FINDINGS|IMPRESSION)\s*:")
sections, last, name = {}, 0, None
for m in SECTION.finditer(text):
    if name: sections[name] = text[last:m.start()].strip()
    name, last = m.group(1).upper(), m.end()
if name: sections[name] = text[last:].strip()

structured = {
    "technique": sections.get("TECHNIQUE"),
    "comparison": sections.get("COMPARISON"),
    "findings": _split_findings(sections.get("FINDINGS", "")),   # one per sentence
    "impression": sections.get("IMPRESSION"),
    "measurements": re.findall(r"\b\d+(?:\.\d+)?\s?(?:mm|cm)\b", text),
    "laterality": sorted({w for w in ("right", "left", "bilateral")
                          if re.search(rf"\b{w}\b", text, re.I)}),
    "assessment": (re.search(r"\b(?:BI-RADS|Lung-RADS)\s*\d[A-C]?\b", text, re.I)
                   or [None])[0] if re.search(r"RADS", text, re.I) else None,
    "follow_up": _extract_followup(sections.get("IMPRESSION", "")),
}

_split_findings / _extract_followup are your sentence splitter and a recommendation matcher ("recommend …", "follow-up in N months"); keep each finding tied to its source sentence offsets.

Workflow

  1. De-identify first. openmed.deidentify(report, policy=...); structure from deidentified_text. Patient name, MRN, accession, and dates go before anything is stored or shared.
  2. Split sections by the standard headers (TECHNIQUE, COMPARISON, FINDINGS, IMPRESSION; also HISTORY/INDICATION). Reports vary — fall back to position if headers are missing.
  3. Run analyze_text for anatomy and finding entities; capture measurements ("8 mm", "1.2 cm") and laterality ("right", "left", "bilateral") near each finding.
  4. Build one structured finding per observation: {anatomy, finding, laterality, measurement, change_vs_prior, source_offsets}. "Unchanged", "stable", "increased", "new" capture temporal change against the comparison.
  5. Pull the assessment category (BI-RADS 0-6, Lung-RADS 1-4X) from the impression and the recommended follow-up (modality + interval).
  6. Flag incidental findings — findings unrelated to the exam indication — and route them to a follow-up tracker so they aren't lost.
  7. Map toward RadLex / DICOM-SR if you need coded interoperability, and surface the whole structure to a radiologist for verification.

Hand-off to / from OpenMed

OpenMed's analyze_text returns a dict; result["entities"] items carry text, label, confidence, start, end.

  • From extracting-clinical-entities: Anatomy and Disease/finding entities populate each structured finding; keep offsets so every field traces to a source sentence.
  • From extracting-lab-tables / OCR: if the report is a scan, OCR it first (openmed.multimodal.ocr.ocr), then run NER on the recognized text.
  • From segmenting-clinical-sections: reuse section detection if your reports don't use canonical headers.
  • To building-patient-timelines: dated findings + change-vs-prior feed a longitudinal view (e.g. nodule size over time).
  • To extracting-dicom-metadata: pair the structured findings with the study's DICOM metadata when assembling a DICOM-SR object.
  • De-identify with deidentifying-clinical-text (openmed.deidentify) before any export. Everything runs on-device.

Edge cases & gotchas

  • Negation and uncertainty change meaning. "No pleural effusion" and "cannot exclude metastasis" are findings about absence/uncertainty — don't record them as positive findings. Use resolving-clinical-context (openmed.clinical) for negation/hedging before asserting a finding.
  • Laterality errors are clinically dangerous. "Right" vs "left" must bind to the correct finding; a misattributed side can drive wrong-site decisions. Tie laterality to the nearest anatomy span by offset, not document-wide.
  • Measurements need their unit and axis. "8 mm" vs "0.8 cm" are equal; a bare "8" is ambiguous. Capture the unit; for masses, capture all reported dimensions ("2.1 x 1.4 cm"), not just the first.
  • Assessment categories have controlled value sets. BI-RADS 0-6 and Lung-RADS 1, 2, 3, 4A, 4B, 4X each map to a defined management action — don't invent or round categories; pull the literal value from the impression.
  • Incidental findings get lost. A renal cyst mentioned in a chest CT is the classic missed follow-up. Explicitly separate incidental from indication-related findings and push incidentals to a tracker.
  • The impression is the actionable summary, but findings may contain detail the impression omits — structure both, and prefer the impression for follow-up/assessment.
  • Decision-support disclaimer. This is not a diagnostic medical device; it organizes text a radiologist authored. Every structured field must be reviewable against its source. Do not auto-act on a derived category or follow-up without clinician sign-off.

Standards & references

版本历史

  • f213557 当前 2026-07-23 00:46

同 Skill 集合

skills/benchmark-pii-recall/SKILL.md
skills/building-with-openmed/SKILL.md
skills/deidentify-a-dataset/SKILL.md
skills/extract-clinical-entities-to-fhir/SKILL.md
skills/loading-openmed-models/SKILL.md
skills/pick-a-pii-model/SKILL.md
skills/annotating-variants/SKILL.md
skills/assembling-fhir-bundles/SKILL.md
skills/auditing-deid-leakage/SKILL.md
skills/auditing-deidentification-runs/SKILL.md
skills/auditing-part11-trails/SKILL.md
skills/auditing-safe-harbor-checklist/SKILL.md
skills/auditing-subgroup-fairness/SKILL.md
skills/authoring-model-cards/SKILL.md
skills/batch-processing-clinical-text/SKILL.md
skills/benchmarking-clinical-ner/SKILL.md
skills/bridging-presidio-and-spacy/SKILL.md
skills/building-gold-corpus/SKILL.md
skills/building-patient-timelines/SKILL.md
skills/checking-hipaa-compliance/SKILL.md
skills/choosing-openmed-models/SKILL.md
skills/coding-hcc-risk-adjustment/SKILL.md
skills/coding-icd10/SKILL.md
skills/computing-ecqms/SKILL.md
skills/configuring-privacy-policies/SKILL.md
skills/defining-cohort-phenotypes/SKILL.md
skills/deidentifying-clinical-text/SKILL.md
skills/deidentifying-multilingual-text/SKILL.md
skills/deploying-openmed-mcp/SKILL.md
skills/detecting-pv-signals/SKILL.md
skills/enforcing-nophi-logging/SKILL.md
skills/etl-to-omop-cdm/SKILL.md
skills/evaluating-with-leakage-gates/SKILL.md
skills/exporting-bulk-fhir/SKILL.md
skills/exporting-to-fhir/SKILL.md
skills/extracting-clinical-entities/SKILL.md
skills/extracting-dicom-metadata/SKILL.md
skills/extracting-lab-tables/SKILL.md
skills/extracting-pii-entities/SKILL.md
skills/extracting-sdoh/SKILL.md
skills/fetching-fhir-resources/SKILL.md
skills/gating-deid-leakage/SKILL.md
skills/generating-synthea-data/SKILL.md
skills/generating-synthetic-surrogates/SKILL.md
skills/ingesting-clinical-documents/SKILL.md
skills/linking-umls-concepts/SKILL.md
skills/mapping-loinc/SKILL.md
skills/mapping-to-snomed/SKILL.md
skills/mining-pubmed-literature/SKILL.md
skills/normalizing-rxnorm/SKILL.md

元信息

文件数
0
版本
de90aba
Hash
8d3f7ce6
收录时间
2026-07-23 00:46

首页 - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-04 19:54
浙ICP备14020137号-1 $访客地图$