RKB109 commited on
Commit
9551fc8
verified
1 Parent(s): 3195a13

Publish artifacts for clinical-rag-safety-gateway-20260815

Browse files
Files changed (5) hide show
  1. README.md +61 -0
  2. evaluation.json +5 -0
  3. inference.py +80 -0
  4. model.json +239 -0
  5. project.json +52 -0
README.md ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ library_name: custom
4
+ pipeline_tag: question-answering
5
+ datasets:
6
+ - RKB109/clinical-rag-safety-gateway-20260815-dataset
7
+ tags:
8
+ - synthetic-data
9
+ - transparent-baseline
10
+ - healthcare-ai
11
+ - question-answering
12
+ - sentence-similarity
13
+ - text-classification
14
+ - summarization
15
+ metrics:
16
+ - accuracy
17
+ ---
18
+
19
+ # Clinical RAG Safety Gateway Baseline Model
20
+
21
+ ## Model Description
22
+
23
+ This repository contains a small, transparent prototype model for
24
+ **Clinical assistants need retrieval, source attribution, and explicit abstention before answers reach care teams.**
25
+
26
+ The model combines per-label token weights with IDF-weighted evidence
27
+ retrieval. It was generated for reproducible architecture demonstrations and
28
+ does not call a hosted LLM.
29
+
30
+ ## Evaluation
31
+
32
+ - Held-out synthetic examples: 4
33
+ - Accuracy: 1
34
+ - Intended metrics: retrieval_accuracy, abstention_coverage, citation_coverage
35
+
36
+ ## Intended Use
37
+
38
+ - Architecture prototyping
39
+ - CI and evaluation examples
40
+ - Local baseline comparisons
41
+ - Educational experimentation
42
+
43
+ ## Hugging Face Task Coverage
44
+
45
+ - `question-answering`
46
+ - `sentence-similarity`
47
+ - `text-classification`
48
+ - `summarization`
49
+
50
+ ## Limitations and Risks
51
+
52
+ Synthetic educational data only. The baseline must not provide diagnosis, treatment, or emergency medical advice.
53
+
54
+ The dataset is synthetic and small. Do not use this model for consequential
55
+ decisions without representative data, expert review, and production-grade
56
+ evaluation.
57
+
58
+ ## Reproducibility
59
+
60
+ The linked GitHub repository includes `train.py`, the exact dataset split,
61
+ evaluation code, and the model JSON format.
evaluation.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "test_examples": 4,
3
+ "accuracy": 1,
4
+ "synthetic_evaluation": true
5
+ }
inference.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Transparent baseline pipeline for the generated AI project."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import math
7
+ import re
8
+ from pathlib import Path
9
+
10
+
11
+ def tokenize(value: str) -> list[str]:
12
+ return re.findall(r"[a-z0-9]+", value.lower())
13
+
14
+
15
+ class Pipeline:
16
+ def __init__(self, model: dict):
17
+ self.model = model
18
+
19
+ @classmethod
20
+ def from_file(cls, path: str | Path) -> "Pipeline":
21
+ return cls(json.loads(Path(path).read_text(encoding="utf-8")))
22
+
23
+ def classify(self, text: str) -> tuple[str, float]:
24
+ tokens = tokenize(text)
25
+ scores = {
26
+ label: sum(weights.get(token, 0) for token in tokens)
27
+ for label, weights in self.model["prototypes"].items()
28
+ }
29
+ ranked = sorted(scores.items(), key=lambda item: (-item[1], item[0]))
30
+ label, best = ranked[0]
31
+ total = sum(max(score, 0) for _, score in ranked) or 1
32
+ return label, best / total
33
+
34
+ def search(self, query: str, limit: int = 3) -> list[dict]:
35
+ query_tokens = set(tokenize(query))
36
+ ranked = []
37
+ for document in self.model["documents"]:
38
+ document_tokens = set(tokenize(document["text"]))
39
+ lexical = sum(
40
+ self.model["idf"].get(token, 1.0)
41
+ for token in query_tokens & document_tokens
42
+ )
43
+ ranked.append({**document, "score": round(lexical, 6)})
44
+ return sorted(ranked, key=lambda item: (-item["score"], item["id"]))[:limit]
45
+
46
+ def graph_evidence(self, text: str) -> list[dict]:
47
+ tokens = set(tokenize(text))
48
+ matches = []
49
+ for subject, relation, target in self.model.get("graph_edges", []):
50
+ edge_tokens = set(tokenize(f"{subject} {relation} {target}"))
51
+ overlap = len(tokens & edge_tokens)
52
+ if overlap:
53
+ matches.append(
54
+ {
55
+ "subject": subject,
56
+ "relation": relation,
57
+ "target": target,
58
+ "overlap": overlap,
59
+ }
60
+ )
61
+ return sorted(matches, key=lambda item: -item["overlap"])
62
+
63
+ def run(self, text: str) -> dict:
64
+ label, confidence = self.classify(text)
65
+ evidence = self.search(text)
66
+ result = {
67
+ "prediction": label,
68
+ "confidence": round(confidence, 4),
69
+ "requires_review": confidence < self.model["confidence_threshold"],
70
+ "evidence": evidence,
71
+ }
72
+ if self.model["mode"] == "graph":
73
+ result["graph_evidence"] = self.graph_evidence(text)
74
+ if self.model["mode"] == "agent":
75
+ result["proposed_tool"] = label
76
+ result["approval_required"] = label in {
77
+ "request-approval",
78
+ "request-human-help",
79
+ }
80
+ return result
model.json ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "format": "daily-project-prototype-v1",
3
+ "project": "clinical-rag-safety",
4
+ "title": "Clinical RAG Safety Gateway",
5
+ "domain": "healthcare-ai",
6
+ "mode": "retrieval",
7
+ "labels": [
8
+ "medication-policy",
9
+ "triage-policy",
10
+ "privacy-policy"
11
+ ],
12
+ "prototypes": {
13
+ "medication-policy": {
14
+ "when": 3,
15
+ "should": 3,
16
+ "medication": 8,
17
+ "reconciliation": 6,
18
+ "be": 3,
19
+ "completed": 3,
20
+ "complete": 3,
21
+ "during": 3,
22
+ "admission": 3,
23
+ "transfer": 3,
24
+ "and": 3,
25
+ "discharge": 3,
26
+ "in": 2,
27
+ "an": 4,
28
+ "operations": 2,
29
+ "review": 6,
30
+ "for": 2,
31
+ "evaluation": 2,
32
+ "case": 2,
33
+ "what": 2,
34
+ "requires": 2,
35
+ "pharmacist": 4,
36
+ "high": 2,
37
+ "risk": 2,
38
+ "changes": 2,
39
+ "require": 2,
40
+ "before": 2,
41
+ "release": 2
42
+ },
43
+ "triage-policy": {
44
+ "when": 2,
45
+ "should": 2,
46
+ "urgent": 4,
47
+ "symptoms": 4,
48
+ "be": 2,
49
+ "escalated": 2,
50
+ "or": 2,
51
+ "life": 2,
52
+ "threatening": 2,
53
+ "require": 2,
54
+ "immediate": 2,
55
+ "escalation": 2,
56
+ "to": 4,
57
+ "qualified": 4,
58
+ "clinical": 2,
59
+ "staff": 2,
60
+ "for": 1,
61
+ "an": 2,
62
+ "evaluation": 1,
63
+ "case": 1,
64
+ "can": 2,
65
+ "the": 6,
66
+ "assistant": 4,
67
+ "diagnose": 2,
68
+ "a": 4,
69
+ "patient": 2,
70
+ "must": 2,
71
+ "abstain": 2,
72
+ "from": 2,
73
+ "diagnosis": 2,
74
+ "and": 2,
75
+ "direct": 2,
76
+ "user": 2,
77
+ "clinician": 2,
78
+ "in": 1,
79
+ "operations": 1,
80
+ "review": 1
81
+ },
82
+ "privacy-policy": {
83
+ "how": 3,
84
+ "should": 3,
85
+ "patient": 6,
86
+ "identifiers": 6,
87
+ "be": 5,
88
+ "handled": 3,
89
+ "use": 5,
90
+ "the": 3,
91
+ "minimum": 3,
92
+ "necessary": 3,
93
+ "information": 3,
94
+ "and": 5,
95
+ "never": 3,
96
+ "place": 3,
97
+ "in": 7,
98
+ "public": 3,
99
+ "logs": 3,
100
+ "an": 4,
101
+ "operations": 2,
102
+ "review": 2,
103
+ "for": 4,
104
+ "evaluation": 4,
105
+ "case": 2,
106
+ "can": 2,
107
+ "protected": 2,
108
+ "health": 2,
109
+ "data": 2,
110
+ "used": 2,
111
+ "test": 2,
112
+ "prompts": 2,
113
+ "synthetic": 2,
114
+ "or": 2,
115
+ "properly": 2,
116
+ "de": 2,
117
+ "identified": 2,
118
+ "records": 2,
119
+ "testing": 2
120
+ }
121
+ },
122
+ "idf": {
123
+ "complete": 2.252763,
124
+ "medication": 1.847298,
125
+ "reconciliation": 2.252763,
126
+ "during": 2.252763,
127
+ "admission": 2.252763,
128
+ "transfer": 2.252763,
129
+ "and": 1.336472,
130
+ "discharge": 2.252763,
131
+ "high": 2.252763,
132
+ "risk": 2.252763,
133
+ "changes": 2.252763,
134
+ "require": 1.847298,
135
+ "pharmacist": 2.252763,
136
+ "review": 2.252763,
137
+ "before": 2.252763,
138
+ "release": 2.252763,
139
+ "urgent": 2.252763,
140
+ "or": 1.847298,
141
+ "life": 2.252763,
142
+ "threatening": 2.252763,
143
+ "symptoms": 2.252763,
144
+ "immediate": 2.252763,
145
+ "escalation": 2.252763,
146
+ "to": 1.847298,
147
+ "qualified": 1.847298,
148
+ "clinical": 2.252763,
149
+ "staff": 2.252763,
150
+ "the": 1.847298,
151
+ "assistant": 2.252763,
152
+ "must": 2.252763,
153
+ "abstain": 2.252763,
154
+ "from": 2.252763,
155
+ "diagnosis": 2.252763,
156
+ "direct": 2.252763,
157
+ "user": 2.252763,
158
+ "a": 2.252763,
159
+ "clinician": 2.252763,
160
+ "use": 1.847298,
161
+ "minimum": 2.252763,
162
+ "necessary": 2.252763,
163
+ "patient": 2.252763,
164
+ "information": 2.252763,
165
+ "never": 2.252763,
166
+ "place": 2.252763,
167
+ "identifiers": 2.252763,
168
+ "in": 2.252763,
169
+ "public": 2.252763,
170
+ "logs": 2.252763,
171
+ "synthetic": 2.252763,
172
+ "properly": 2.252763,
173
+ "de": 2.252763,
174
+ "identified": 2.252763,
175
+ "records": 2.252763,
176
+ "for": 2.252763,
177
+ "testing": 2.252763,
178
+ "evaluation": 2.252763
179
+ },
180
+ "documents": [
181
+ {
182
+ "id": "med-policy-01",
183
+ "label": "medication-policy",
184
+ "text": "Complete medication reconciliation during admission, transfer, and discharge.",
185
+ "metadata": {
186
+ "synthetic": true,
187
+ "domain": "healthcare-ai"
188
+ }
189
+ },
190
+ {
191
+ "id": "med-policy-02",
192
+ "label": "medication-policy",
193
+ "text": "High-risk medication changes require pharmacist review before release.",
194
+ "metadata": {
195
+ "synthetic": true,
196
+ "domain": "healthcare-ai"
197
+ }
198
+ },
199
+ {
200
+ "id": "triage-01",
201
+ "label": "triage-policy",
202
+ "text": "Urgent or life-threatening symptoms require immediate escalation to qualified clinical staff.",
203
+ "metadata": {
204
+ "synthetic": true,
205
+ "domain": "healthcare-ai"
206
+ }
207
+ },
208
+ {
209
+ "id": "triage-02",
210
+ "label": "triage-policy",
211
+ "text": "The assistant must abstain from diagnosis and direct the user to a qualified clinician.",
212
+ "metadata": {
213
+ "synthetic": true,
214
+ "domain": "healthcare-ai"
215
+ }
216
+ },
217
+ {
218
+ "id": "privacy-01",
219
+ "label": "privacy-policy",
220
+ "text": "Use the minimum necessary patient information and never place identifiers in public logs.",
221
+ "metadata": {
222
+ "synthetic": true,
223
+ "domain": "healthcare-ai"
224
+ }
225
+ },
226
+ {
227
+ "id": "privacy-02",
228
+ "label": "privacy-policy",
229
+ "text": "Use synthetic or properly de-identified records for testing and evaluation.",
230
+ "metadata": {
231
+ "synthetic": true,
232
+ "domain": "healthcare-ai"
233
+ }
234
+ }
235
+ ],
236
+ "graph_edges": [],
237
+ "confidence_threshold": 0.18,
238
+ "trained_on_synthetic_data": true
239
+ }
project.json ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "Clinical RAG Safety Gateway",
3
+ "problem": "Clinical assistants need retrieval, source attribution, and explicit abstention before answers reach care teams.",
4
+ "domain": "healthcare-ai",
5
+ "architecture": "retrieval",
6
+ "hugging_face_tasks": [
7
+ "question-answering",
8
+ "sentence-similarity",
9
+ "text-classification",
10
+ "summarization"
11
+ ],
12
+ "recommended_stack": [
13
+ "FastAPI for typed service endpoints",
14
+ "LangGraph for durable safety and escalation workflows",
15
+ "LlamaIndex for ingestion and retrieval abstractions",
16
+ "PostgreSQL plus pgvector for filtered vector search",
17
+ "Redis for caching and rate limiting",
18
+ "OpenTelemetry plus Phoenix for traces and evaluation"
19
+ ],
20
+ "real_world_data_sources": [
21
+ {
22
+ "name": "ClinicalTrials.gov API v2",
23
+ "url": "https://clinicaltrials.gov/api/v2/studies?pageSize=5",
24
+ "purpose": "Public study metadata for retrieval and citation tests"
25
+ },
26
+ {
27
+ "name": "openFDA drug labels",
28
+ "url": "https://api.fda.gov/drug/label.json?limit=5",
29
+ "purpose": "Public drug-label text for safety-oriented ingestion"
30
+ }
31
+ ],
32
+ "job_description_skills": [
33
+ "Production RAG design and retrieval evaluation",
34
+ "Healthcare AI safety, abstention, and auditability",
35
+ "Vector databases and metadata-aware retrieval",
36
+ "Agent orchestration with human review",
37
+ "LLMOps tracing, regression tests, and release gates"
38
+ ],
39
+ "impact_targets": [
40
+ "Reach Recall@5 >= 0.85 on a reviewed retrieval set",
41
+ "Maintain 100% citation coverage for non-abstained answers",
42
+ "Block 100% of diagnosis or emergency-advice test prompts",
43
+ "Keep p95 retrieval latency below 300 ms at 50 requests/second"
44
+ ],
45
+ "baseline_evaluation": {
46
+ "test_examples": 4,
47
+ "accuracy": 1,
48
+ "synthetic_evaluation": true
49
+ },
50
+ "estimated_delivery": "8-12 weeks for one engineer",
51
+ "generated_baseline_is_production_ready": false
52
+ }