Views
No views yet
Task: given a medical question and its answer, extract factual triples of the form
[subject, relation, object]as a pure JSON array.
<BASE_MODEL_ID> (for example: med42-llama3-8b, Meditron3-8B, PMC_LLaMA_13B, or qwen2-med-7b)1[
2 ["Psoriasis", "is", "chronic inflammatory skin disease"],
3 ["Psoriasis", "is associated with", "systemic comorbidities"]
4]<BASE_MODEL_ID> and any placeholder names below with your actual base model and repo id (for example: JoyDaJun/MedRAGChecker-Extractor-Meditron3-8B).1from transformers import AutoTokenizer, AutoModelForCausalLM
2from peft import PeftModel
3import torch, json
4
5base_model_id = "<BASE_MODEL_ID>" # e.g. "med42-llama3-8b"
6adapter_id = "<ADAPTER_REPO_ID>" # e.g. "JoyDaJun/MedRAGChecker-Extractor-Med42-8B"
7
8tokenizer = AutoTokenizer.from_pretrained(base_model_id)
9model = AutoModelForCausalLM.from_pretrained(
10 base_model_id,
11 torch_dtype=torch.bfloat16,
12 device_map="auto",
13)
14model = PeftModel.from_pretrained(model, adapter_id)
15
16def build_prompt(question: str, answer: str) -> str:
17 system_part = (
18 "You are an information extraction assistant. "
19 "Given a medical question and its answer, extract all factual triples "
20 "as [subject, relation, object]. "
21 "Return a pure JSON array of triples, with no explanations, no extra text, "
22 "no comments. If there are no clear factual triples, return an empty JSON array []."
23 )
24 qa_part = f"Question: {question}\nAnswer: {answer}"
25 return (
26 system_part
27 + "\n\n"
28 + qa_part
29 + '\n\nTriples (JSON only, e.g. [["subj", "rel", "obj"], ...]):\n'
30 )
31
32question = "Does hypercholesterolemia increase leukotriene B4 in neutrophils?"
33answer = "Hypercholesterolemia increases 5-LO activity in neutrophils..."
34
35prompt = build_prompt(question, answer)
36inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
37
38with torch.no_grad():
39 gen_ids = model.generate(
40 **inputs,
41 max_new_tokens=256,
42 do_sample=False,
43 )
44
45text = tokenizer.decode(gen_ids[0], skip_special_tokens=True)
46
47# Optional: keep only the JSON array
48start = text.find("[")
49end = text.rfind("]") + 1
50json_str = text[start:end] if start != -1 and end != -1 else "[]"
51triples = json.loads(json_str)
52print(triples)1from transformers import AutoTokenizer, AutoModelForCausalLM
2from peft import PeftModel
3import torch, json
4
5base_model_id = "<QWEN_BASE_MODEL_ID>" # e.g. "qwen2-med-7b"
6adapter_id = "<ADAPTER_REPO_ID_QWEN>" # e.g. "JoyDaJun/MedRAGChecker-Extractor-Qwen2-med-7B"
7
8tokenizer = AutoTokenizer.from_pretrained(base_model_id)
9model = AutoModelForCausalLM.from_pretrained(
10 base_model_id,
11 torch_dtype=torch.bfloat16,
12 device_map="auto",
13)
14model = PeftModel.from_pretrained(model, adapter_id)
15
16def build_prompt(question: str, answer: str) -> str:
17 system_part = (
18 "Given a medical question and its answer, extract all factual triples "
19 "as [subject, relation, object]. "
20 "Return only a JSON array of triples."
21 )
22 qa_part = f"Question: {question}\nAnswer: {answer}"
23 return system_part + "\n\n" + qa_part + '\n\nTriples (JSON only, e.g. [["subj", "rel", "obj"], ...]):\n'
24
25question = "Does hypercholesterolemia increase leukotriene B4 in neutrophils?"
26answer = "Hypercholesterolemia increases 5-LO activity in neutrophils..."
27
28messages = [
29 {"role": "system", "content": "You are an information extraction assistant."},
30 {"role": "user", "content": build_prompt(question, answer)},
31]
32prompt = tokenizer.apply_chat_template(
33 messages,
34 tokenize=False,
35 add_generation_prompt=True,
36)
37
38inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
39
40with torch.no_grad():
41 gen_ids = model.generate(
42 **inputs,
43 max_new_tokens=256,
44 do_sample=False,
45 )
46
47text = tokenizer.decode(gen_ids[0], skip_special_tokens=True)
48start = text.find("[")
49end = text.rfind("]") + 1
50json_str = text[start:end] if start != -1 and end != -1 else "[]"
51triples = json.loads(json_str)
52print(triples)DistillExtractor/train_extractor_sft.py script in the MedRAGChecker codebase.extractor_sft.jsonl with fields:
instruction: system prompt + Question: + Answer: (from biomedical QA datasets and RAG outputs).output: pure JSON array of [subject, relation, object] triples labeled by GPT-4.1.Question: and Answer: from the instruction field using regex.Triples (JSON only, e.g. [["subj", "rel", "obj"], ...]):
header.101 with gradient accumulation 32 (effective batch size 32).2048.1e-4.r = 16, alpha = 32, dropout = 0.0.bfloat16 on GPUs with device_map="auto".1export WANDB_PROJECT=MedRAGChecker
2export WANDB_NAME=extractor_<BASE_NAME>
3
4BASE=/path/to/<BASE_MODEL_ID>
5CUDA_VISIBLE_DEVICES=0,1,2,3 \
6python DistillExtractor/train_extractor_sft.py \
7 --model_name "$BASE" \
8 --train_path ./data/extractor_sft.jsonl \
9 --output_dir ./runs/extractor_sft_<BASE_NAME> \
10 --epochs 10 \
11 --batch_size 1 \
12 --grad_accum 32 \
13 --lr 1e-4 \
14 --bf16<BASE_MODEL_ID> and <BASE_NAME> with your actual base model.(subject, relation, object).N = 200 examples for a Meditron3-8B-based extractor:| Metric | Value |
|---|---|
| strict_precision | 0.0890 |
| strict_recall | 0.0930 |
| strict_f1 | 0.0900 |
| exact_match | 0.0500 |
| soft_precision | 0.2052 |
| soft_recall | 0.2598 |
| soft_f1 | 0.2148 |
1python DistillExtractor/run_extractor_eval_soft.py \
2 --base_model <BASE_MODEL_ID> \
3 --adapter_path <ADAPTER_REPO_OR_LOCAL_PATH> \
4 --data_path ./data/extractor_sft.jsonl \
5 --output_path ./results/extractor_soft_<BASE_NAME>.json \
6 --num_examples 2001@inproceedings{ji2025medragchecker,
2 title = {MedRAGChecker: Claim-level Verification for Biomedical Retrieval-Augmented Generation},
3 author = {Ji, Yuelyu and collaborators},
4 booktitle = {Proceedings of a future venue},
5 year = {2025}
6}<BASE_MODEL_ID>.