AI-Powered Clinical Research Assistant for Patient–Clinical Trial Matching and Post-Treatment Outcome Analysis
Build an AI-powered clinical research assistant with two connected phases:
The researcher provides a clinical trial file, specifically:
NCT05502562
The system must extract the trial's:
- Disease/condition
- Intervention/drug
- Inclusion criteria
- Exclusion criteria
- Age requirements
- Sex requirements
- Laboratory requirements
- Medical-history requirements
- Medication restrictions
- Primary outcomes
- Secondary outcomes
- Trial time frames
- Recruitment/status information where available
The system then analyzes:
synthetic_type2_diabetes_trial_volunteers_200.csv
and identifies the best-matching synthetic patient(s) for the selected trial.
The matching system must combine:
- Structured rule matching
- Eligibility criteria extraction
- Clinical terminology normalization
- Production RAG
- Semantic retrieval
- BM25
- Turovec
- Dense embeddings
- Cross-encoder reranking
- Deterministic eligibility validation
- Match scoring
- Missing-data detection
- Evidence traceability The result must be:
Potentially Eligible
+
Match Score
+
Passed Criteria
+
Failed Criteria
+
Unknown Criteria
+
Manual Review Items
+
Evidence
After Phase 1 identifies the best patient–trial match, the selected patient's clinical information is analyzed using:
diabetic_data.csv
as the historical diabetes/drug-use dataset for ML development, where appropriate.
The Phase 2 engine should analyze:
- Baseline clinical characteristics
- Drug/intervention information available in the dataset
- Laboratory measurements
- Clinical outcomes
- Follow-up information where available
- Patient risk factors
- Treatment-related variables
- Outcome labels
- Trial-defined endpoints
- Safety/adverse-event information where available
- Historical evidence
- ML predictions
- Model explanations
The final output must be an evidence-grounded clinical research analysis, not an autonomous medical decision.
The three datasets have different purposes.
| File | Purpose |
|---|---|
NCT05502562 |
Researcher-provided clinical trial/protocol data |
synthetic_type2_diabetes_trial_volunteers_200.csv |
Synthetic patient population for Phase 1 patient–trial matching |
diabetic_data.csv |
Historical diabetes/drug-use data for Phase 2 ML/clinical outcome analysis |
The system must never falsely claim that diabetic_data.csv contains validated efficacy results for the exact intervention in NCT05502562 unless the dataset actually contains that intervention and appropriate outcome labels.
If the dataset does not contain drug-specific treatment-response labels, the system must clearly report:
Drug-specific outcome prediction is not validated from the available dataset.
The ML model provides an analytical estimate based on the available historical population.
Likewise, the synthetic patient dataset must be labelled:
SYNTHETIC DATA — FOR RESEARCH PROTOTYPE ONLY
RESEARCHER
|
v
Upload Trial File
NCT05502562
|
v
Trial Document Parser
|
v
Eligibility Extraction
|
v
Structured Criteria
|
v
synthetic_type2_diabetes_trial_volunteers_200.csv
|
v
Patient Normalization
|
v
Production RAG
|
+-----------+-----------+
| | |
BM25 Dense Reranker
| | |
+-----------+-----------+
|
v
Eligibility Rule Engine
|
v
Match Scoring
|
v
BEST PATIENT MATCH
|
v
PHASE 2
|
v
diabetic_data.csv
|
v
ML Training/Data
Preparation
|
v
Logistic Regression
Random Forest
XGBoost
LGBM or TABFM
|
v
Best ML Model
|
v
SHAP
|
v
Outcome Prediction
|
v
Clinical Evidence RAG
|
v
Research LLM
|
v
Final Research Report
The researcher uploads:
NCT05502562
The application should support:
JSON
CSV
TXT
PDF
DOCX
depending on the actual file format provided.
Pipeline:
NCT05502562
|
v
Document Parser
|
v
Text + Tables
|
v
Section Detection
|
v
Eligibility Section
Outcome Section
Intervention Section
Study Design Section
|
v
LLM Structured Extraction
|
v
Pydantic Validation
|
v
Structured Trial JSON
Convert the trial into:
{
"trial_id": "NCT05502562",
"condition": "Type 2 Diabetes",
"intervention": {
"name": "REPLACE_WITH_ACTUAL_INTERVENTION_FROM_TRIAL_FILE",
"type": "drug"
},
"eligibility": {
"inclusion": [],
"exclusion": []
},
"outcomes": {
"primary": [],
"secondary": []
},
"study_design": {},
"timeframes": []
}The actual drug must be extracted from the researcher-provided trial file. Never hard-code a drug name if it is not present in the file.
Use an LLM with structured output.
Recommended architecture:
LLM
+
Pydantic
+
JSON Schema
The LLM converts natural language into structured eligibility rules.
Example:
{
"criterion_id": "INC-001",
"type": "inclusion",
"field": "age",
"operator": "greater_than_or_equal",
"value": 18,
"unit": "years",
"source_text": "...",
"source_section": "Eligibility Criteria"
}Example laboratory rule:
{
"criterion_id": "INC-002",
"type": "inclusion",
"field": "hba1c",
"operator": "between",
"min": 7.0,
"max": 10.0,
"unit": "%",
"source_text": "...",
"source_section": "Eligibility Criteria"
}Patient and trial terminology may differ.
Example:
Trial:
Type 2 Diabetes Mellitus
Patient:
T2DM
Normalized:
Type 2 Diabetes Mellitus
Recommended approach:
Rule-based normalization
+
Medical terminology dictionary
+
LLM normalization
+
Optional biomedical NLP model
Possible biomedical NLP models/tools:
- scispaCy
- SapBERT
- ClinicalBERT/BioClinicalBERT
- UMLS terminology mapping where licensing/access is appropriate
The system must preserve the original term and normalized term.
Input file:
synthetic_type2_diabetes_trial_volunteers_200.csv
Expected columns may include:
patient_id
age
sex
diabetes_type
diagnosis_confirmed
hba1c
fasting_glucose_mg_dl
weight_kg
bmi
systolic_bp
diastolic_bp
diabetes_duration_years
current_medications
hypertension
cardiovascular_disease
kidney_disease
retinopathy
pregnancy
allergies
creatinine_mg_dl
egfr_ml_min_1_73m2
alt_u_l
ast_u_l
The implementation must inspect the actual CSV schema and map available columns instead of assuming every column exists.
Use:
Pandas
+
NumPy
+
Pydantic
Steps:
CSV
|
v
Schema Detection
|
v
Missing Value Analysis
|
v
Type Conversion
|
v
Unit Normalization
|
v
Categorical Normalization
|
v
Clinical Terminology Normalization
|
v
Validated Patient Records
Never automatically treat missing clinical information as eligibility.
Example:
Trial requirement:
eGFR >= threshold
Patient:
eGFR = NULL
Output:
UNKNOWN
not:
PASS
Possible patient status:
COMPLETE
INCOMPLETE
CONFLICTING
REQUIRES_REVIEW
Reuse the existing Production RAG with PageIndex architecture.
Recommended components:
Document
|
v
Page/Section Indexing
|
+--> BM25
|
+--> Dense Embedding Search
|
v
Hybrid Retrieval
|
v
Cross-Encoder Reranking
|
v
Top Evidence
Recommended models:
BAAI/bge-small-en-v1.5
For a biomedical-focused version, benchmark a biomedical embedding model as an alternative.
BM25
cross-encoder/ms-marco-MiniLM-L-6-v2
Recommended:
PostgreSQL + pgvector
or an existing compatible vector database.
RAG should answer:
What does the trial criterion say?
Where is the criterion located?
What is the trial-defined endpoint?
What evidence supports this criterion?
What does the trial document state?
RAG should NOT independently decide:
Patient is eligible.
The deterministic rule engine makes that decision based on the structured criterion and patient value.
Implement a rule engine in Python.
Possible outputs:
PASS
FAIL
UNKNOWN
MANUAL_REVIEW
Example:
Criterion:
Age >= 18
Patient:
52
Result:
PASS
Example:
Criterion:
Pregnancy = exclusion
Patient:
Pregnancy = Yes
Result:
FAIL
Example:
Criterion:
eGFR >= X
Patient:
Missing
Result:
UNKNOWN
A mandatory exclusion failure should result in:
NOT_ELIGIBLE
A mandatory inclusion failure should result in:
NOT_ELIGIBLE
Missing required information:
POTENTIALLY_ELIGIBLE_WITH_REVIEW
All mandatory criteria pass:
POTENTIALLY_ELIGIBLE
The UI must clearly state:
Final enrollment requires researcher/clinical verification.
After hard filtering, calculate a ranking score.
Example:
Match Score =
0.60 × Eligibility Compatibility
+
0.15 × Clinical Similarity
+
0.10 × Demographic Compatibility
+
0.10 × Semantic Trial Relevance
+
0.05 × Data Completeness
The weights must be configurable.
The score means:
How well this synthetic patient matches the selected trial criteria.
It does NOT mean:
Probability of treatment success.
For ranking patients, use a combination of:
Rule-based feature matching
+
Normalized numeric distance
+
Dense embedding similarity
Optional model:
Sentence-BERT / biomedical sentence embedding
For structured patient records, a hybrid feature approach is preferred over blindly embedding the entire patient CSV row.
Example:
{
"trial_id": "NCT05502562",
"best_match": {
"patient_id": "DM-147",
"eligibility_status": "POTENTIALLY_ELIGIBLE",
"match_score": 95.4,
"passed": 12,
"failed": 0,
"unknown": 1,
"manual_review": 1
}
}Also return the top 5 or top 10 candidates.
Example:
Rank 1 — DM-147 — 95.4
Rank 2 — DM-082 — 93.8
Rank 3 — DM-191 — 91.7
Rank 4 — DM-033 — 89.4
Rank 5 — DM-112 — 87.9
For every match, display:
WHY THIS PATIENT MATCHED
Example:
Age:
52 → PASS
Type 2 Diabetes:
Yes → PASS
HbA1c:
8.4% → PASS
Kidney function:
eGFR 88 → PASS
Pregnancy:
No → PASS
Required variable:
Unknown → MANUAL REVIEW
This is more valuable than displaying only a percentage.
Phase 2 begins after Phase 1 selects the best-matching patient.
Input:
Best matched patient:
DM-147
Trial:
NCT05502562
Intervention:
Extracted from trial file
Historical dataset:
diabetic_data.csv
The primary historical dataset is:
diabetic_data.csv
Use it for:
ML training
Feature analysis
Historical outcome analysis
Medication analysis
Diabetes population modelling
The actual schema must be inspected before model training.
Do not assume that this file contains:
the exact intervention
the exact trial population
pre/post drug laboratory measurements
unless the data confirms it.
Pipeline:
diabetic_data.csv
|
v
Schema Inspection
|
v
Missingness Analysis
|
v
Duplicate Detection
|
v
Data-Type Validation
|
v
Drug/Medication Identification
|
v
Outcome Identification
|
v
Feature Engineering
Generate a data profile:
Rows
Columns
Missing %
Unique values
Numeric distributions
Medication categories
Outcome distribution
Extract the actual intervention from:
NCT05502562
Then search diabetic_data.csv for corresponding medication/intervention information.
Normalize:
Brand name
Generic name
Abbreviations
Medication categories
Use:
Rule-based mapping
+
Drug terminology dictionary
+
LLM only for ambiguous normalization
If the exact intervention is absent:
EXACT DRUG NOT PRESENT IN HISTORICAL DATA
Do not pretend another medication is equivalent.
The preferred target is:
Trial endpoint achievement
or another clearly defined clinical outcome that can be reliably derived from the historical dataset.
Example:
target = 1
if the endpoint is achieved.
target = 0
if the endpoint is not achieved.
If the historical dataset cannot produce a valid endpoint label, define an alternative validated outcome and clearly disclose that it is not the trial endpoint.
Possible features, depending on actual dataset availability:
Age
Sex
Baseline HbA1c
Baseline glucose
BMI
Weight
Blood pressure
Diabetes duration
Medication history
Kidney function
Creatinine
ALT
AST
Comorbidities
Prior utilization
Other relevant laboratory variables
Use only features available before the prediction time point.
Avoid data leakage.
The model must not use future information to predict an outcome.
Incorrect:
Predict outcome
using follow-up HbA1c
Correct:
Predict outcome
using baseline information
Example:
Baseline features
|
v
ML prediction
|
v
Follow-up
|
v
Observed outcome
Train and compare at least three models.
Purpose:
Interpretable baseline model
Use:
scikit-learn LogisticRegression
Advantages:
- Simple
- Interpretable
- Strong baseline
- Useful for calibration comparison
Purpose:
Nonlinear tree-based baseline
Use:
sklearn.ensemble.RandomForestClassifier
Advantages:
- Handles nonlinear relationships
- Robust to feature interactions
- Easy benchmark
Primary model:
XGBClassifier
Use XGBoost when the dataset and labels are appropriate.
Reasons:
- Strong tabular performance
- Nonlinear relationships
- Feature interactions
- Good performance on heterogeneous clinical data
- SHAP compatibility
If diabetic_data.csv contains an appropriate continuous outcome, train:
XGBRegressor
Example:
Predicted change in HbA1c
Only use regression when the dataset actually provides valid continuous outcome labels.
diabetic_data.csv
|
v
Clean
|
v
Feature Engineering
|
v
Train / Validation / Test Split
|
v
Preprocessing
|
+-------------------+
| |
v v
Logistic Regression Random Forest
| |
+---------+---------+
|
v
XGBoost
|
v
Model Evaluation
|
v
Select Best Model
Use a patient-level split when multiple records from the same patient exist.
For Logistic Regression:
Numerical imputation
+
StandardScaler
+
OneHotEncoder
For Random Forest/XGBoost:
Appropriate missing-value handling
+
Categorical encoding
+
Numerical validation
Use:
sklearn Pipeline
ColumnTransformer
to prevent preprocessing leakage.
If the target is imbalanced, evaluate:
Class weights
SMOTE only where scientifically appropriate
Threshold tuning
PR-AUC
Do not rely only on accuracy.
For classification:
ROC-AUC
PR-AUC
Accuracy
Precision
Recall
F1
Specificity
Sensitivity
Confusion Matrix
Brier Score
Calibration Curve
Most important:
ROC-AUC
PR-AUC
Recall
Precision
F1
Calibration
Choose the evaluation metric based on the research use case.
Use:
Stratified K-Fold
for classification when appropriate.
Example:
5-fold cross-validation
Use a separate final test set whenever the dataset size permits.
For XGBoost, tune:
n_estimators
max_depth
learning_rate
subsample
colsample_bytree
min_child_weight
reg_alpha
reg_lambda
Use:
Optuna
or:
RandomizedSearchCV
Avoid excessively complex tuning when the dataset is small.
For the selected tree-based model:
XGBoost
+
SHAP
Generate:
Global Feature Importance
Local Patient Explanation
SHAP Summary Plot
SHAP Waterfall Plot
For example:
PATIENT DM-147
Prediction:
78%
Top contributors:
Baseline HbA1c +
BMI +
Diabetes duration -
Medication history +
Age +
State clearly:
SHAP explains model behavior.
It does not establish clinical causality.
The system should additionally support a follow-up report for the selected patient.
Example:
DM-147_followup_report.pdf
The report may contain:
Patient ID
Treatment
Follow-up date
HbA1c
Fasting glucose
Weight
BMI
Blood pressure
Creatinine
eGFR
Adverse events
Serious adverse events
Physician observations
For the prototype, this can be a synthetic document labelled:
SYNTHETIC CLINICAL REPORT — FOR RESEARCH PROTOTYPE ONLY
Pipeline:
PDF/DOCX
|
v
PyMuPDF
|
v
Text + Tables
|
v
LLM Structured Extraction
|
v
Pydantic
|
v
Clinical JSON
Example:
{
"patient_id": "DM-147",
"follow_up_week": 40,
"treatment": "EXTRACTED_FROM_REPORT",
"measurements": {
"hba1c": 7.1,
"fasting_glucose_mg_dl": 135,
"weight_kg": 77,
"systolic_bp": 132,
"diastolic_bp": 84
},
"adverse_events": [
{
"event": "nausea",
"severity": "mild",
"serious": false
}
]
}Use deterministic Python calculations.
Example:
Baseline HbA1c:
8.4%
Follow-up HbA1c:
7.1%
Change:
-1.3 percentage points
Weight:
82 kg → 77 kg
Change:
-5 kg
Percentage:
-6.1%
Glucose:
172 → 135 mg/dL
Change:
-37 mg/dL
Never rely on the LLM to perform these calculations.
Extract the actual endpoint from:
NCT05502562
Represent it structurally.
Example:
{
"endpoint_id": "EP-001",
"name": "Actual endpoint from trial",
"measurement": "Actual measurement",
"timepoint": "Actual trial timepoint",
"definition": "Actual endpoint definition",
"source": "NCT05502562"
}The system must not invent endpoint thresholds.
Architecture:
Trial Endpoint
+
Patient Baseline
+
Patient Follow-Up
|
v
Deterministic Endpoint Engine
|
+--> ACHIEVED
|
+--> NOT_ACHIEVED
|
+--> UNKNOWN
Example:
Baseline:
8.4%
Follow-up:
7.1%
Observed change:
-1.3 percentage points
Trial-defined endpoint:
[Actual endpoint]
Result:
ACHIEVED / NOT_ACHIEVED / UNKNOWN
Create a separate safety engine.
Extract:
Adverse Event
Severity
Seriousness
Onset
Duration
Outcome
Action Taken
Example:
{
"event": "nausea",
"severity": "mild",
"serious": false
}Output:
Adverse events:
1
Serious:
0
Reported:
Mild nausea
Causality:
Not established
Never automatically state:
The drug caused nausea.
Correct:
Nausea was reported during the follow-up period.
Causal attribution requires clinical assessment.
Phase 2 RAG should index:
NCT05502562
Trial protocol
Trial results
Relevant published studies
Drug evidence
Safety evidence
Clinical literature
Guidelines where appropriate
Retrieval:
Research Question
|
v
BM25
+
Dense Retrieval
|
v
Hybrid Search
|
v
Cross-Encoder Reranking
|
v
Evidence
|
v
Research LLM
The LLM receives:
Patient facts
+
Baseline measurements
+
Follow-up measurements
+
Calculated changes
+
Trial endpoint
+
Endpoint result
+
ML prediction
+
SHAP explanation
+
Safety findings
+
Retrieved research evidence
The LLM generates:
Research summary
Outcome interpretation
Evidence synthesis
Safety summary
Model explanation
Limitations
Missing information
The LLM must not invent evidence.
Create controlled tools:
get_trial()
extract_trial_criteria()
get_patient()
validate_patient()
match_patient_to_trial()
get_baseline()
get_followup()
calculate_clinical_changes()
get_trial_endpoints()
evaluate_endpoint()
run_ml_prediction()
get_shap_explanation()
analyze_safety()
search_research_evidence()
generate_report()
Workflow:
Researcher:
"Analyze the best matched patient."
Agent:
|
+--> Retrieve trial
|
+--> Retrieve matched patient
|
+--> Validate eligibility
|
+--> Retrieve historical ML data
|
+--> Run selected model
|
+--> Generate SHAP
|
+--> Read follow-up report
|
+--> Calculate observed changes
|
+--> Evaluate trial endpoint
|
+--> Analyze safety
|
+--> Retrieve evidence
|
+--> Generate final report
Generate:
============================================================
AI CLINICAL RESEARCH ANALYSIS
============================================================
TRIAL
------------------------------------------------------------
NCT:
NCT05502562
Intervention:
[Extracted from trial]
PATIENT
------------------------------------------------------------
Patient ID:
DM-147
Source:
Synthetic research prototype
PHASE 1 MATCH
------------------------------------------------------------
Eligibility:
Potentially Eligible
Match Score:
95.4
Passed:
12
Failed:
0
Unknown:
1
Manual Review:
1
OBSERVED CLINICAL CHANGES
------------------------------------------------------------
HbA1c:
8.4% → 7.1%
Change:
-1.3 percentage points
Weight:
82 kg → 77 kg
Change:
-5 kg
Fasting Glucose:
172 → 135 mg/dL
Change:
-37 mg/dL
TRIAL ENDPOINT
------------------------------------------------------------
Endpoint:
[Actual NCT05502562 endpoint]
Observed value:
[Calculated value]
Result:
ACHIEVED / NOT ACHIEVED / UNKNOWN
Source:
NCT05502562
ML ANALYSIS
------------------------------------------------------------
Training Dataset:
diabetic_data.csv
Models Compared:
1. Logistic Regression
2. Random Forest
3. XGBoost
Selected Model:
[Best validated model]
Prediction:
[Prediction]
Probability:
[Probability]
Important:
This is a model output based on the available
historical training population. It is not an
autonomous clinical recommendation.
MODEL EXPLANATION
------------------------------------------------------------
SHAP Top Features:
1. [Feature]
2. [Feature]
3. [Feature]
4. [Feature]
5. [Feature]
SHAP explains model behavior and does not establish
causality.
SAFETY ANALYSIS
------------------------------------------------------------
Adverse Events:
[Events]
Serious Adverse Events:
[Events]
Causality:
Not established
EVIDENCE SYNTHESIS
------------------------------------------------------------
Trial Evidence:
[Evidence]
Research Evidence:
[Evidence]
Patient Evidence:
[Evidence]
MISSING INFORMATION
------------------------------------------------------------
[Missing information]
CONFLICTING INFORMATION
------------------------------------------------------------
[Conflicts]
FINAL RESEARCH INTERPRETATION
------------------------------------------------------------
The system identified the above patient as a
potential match to the researcher-provided trial
based on the available synthetic patient data.
The follow-up clinical record produced the observed
changes shown above.
The trial endpoint was evaluated using the actual
endpoint definition extracted from NCT05502562.
The ML component provides an additional analytical
prediction based on diabetic_data.csv and its
available outcome labels.
The retrieved research evidence provides contextual
support for the analysis.
This system does not independently establish drug
efficacy, treatment causality, or a medical decision.
Human researcher/clinical review is required.
============================================================
NCT05502562
Condition
Intervention
Study Phase
Eligibility
Primary Endpoint
Secondary Endpoints
synthetic_type2_diabetes_trial_volunteers_200.csv
Patient Ranking
#1 DM-147
Match Score: 95.4
Potentially Eligible
#2 DM-082
Match Score: 93.8
#3 DM-191
Match Score: 91.7
Clicking a patient displays:
PASS
FAIL
UNKNOWN
MANUAL REVIEW
with evidence.
Baseline
|
v
Treatment
|
v
Week 12
|
v
Week 24
|
v
Week 40
Charts:
HbA1c
Weight
Glucose
Blood Pressure
Kidney Function
Adverse Events
Dataset:
diabetic_data.csv
Model Comparison
Logistic Regression
ROC-AUC: ...
Random Forest
ROC-AUC: ...
XGBoost
ROC-AUC: ...
Selected:
XGBoost
Then:
Patient Prediction
+
Probability
+
SHAP Explanation
Display:
Patient Evidence
Trial Evidence
Research Evidence
Every generated conclusion should be traceable.
Each important output must show:
Conclusion
|
+--> Patient source
|
+--> Trial source
|
+--> Research source
|
+--> Calculation
|
+--> ML model if applicable
Example:
Endpoint ACHIEVED
Patient evidence:
DM-147_followup_report.pdf
Trial evidence:
NCT05502562
Calculation:
Baseline HbA1c - Follow-up HbA1c
Model:
Not used for endpoint calculation
This distinction is extremely important.
React.js
TypeScript
Recharts / Plotly
Python
FastAPI
Pydantic
Pandas
NumPy
PostgreSQL
pgvector
ClinicalTrials.gov Open API
PyMuPDF
LLM structured extraction
Pydantic validation
PageIndex
BM25
BGE embeddings
Cross-encoder reranker
pgvector
scispaCy
SapBERT
ClinicalBERT/BioClinicalBERT
Use biomedical NLP only when it improves terminology normalization or clinical entity recognition.
scikit-learn
XGBoost
SHAP
Optuna
Docker
Docker Compose
Pytest
Postman
clinical-research-assistant/
│
├── backend/
│ ├── app/
│ │ ├── main.py
│ │ │
│ │ ├── api/
│ │ │ ├── trial_routes.py
│ │ │ ├── patient_routes.py
│ │ │ ├── matching_routes.py
│ │ │ ├── analysis_routes.py
│ │ │ └── research_routes.py
│ │ │
│ │ ├── services/
│ │ │ ├── clinicaltrials_service.py
│ │ │ ├── trial_parser.py
│ │ │ ├── eligibility_service.py
│ │ │ ├── patient_matching_service.py
│ │ │ ├── document_service.py
│ │ │ ├── endpoint_service.py
│ │ │ ├── safety_service.py
│ │ │ ├── ml_service.py
│ │ │ ├── shap_service.py
│ │ │ ├── rag_service.py
│ │ │ └── research_agent.py
│ │ │
│ │ ├── models/
│ │ │ ├── patient.py
│ │ │ ├── trial.py
│ │ │ ├── eligibility.py
│ │ │ ├── outcome.py
│ │ │ └── report.py
│ │ │
│ │ ├── ml/
│ │ │ ├── preprocess.py
│ │ │ ├── train.py
│ │ │ ├── evaluate.py
│ │ │ ├── predict.py
│ │ │ └── explain.py
│ │ │
│ │ ├── rag/
│ │ │ ├── ingest.py
│ │ │ ├── embeddings.py
│ │ │ ├── bm25.py
│ │ │ ├── hybrid.py
│ │ │ └── reranker.py
│ │ │
│ │ └── utils/
│ │
│ └── tests/
│
├── data/
│ ├── NCT05502562
│ ├── synthetic_type2_diabetes_trial_volunteers_200.csv
│ └── diabetic_data.csv
│
├── models/
│ ├── best_model.pkl
│ ├── preprocessor.pkl
│ └── model_metadata.json
│
├── rag_index/
│
├── frontend/
│
├── docker-compose.yml
└── README.md
POST /api/trials/uploadInput:
NCT05502562
Output:
{
"trial_id": "NCT05502562",
"status": "processed"
}POST /api/matching/runInput:
{
"trial_id": "NCT05502562",
"patient_dataset": "synthetic_type2_diabetes_trial_volunteers_200.csv"
}Output:
{
"best_patient_id": "DM-147",
"match_score": 95.4,
"status": "POTENTIALLY_ELIGIBLE"
}POST /api/ml/trainInput:
{
"dataset": "diabetic_data.csv",
"target": "endpoint_outcome"
}Output:
{
"selected_model": "XGBoost",
"roc_auc": 0.84,
"f1": 0.79
}These values are examples only; the actual system must calculate them.
POST /api/ml/predictInput:
{
"patient_id": "DM-147"
}Output:
{
"model": "XGBoost",
"prediction": 1,
"probability": 0.78
}POST /api/analysis/reportInput:
DM-147_followup_report.pdf
Output:
{
"patient_id": "DM-147",
"status": "processed"
}POST /api/research/analyzeInput:
{
"trial_id": "NCT05502562",
"patient_id": "DM-147"
}Output:
{
"status": "completed",
"report_id": "REPORT-001"
} NCT05502562
|
v
Trial Understanding
|
+------+------+
| |
v v
LLM Extractor RAG
| |
+------+------+
|
v
Structured Criteria
|
v
synthetic_type2_diabetes_trial_volunteers_200.csv
|
v
Patient Matching
|
+-------------+-------------+
| | |
Rules RAG Similarity
| | |
+-------------+-------------+
|
v
Eligibility Engine
|
v
Match Ranking
|
v
BEST PATIENT
|
v
PHASE 2 ANALYSIS
|
v
diabetic_data.csv
|
+----------+----------+
| | |
v v v
Logistic Random XGBoost
Regression Forest
| | |
+----------+----------+
|
v
Model Selection
|
v
SHAP
|
v
Outcome Prediction
|
v
Follow-up Clinical Report
|
v
Document Intelligence
|
v
Baseline vs Follow-up
|
v
Endpoint Engine
|
v
Safety Analysis
|
v
Research RAG
|
v
Research LLM
|
v
FINAL RESEARCH REPORT
| Component | Model/Technology | Responsibility |
|---|---|---|
| Trial extraction | LLM | Convert trial text to structured criteria |
| Clinical terminology | scispaCy/SapBERT/LLM | Normalize medical terms |
| Dense retrieval | BGE embedding | Semantic retrieval |
| Sparse retrieval | BM25 | Keyword retrieval |
| Reranking | Cross-encoder | Rank retrieved evidence |
| Eligibility | Python rule engine | Deterministic criterion evaluation |
| Match ranking | Hybrid scoring | Rank candidate patients |
| Document extraction | LLM + Pydantic | Extract clinical facts |
| Baseline/follow-up | Python | Calculate changes |
| Endpoint | Python rule engine | Evaluate actual trial endpoint |
| ML baseline | Logistic Regression | Interpretable benchmark |
| ML model | Random Forest | Nonlinear benchmark |
| ML primary | XGBoost | Tabular outcome prediction |
| Explainability | SHAP | Explain ML behavior |
| Evidence retrieval | Production RAG | Retrieve research evidence |
| Research synthesis | LLM | Generate grounded report |
| Final decision | Human researcher | Review and interpret |
The system must never:
Prescribe a drug
Tell a patient to start treatment
Claim a drug cured the patient
Claim efficacy from one synthetic patient
Claim statistical significance from one patient
Claim causality from temporal association alone
Invent missing laboratory values
Invent trial endpoints
Invent clinical research evidence
Call a patient definitely eligible without human verification
The system should instead use:
Potentially Eligible
Observed Improvement
Endpoint Achieved
Endpoint Not Achieved
Unknown
Requires Manual Review
Model Prediction
Evidence Suggests
Causality Not Established
Use this description when presenting:
Our system is an AI-powered Clinical Research Assistant with two phases. In Phase 1, a researcher provides a clinical trial such as NCT05502562, and our system uses LLM-based eligibility extraction, Production RAG, biomedical terminology normalization, deterministic clinical rules, and hybrid patient matching to identify the best-matching patient from
synthetic_type2_diabetes_trial_volunteers_200.csv. In Phase 2, the selected patient is analyzed using historical diabetes/drug-use data fromdiabetic_data.csv, an explainable ML pipeline comparing Logistic Regression, Random Forest and XGBoost, SHAP-based model interpretation, clinical-document intelligence, deterministic endpoint analysis, safety analysis, and evidence-grounded RAG. The system then produces an auditable research report showing patient–trial compatibility, observed clinical changes, trial endpoint status, ML prediction, model explanation, safety findings, supporting evidence, and missing information for human researcher review.
Do not position the system as:
Patient → LLM → Trial
Position it as:
Trial Understanding
↓
Evidence Retrieval
↓
Structured Eligibility
↓
Deterministic Matching
↓
Best Patient
↓
Historical ML Analysis
↓
Clinical Report Intelligence
↓
Endpoint Evaluation
↓
Safety Analysis
↓
Evidence Retrieval
↓
Explainable Research Assistant
↓
Auditable Research Report
The strongest architectural principle is:
LLM
→ understands documents
RAG
→ retrieves evidence
Rule Engine
→ evaluates deterministic clinical criteria
Python
→ performs calculations
XGBoost
→ predicts from historical structured data
SHAP
→ explains the ML prediction
Research LLM
→ synthesizes the evidence
Human Researcher
→ makes the final research judgment
This separation makes the system more reliable, explainable, auditable, and suitable for a clinical-research hackathon prototype.