RP-360/Qwen3.5-4B-mdr-narrative-grpo-codes-weighted represents the reinforcement learning alignment stage of the Medical Device Report (MDR) Narrative Intelligence system. Trained directly on top of RP-360/Qwen3.5-4B-mdr-narrative-sft-codes-weighted, this policy model optimizes structured clinical information extraction through 300 steps of Group Relative Policy Optimization (GRPO) (2,400 rollouts, group size G = 8) guided by a 7-Dimensional Programmatic Reward Suite.
🚀 Combined Macro F1: Achieves 0.5608 (+157.6% relative gain over baseline 0.2177), outperforming the pre-registered GRPO ROI hurdle rate of 0.3383 by +65.8%.
🛡️ Verbatim Evidence Grounding: 99.56% citation precision (448/450 quotes verbatim verified against source narratives; 0.44% hallucination rate), guarded by hard invariant penalties.
📋 98.5% Strict Schema Pass Rate: 197/200 reports achieve flawless syntactic compliance with mni-json-v2-codes with zero missing keys.
⚡ High Inference Throughput: Generates all 200 reports in 497.4s (8m 17s) (~0.402 reports/sec), running 19.5% faster than SFT Codes-Weighted and 55.9% faster than SFT Full JSON.
📈 Optimal Policy Reward Convergence: Average composite reward of +0.6344 across held-out reports (98.0% positive reward steps, 37.0% high quality ≥ +0.70).
Evaluation was performed on a standalone benchmark of 200 held-out medical adverse event reports from RP-360/mdr-narrative-consolidated-pre-20k. A strict data partition audit verified 0 overlap with the training corpus (zero data leakage).
Executive Evaluation Scoreboard
Table with columns: Evaluation Dimension, Constant Baseline, GRPO Hurdle Target, Qwen3.5-4B GRPO Policy, Absolute Delta, Relative Gain, Clinical Status
Evaluation Dimension
Constant Baseline
GRPO Hurdle Target
Qwen3.5-4B GRPO Policy
Absolute Delta
Relative Gain
Clinical Status
Annex A Macro F1(Device Problems)
0.1753
—
0.4538
+0.2785
+158.8%
🟢 Outperforms Baseline
Annex E Macro F1(Patient Harms)
0.2600
—
0.6678
+0.4078
+156.9%
🟢 Reaches Head Data Ceiling
Combined Macro F1(Overall IMDRF)
0.2177
0.3383
0.5608
+0.3431
+157.6%
🎯 Beats Hurdle (+65.8%)
Schema Pass Rate
0.0%
95.0%
98.5% (197/200)
—
—
🟢 Strict JSON Compliance
Verbatim Quote Grounding
0.0%
90.0%
99.56% (448/450)
—
—
🛡️ 0.44% Hallucination Rate
Categorical: event_type
53.5%
—
90.0% (180/200)
+36.5%
—
🟢 High-Confidence Class.
Categorical: harm_bucket
76.0%
—
90.5% (181/200)
+14.5%
—
🟢 High Sensitivity to Harm
Categorical: DEVICE_EXAMINED
61.5%
—
72.0% (144/200)
+10.5%
—
🟢 Consistent Adjudication
Mean Composite Policy Reward
0.0000
> +0.3000
+0.6344
+0.6344
—
🚀 Optimal Policy Convergence
Categorical Field Confusion Analysis
The model predicts three critical categorical metadata attributes: DEVICE_EXAMINED (whether the manufacturer physical lab inspected the device), event_type (Malfunction vs Injury vs Death), and harm_bucket (harm vs no_harm).
Harm Bucket Sensitivity: Identifies true patient harm with 90.5% accuracy, minimizing false negatives in critical risk scenarios.
Adverse Event Type: 90.0% overall accuracy, accurately separating mechanical device malfunctions from direct clinical injuries.
Device Examination Adjudication: Reaches 72.0% accuracy (an 10.5% absolute gain over the majority baseline), distinguishing between records reviews and genuine physical laboratory teardowns.
Each predicted IMDRF code requires supporting narrative evidence formatted as {"code": "...", "quote": "..."}. During evaluation, all emitted quotes were tested for exact substring presence in the source reporter and manufacturer narratives:
Table with columns: Evidence Grounding Dimension, Metric Value, Benchmark Standard, Status
The table below compares the empirical baseline, both Supervised Fine-Tuning (SFT) generations, and the final GRPO reinforcement learning policy across all 200 held-out validation reports:
Table with columns: Evaluation Dimension, Constant / Majority Baseline, Gen 1 SFT Model: Full JSON (-sft-json), Gen 2 SFT Model: Codes-Weighted (-sft-codes-weighted), Gen 3 GRPO RL Policy (-grpo-codes-weighted), Empirical Ceiling / Target, Advantage & RL Impact
Evaluation Dimension
Constant / Majority Baseline
Gen 1 SFT Model: Full JSON (-sft-json)
Gen 2 SFT Model: Codes-Weighted (-sft-codes-weighted)
Gen 3 GRPO RL Policy (-grpo-codes-weighted)
Empirical Ceiling / Target
Advantage & RL Impact
Schema Syntax Version
—
mni-json-v1 (embedded defs)
mni-json-v2-codes (codes only)
mni-json-v2-codes
—
Optimized token budget (~390 tokens/report)
Generation Latency (200 reports)
—
1,127s (18m 46s)
618s (10m 18s)
497s (8m 17s)
—
⚡ 1.24x Faster vs Gen 2, 2.27x vs Gen 1
Throughput (reports/sec)
—
0.177
0.324
0.402
—
⚡ +24.1% higher generation throughput
Schema Pass Rate
0.0%
99.0% (198/200)
99.0% (198/200)
98.5% (197/200)
100.0%
🟢 Flawless syntactic reliability
Annex A Macro F1(Device Problems)
0.1753
0.4180 (69.2% ceiling)
0.4360 (72.2% ceiling)
0.4538 (76.3% ceiling)
0.5947
🟢 Highest Annex A F1 across all models
Annex E Macro F1(Patient Harms)
0.2600
0.6360 (95.2% ceiling)
0.6250 (93.6% ceiling)
0.6678 (100.0% ceiling)
0.6678
🟢 Reaches Empirical Head Ceiling
Combined Macro F1(Clinical Overall)
0.2177
0.5270
0.5305
0.5608
—
🎯 Beats GRPO Hurdle (0.3383) by +65.8%
Average Composite Policy Reward
0.0000
N/A (unaligned)
-0.4370 (initial rollout)
+0.6344 (Peak: +0.9941)
+1.0000
🚀 Monotonic RL trajectory convergence
Taxonomy Terms + Defs Fidelity
0.0%
88.7% (param memory)
99.6% (hydration)
99.6% (hydration)
100.0%
🟢 Zero Definition Hallucination
Evidence Quotes Grounding Precision
0.0%
99.3% (398/401 verbatim)
99.3% (445/448 verbatim)
99.56% (448/450 verbatim)
100.0%
🛡️ Guarded by hard -0.20 INV8 penalty
Adverse Event Type Accuracy
53.5%
90.5%
89.0%
90.0%
100.0%
🟢 +36.5% over majority class
Harm Severity Bucket Accuracy
76.0%
89.5%
90.0%
90.5%
100.0%
🟢 +14.5% over majority class
Device Examination Accuracy
61.5%
64.0%
62.5%
72.0%
100.0%
🟢 +9.5% gain over SFT (Highest)
Anti-Gaming Guardrails
None
None
None
Active (AH, INV1, INV8, INV9)
Required
🛡️ Prevents code flooding & negations
SFT Base Model Lineage & Training Loss Dynamics
The GRPO policy model is built upon a two-stage Supervised Fine-Tuning (SFT) foundation prior to reinforcement learning:
Stage 1: Foundational SFT Training & Convergence (-sft-json)
The foundational clinical extraction model (RP-360/Qwen3.5-4B-mdr-narrative-sft-json) was trained on 9,087 reports on an NVIDIA A100-SXM4 GPU (2.54 h) with early stopping triggered at Step 1,600 / 2,835 (Epoch 2.82). Checkpoint 1100 reached the global minimum validation loss of 0.12582 across all 431 held-out validation reports:
SFT Validation Loss Trajectory & Checkpoint Selection
Trained with effective batch size 16 (sequence length 3,072) on an NVIDIA A100-SXM4 GPU with early stopping (patience 5). Evaluated every 100 steps across all 431 held-out validation reports:
Table with columns: Evaluation Step, Training Loss (Cross-Entropy), Validation Loss (431 Reports), Delta vs Prior, Status / Checkpoint
Evaluation Step
Training Loss (Cross-Entropy)
Validation Loss (431 Reports)
Delta vs Prior
Status / Checkpoint
Step 100
0.8535
0.24775
—
Initial validation evaluation
Step 200
0.7250
0.24981
+0.00206
Patience 1/5
Step 300
0.7358
0.24451
-0.00530
🟢 Improvement
Step 400
0.7329
0.24863
+0.00412
Patience 1/5
Step 500
0.7208
0.24415
-0.00448
🏆 Optimal Checkpoint (Merged as Base Weights for GRPO)
Step 600
0.6384
0.25513
+0.01098
Patience 1/5 (Validation loss plateauing)
Step 700
0.5849
0.26128
+0.00615
Patience 2/5
Step 800
0.5848
0.26515
+0.00387
Patience 3/5
Step 900
0.6587
0.26179
-0.00336
Patience 4/5
Step 1,000
0.5878
0.26232
+0.00053
⏹️ Early Stopping Triggered (Patience 5/5 reached)
checkpoint-500 achieved the lowest validation cross-entropy loss (0.24415) and was selected and merged as the starting weights for GRPO policy alignment.
Pre-GRPO Diagnostics vs. Post-GRPO Policy Realization
Before launching GRPO, the base policy RP-360/Qwen3.5-4B-mdr-narrative-sft-codes-weighted underwent multi-temperature latent exploration diagnostics (Pass@K) to establish the empirical ROI hurdle rate. The table below traces the diagnostic benchmarks to the final post-GRPO policy results:
Table with columns: Diagnostic Dimension / Check, Pre-GRPO Value, Benchmark Meaning, Post-GRPO Actual Policy, Status & Achievement
Diagnostic Dimension / Check
Pre-GRPO Value
Benchmark Meaning
Post-GRPO Actual Policy
Status & Achievement
Pass@1 (F1 ≥ 0.50)
0.135
Single-Pass Greedy Floor (SFT base)
0.5608
🟢 +0.426 jump over greedy base
Pass@8 (F1 ≥ 0.50)
0.480
Upper Bound Exploration Spread
0.5608
🚀 Surpasses Pass@8 latent ceiling (+0.081)
Exploration Variance (+Δ)
+0.345
Spread required for RL (≥ +0.18)
—
🟢 Sufficient exploratory headroom verified
Self-Consistency 8-Vote Baseline
0.3383
GRPO ROI Hurdle Rate to Beat
0.5608
🎯 Beats ROI Hurdle Rate by +65.8%
Pass@8 Exact Full-Record Match
0.280
Peak Exact Match Exploration
0.395 (Annex A) / 0.565 (Annex E)
🟢 Significant leap in exact match recall
Curated Prime RL Pool
12 (48.0%)
Goldilocks Active Learning candidates
300 steps
🟢 Optimized across hard clinical cases
Peak Single-Rollout Reward
-0.437
Cold-start baseline step 1
+0.9941
🏆 Near-flawless convergence at Step 286
The 7-Dimensional Intelligence Reward Suite
Rather than relying on opaque neural reward models that are susceptible to reward gaming, this GRPO alignment uses an authoritative, rule-based clinical verifier evaluating 7 orthogonal dimensions:
text
┌────────────────────────────────────────────────────────────────────────┐│ Composite Reward Function │├────────────────────────────────────────────────────────────────────────┤│ R = clip( ∑ (w_k · C_k) - Total_Penalties, min = -1.0, max = +1.0 )│└────────────────────────────────────────────────────────────────────────┘
To prevent the policy from exploiting reward formulation shortcuts (such as code spamming or citing non-existent sentences), 5 strict invariants are enforced during rollout scoring:
Verbatim Citation Guard (INV8): If any quote in EVIDENCE is not found verbatim in the source report, an immediate penalty of -0.20 is applied.
Negation Inversion Guard (INV9): If the policy cites a clinically negated phrase (e.g., citing "no evidence of lead fracture" to support code 1069), an immediate invariant violation penalty is triggered.
Harm / Annex E Consistency (INV1): If harm_bucket == "harm" but no Annex E code is provided, a -0.20 penalty is levied.
Anti-Hallucination Code Flooding Defense (AH): Emitting >5 Annex A codes or >4 Annex E codes to artificially inflate recall triggers an escalating penalty of -0.05 per excess code.
Parse Failure Penalty: Any syntax corruption, missing braces, or invalid JSON immediately receives a -1.00 score.
Training Dynamics & Convergence Progression
GRPO optimization demonstrated monotonic convergence across all 300 steps on an NVIDIA A100-SXM4 GPU.
KL Divergence Penalty (β = 0.02): Successfully prevented policy collapse and catastrophic forgetting. The KL divergence gently expanded from 0.0005 during initial warmup to settle stably between 0.20 and 0.26.
Zero Policy Degradation: The model preserved structural validity throughout all 300 training steps.
Hardware & Engineering Telemetry
The training and evaluation runs executed on an NVIDIA A100-SXM4-40GB:
RAW FDA MAUDE MEDICAL DEVICE ADVERSE EVENT REPORT │ ▼┌─────────────────────────────────────────────────────────────┐│ RP-360/Qwen3.5-4B-mdr-narrative-grpo-codes-weighted ││ (Qwen3.5-4B Hybrid Attention + GRPO-Aligned Policy) │└─────────────────────────────────────────────────────────────┘ │ ▼ Emits Compact Codes-Only JSON (512 max tokens){ "FAILURE_MODE": "Communication failure", "IMDRF_A": ["1332"], <-- CODES ONLY "IMDRF_E": ["2388"], <-- CODES ONLY "EVIDENCE": [{"code": "1332", "quote": "THE IPG FAILED TO..."}]} │ ▼ Post-Hoc Deterministic Hydration (`enrich_record`)┌─────────────────────────────────────────────────────────────┐│ Authoritative IMDRF Taxonomy Dictionary Lookup ││ "1332" -> "Failure to Interrogate", "Problem associated..." ││ "2388" -> "Inadequate Pain Relief", "Continuing discomfort" │└─────────────────────────────────────────────────────────────┘ │ ▼ Final Enriched Output (99.6% Taxonomy Match){ "IMDRF_A": [ { "code": "1332", "term": "Failure to Interrogate", "definition": "Problem associated with the device failure to appropriately respond to signals..." } ], "IMDRF_E": [ { "code": "2388", "term": "Inadequate Pain Relief", "definition": "Continuing discomfort due to a lack or failure of a medical approach..." } ]}
Usage & Quickstart Guide
1. Fast Inference with Unsloth
python
import torchfrom unsloth import FastLanguageModelmodel_id = "RP-360/Qwen3.5-4B-mdr-narrative-grpo-codes-weighted"model, tokenizer = FastLanguageModel.from_pretrained( model_name = model_id, max_seq_length = 2048, load_in_4bit = False,)FastLanguageModel.for_inference(model)SYSTEM_PROMPT = ( "Extract MDR information and output only valid JSON. " "For IMDRF fields, output only the codes.")narrative = """ON RECENT FOLLOW-UP, THE PATIENT EXPERIENCED SUDDEN LOSS OF STIMULATION. CHEST X-RAY REVEALED LEAD FRACTURE AT THE COSTOCLAVICULAR JUNCTION. THE PATIENT REQUIRED EMERGENCY SURGERY FOR LEAD EXTRACTION AND REPLACEMENT."""messages = [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": f"Extract MDR information from the following report:\n\n{narrative}"}]prompt_text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)inputs = tokenizer(prompt_text, return_tensors="pt").to("cuda")with torch.inference_mode(): outputs = model.generate( **inputs, max_new_tokens = 512, temperature = 0.1, # Low temperature recommended for deterministic extraction do_sample = False, )response = tokenizer.decode(outputs[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)print(response)
2. Standard Transformers with Post-Hoc Hydration
python
import jsonimport torchfrom transformers import AutoModelForCausalLM, AutoTokenizermodel_id = "RP-360/Qwen3.5-4B-mdr-narrative-grpo-codes-weighted"tokenizer = AutoTokenizer.from_pretrained(model_id)model = AutoModelForCausalLM.from_pretrained( model_id, torch_dtype = torch.bfloat16, device_map = "auto")model.eval()# Authoritative IMDRF taxonomy dictionary (subset)TAXONOMY = { "1069": ("Break", "Device separation or breakage into two or more parts."), "1332": ("Failure to Interrogate", "Problem associated with the device failure to respond to interrogation signals."), "1574": ("Failure to Deliver Stimulation", "Problem associated with the failure of the device to deliver electrical energy."), "3283": ("Wireless Communication Problem", "Problems with RF wireless technology characteristics and performance."), "2388": ("Inadequate Pain Relief", "Continuing discomfort due to a lack or failure of a medical approach to treat pain."), "1706": ("Cardiac Arrhythmia", "Any variation from the normal rate or rhythm of the heartbeat.")}def enrich_record(obj, taxonomy): """Deterministically hydrates IMDRF codes with official term and definition.""" if not obj: return obj enriched = dict(obj) enriched["IMDRF_A"] = [{"code": c, "term": taxonomy.get(c, (c, ""))[0], "definition": taxonomy.get(c, (c, ""))[1]} for c in obj.get("IMDRF_A", [])] enriched["IMDRF_E"] = [{"code": c, "term": taxonomy.get(c, (c, ""))[0], "definition": taxonomy.get(c, (c, ""))[1]} for c in obj.get("IMDRF_E", [])] enriched["EVIDENCE"] = [{"code": p["code"], "term": taxonomy.get(p["code"], (p["code"], ""))[0], "quote": p["quote"]} for p in obj.get("EVIDENCE", [])] return enriched
Limitations & Clinical Safety Disclaimer
[!WARNING]
Intended Use for Post-Market Surveillance Decision Support Only
This model is trained specifically to assist clinical engineers, regulatory affairs specialists, and health informatics teams in screening and organizing adverse event reports under FDA 21 CFR Part 803 and IMDRF guidelines. It is not a certified medical device and does not provide primary clinical diagnosis or patient treatment plans. All extracted codes and causality inferences must be reviewed by qualified post-market surveillance professionals before regulatory filing.
Citation & Model Metadata
bibtex
@misc{rp360_qwen35_mdr_grpo_2026, author = {RP-360 Clinical Intelligence Team}, title = {Qwen3.5-4B MDR Narrative Intelligence: Group Relative Policy Optimization (GRPO) for Clinical Adverse Event Extraction}, year = {2026}, publisher = {Hugging Face}, howpublished = {\url{https://huggingface.co/RP-360/Qwen3.5-4B-mdr-narrative-grpo-codes-weighted}}}
┌────────────────────────────────────────────────────────────────────────┐│ Composite Reward Function │├────────────────────────────────────────────────────────────────────────┤│ R = clip( ∑ (w_k · C_k) - Total_Penalties, min = -1.0, max = +1.0 )│└────────────────────────────────────────────────────────────────────────┘
{ "think": "Patient presented with lead migration resulting in loss of pacing capture...", "FAILURE_MODE": "Lead displacement", "MECHANISM": "Electrode dislodgement -> loss of capture", "PATIENT_HARM": "Syncope and recurrent arrhythmia", "INTERVENTION": "Surgical revision and lead replacement", "OUTCOME": "Recovered post-reoperation", "DEVICE_ROLE": "Directly responsible", "IMDRF_A": ["1332", "3283"], "IMDRF_E": ["1706", "2388"], "EVIDENCE": [ {"code": "1332", "quote": "fluoroscopy confirmed displacement of the ventricular lead"}, {"code": "1706", "quote": "patient experienced temporary syncope"} ], "MFR_INVESTIGATION": "Device returned and evaluated; confirmed insulation intact, mechanical dislodgement identified", "DEVICE_EXAMINED": true, "ADDRESSES_HARM": true, "FLAG": "none", "event_type": "Injury", "harm_bucket": "harm"}
RAW FDA MAUDE MEDICAL DEVICE ADVERSE EVENT REPORT │ ▼┌─────────────────────────────────────────────────────────────┐│ RP-360/Qwen3.5-4B-mdr-narrative-grpo-codes-weighted ││ (Qwen3.5-4B Hybrid Attention + GRPO-Aligned Policy) │└─────────────────────────────────────────────────────────────┘ │ ▼ Emits Compact Codes-Only JSON (512 max tokens){ "FAILURE_MODE": "Communication failure", "IMDRF_A": ["1332"], <-- CODES ONLY "IMDRF_E": ["2388"], <-- CODES ONLY "EVIDENCE": [{"code": "1332", "quote": "THE IPG FAILED TO..."}]} │ ▼ Post-Hoc Deterministic Hydration (`enrich_record`)┌─────────────────────────────────────────────────────────────┐│ Authoritative IMDRF Taxonomy Dictionary Lookup ││ "1332" -> "Failure to Interrogate", "Problem associated..." ││ "2388" -> "Inadequate Pain Relief", "Continuing discomfort" │└─────────────────────────────────────────────────────────────┘ │ ▼ Final Enriched Output (99.6% Taxonomy Match){ "IMDRF_A": [ { "code": "1332", "term": "Failure to Interrogate", "definition": "Problem associated with the device failure to appropriately respond to signals..." } ], "IMDRF_E": [ { "code": "2388", "term": "Inadequate Pain Relief", "definition": "Continuing discomfort due to a lack or failure of a medical approach..." } ]}
import torchfrom unsloth import FastLanguageModelmodel_id = "RP-360/Qwen3.5-4B-mdr-narrative-grpo-codes-weighted"model, tokenizer = FastLanguageModel.from_pretrained( model_name = model_id, max_seq_length = 2048, load_in_4bit = False,)FastLanguageModel.for_inference(model)SYSTEM_PROMPT = ( "Extract MDR information and output only valid JSON. " "For IMDRF fields, output only the codes.")narrative = """ON RECENT FOLLOW-UP, THE PATIENT EXPERIENCED SUDDEN LOSS OF STIMULATION. CHEST X-RAY REVEALED LEAD FRACTURE AT THE COSTOCLAVICULAR JUNCTION. THE PATIENT REQUIRED EMERGENCY SURGERY FOR LEAD EXTRACTION AND REPLACEMENT."""messages = [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": f"Extract MDR information from the following report:\n\n{narrative}"}]prompt_text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)inputs = tokenizer(prompt_text, return_tensors="pt").to("cuda")with torch.inference_mode(): outputs = model.generate( **inputs, max_new_tokens = 512, temperature = 0.1, # Low temperature recommended for deterministic extraction do_sample = False, )response = tokenizer.decode(outputs[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)print(response)
import jsonimport torchfrom transformers import AutoModelForCausalLM, AutoTokenizermodel_id = "RP-360/Qwen3.5-4B-mdr-narrative-grpo-codes-weighted"tokenizer = AutoTokenizer.from_pretrained(model_id)model = AutoModelForCausalLM.from_pretrained( model_id, torch_dtype = torch.bfloat16, device_map = "auto")model.eval()# Authoritative IMDRF taxonomy dictionary (subset)TAXONOMY = { "1069": ("Break", "Device separation or breakage into two or more parts."), "1332": ("Failure to Interrogate", "Problem associated with the device failure to respond to interrogation signals."), "1574": ("Failure to Deliver Stimulation", "Problem associated with the failure of the device to deliver electrical energy."), "3283": ("Wireless Communication Problem", "Problems with RF wireless technology characteristics and performance."), "2388": ("Inadequate Pain Relief", "Continuing discomfort due to a lack or failure of a medical approach to treat pain."), "1706": ("Cardiac Arrhythmia", "Any variation from the normal rate or rhythm of the heartbeat.")}def enrich_record(obj, taxonomy): """Deterministically hydrates IMDRF codes with official term and definition.""" if not obj: return obj enriched = dict(obj) enriched["IMDRF_A"] = [{"code": c, "term": taxonomy.get(c, (c, ""))[0], "definition": taxonomy.get(c, (c, ""))[1]} for c in obj.get("IMDRF_A", [])] enriched["IMDRF_E"] = [{"code": c, "term": taxonomy.get(c, (c, ""))[0], "definition": taxonomy.get(c, (c, ""))[1]} for c in obj.get("IMDRF_E", [])] enriched["EVIDENCE"] = [{"code": p["code"], "term": taxonomy.get(p["code"], (p["code"], ""))[0], "quote": p["quote"]} for p in obj.get("EVIDENCE", [])] return enriched
@misc{rp360_qwen35_mdr_grpo_2026, author = {RP-360 Clinical Intelligence Team}, title = {Qwen3.5-4B MDR Narrative Intelligence: Group Relative Policy Optimization (GRPO) for Clinical Adverse Event Extraction}, year = {2026}, publisher = {Hugging Face}, howpublished = {\url{https://huggingface.co/RP-360/Qwen3.5-4B-mdr-narrative-grpo-codes-weighted}}}