Skip to content

Exclusion Criteria

matchminer_ai.matching.exclusion_check

Exclusion criteria check helpers.

exclusion_criteria_check

exclusion_criteria_check(matches: DataFrame, *, config: MMAIConfig | None = None, filter_excluded: bool = False, return_metadata: bool = False) -> pd.DataFrame | tuple[pd.DataFrame, dict]

Evaluate whether each candidate patient-trial pair passes exclusion criteria.

Parameters:

Name Type Description Default
matches DataFrame

DataFrame of candidate patient-trial pairs to evaluate for exclusion checks.

Expected columns

patient_id : str Patient identifier. trial_id : str Trial identifier. general_exclusion_criteria : str Trial-level exclusion criteria text. general_exclusion_criteria_evidence : str Patient-level evidence related to exclusion criteria.

required
config MMAIConfig

MMAI configuration containing exclusion checker settings. Uses default preset when omitted.

None
filter_excluded bool

If True, return only rows where exclusion_criteria_pass is True.

False
return_metadata bool

When True, also return a metadata dict containing the config snapshot and model metadata for this run.

False

Returns:

Type Description
DataFrame

Derived output table containing:

Columns

patient_id : str Patient identifier. trial_id : str Trial identifier. exclusion_score : float Model-generated confidence score associated with exclusion-check label. exclusion_criteria_pass : bool True when the patient is predicted to pass exclusion criteria for this trial; False otherwise.

tuple[DataFrame, dict]

When return_metadata is True, returns the DataFrame plus metadata.

Source code in src/matchminer_ai/matching/exclusion_check.py
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
def exclusion_criteria_check(
    matches: pd.DataFrame,
    *,
    config: MMAIConfig | None = None,
    filter_excluded: bool = False,
    return_metadata: bool = False,
) -> pd.DataFrame | tuple[pd.DataFrame, dict]:
    """
    Evaluate whether each candidate patient-trial pair passes exclusion criteria.

    Parameters
    ----------
    matches : pd.DataFrame
        DataFrame of candidate patient-trial pairs to evaluate for exclusion checks.

        Expected columns
        ----------------
        patient_id : str
            Patient identifier.
        trial_id : str
            Trial identifier.
        general_exclusion_criteria : str
            Trial-level exclusion criteria text.
        general_exclusion_criteria_evidence : str
            Patient-level evidence related to exclusion criteria.

    config : MMAIConfig, optional
        MMAI configuration containing exclusion checker settings.
        Uses default preset when omitted.
    filter_excluded : bool, default False
        If True, return only rows where ``exclusion_criteria_pass`` is True.
    return_metadata : bool, default False
        When True, also return a metadata dict containing the config snapshot
        and model metadata for this run.

    Returns
    -------
    pd.DataFrame
        Derived output table containing:

        Columns
        -------
        patient_id : str
            Patient identifier.
        trial_id : str
            Trial identifier.
        exclusion_score : float
            Model-generated confidence score associated with exclusion-check label.
        exclusion_criteria_pass : bool
            True when the patient is predicted to pass exclusion criteria for
            this trial; False otherwise.
    tuple[pd.DataFrame, dict]
        When return_metadata is True, returns the DataFrame plus metadata.
    """
    # Validate that rows contain the text + ids needed for exclusion checker prompts.
    required = [
        "patient_id",
        "trial_id",
        "general_exclusion_criteria",
        "general_exclusion_criteria_evidence",
    ]
    missing = [col for col in required if col not in matches.columns]
    if missing:
        raise ValueError(f"matches is missing required columns: {', '.join(missing)}")

    # Resolve run config and build checker prompts from the configured template.
    resolved_config = config or load_default_preset()
    checker_config = dict(resolved_config.raw.get("exclusion_criteria", {}))
    prompt_file = str(checker_config["prompt_file"]).strip()

    template = _load_exclusion_criteria_template(prompt_file)
    prompts = _build_exclusion_criteria_prompts(matches, template=template)

    # Run the backend text-classification model over all prompts.
    predictions, model_metadata = run_checker(
        prompts,
        checker_config=checker_config,
        model_metadata_cache_dir=resolved_config.model_metadata_cache_dir,
    )

    if len(predictions) != len(matches):
        raise ValueError(
            "Checker returned a different number of predictions than input rows."
        )

    # Convert model outputs into a compact, derived result table.
    output = matches[["patient_id", "trial_id"]].copy()
    output["exclusion_score"] = [
        float(prediction["score"]) for prediction in predictions
    ]
    output["exclusion_criteria_pass"] = [
        str(prediction["label"]).strip().upper() == "NEGATIVE"
        for prediction in predictions
    ]

    # Optionally keep only rows that passed exclusion criteria.
    if filter_excluded:
        keep_rows = output["exclusion_criteria_pass"]
        output = output.loc[keep_rows].copy()
    output = output.reset_index(drop=True)

    # Optionally return metadata for reproducibility/debugging.
    if return_metadata:
        metadata_payload = {
            "package": package_metadata(),
            "config_snapshot": config_snapshot(resolved_config),
            "model_metadata": {
                "exclusion_criteria_checker": model_metadata,
            },
        }
        return output, metadata_payload
    return output

matchminer_ai.matching.llm_checks

LLM-based match quality and exclusion screening helpers.

exclusion_criteria_check_with_llm

exclusion_criteria_check_with_llm(matches: DataFrame, *, config: 'MMAIConfig | None' = None, return_metadata: bool = False) -> pd.DataFrame | tuple[pd.DataFrame, dict]

Evaluate trial-level exclusion criteria with the configured LLM prompt.

Parameters:

Name Type Description Default
matches DataFrame

DataFrame of candidate patient-trial pairs to evaluate for exclusion checks.

Expected columns

patient_id : str Patient identifier. trial_id : str Trial identifier. general_exclusion_criteria : str Trial-level exclusion criteria text. general_exclusion_criteria_evidence : str Patient-level evidence related to exclusion criteria.

required
config MMAIConfig

MMAI configuration containing LLM exclusion checker settings. Uses default preset when omitted.

None
return_metadata bool

When True, also return a metadata dict containing the config snapshot and model metadata for this run.

False

Returns:

Type Description
DataFrame

Derived output table containing:

Columns

patient_id : str Patient identifier. trial_id : str Trial identifier. llm_exclusion_criteria_pass : bool | None Whether the LLM judged that the patient passes exclusion criteria, or None when parsing failed. Debug Columns


llm_exclusion_criteria_answer_text : str Text the package treated as the LLM answer and used for parsing. Included only when debug_mode is true. llm_exclusion_criteria_reasoning_text : str Optional separate reasoning trace returned by the backend or extracted by the configured reasoning parser. Included only when debug_mode is true. llm_exclusion_criteria_parse_status : str Whether the package could parse the answer text. Values are parsed, parsed_fallback, or parse_failed. Included only when debug_mode is true.

tuple[DataFrame, dict]

When return_metadata is True, returns the DataFrame plus metadata.

Source code in src/matchminer_ai/matching/llm_checks.py
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
def exclusion_criteria_check_with_llm(
    matches: pd.DataFrame,
    *,
    config: "MMAIConfig | None" = None,
    return_metadata: bool = False,
) -> pd.DataFrame | tuple[pd.DataFrame, dict]:
    """
    Evaluate trial-level exclusion criteria with the configured LLM prompt.

    Parameters
    ----------
    matches : pd.DataFrame
        DataFrame of candidate patient-trial pairs to evaluate for exclusion
        checks.

        Expected columns
        ----------------
        patient_id : str
            Patient identifier.
        trial_id : str
            Trial identifier.
        general_exclusion_criteria : str
            Trial-level exclusion criteria text.
        general_exclusion_criteria_evidence : str
            Patient-level evidence related to exclusion criteria.

    config : MMAIConfig, optional
        MMAI configuration containing LLM exclusion checker settings.
        Uses default preset when omitted.
    return_metadata : bool, default False
        When True, also return a metadata dict containing the config snapshot
        and model metadata for this run.

    Returns
    -------
    pd.DataFrame
        Derived output table containing:

        Columns
        -------
        patient_id : str
            Patient identifier.
        trial_id : str
            Trial identifier.
        llm_exclusion_criteria_pass : bool | None
            Whether the LLM judged that the patient passes exclusion criteria,
            or None when parsing failed.
        Debug Columns
        -------------
        llm_exclusion_criteria_answer_text : str
            Text the package treated as the LLM answer and used for parsing.
            Included only when debug_mode is true.
        llm_exclusion_criteria_reasoning_text : str
            Optional separate reasoning trace returned by the backend or
            extracted by the configured reasoning parser. Included only when
            debug_mode is true.
        llm_exclusion_criteria_parse_status : str
            Whether the package could parse the answer text. Values are
            ``parsed``, ``parsed_fallback``, or ``parse_failed``. Included only
            when debug_mode is true.
    tuple[pd.DataFrame, dict]
        When return_metadata is True, returns the DataFrame plus metadata.
    """
    required = [
        "patient_id",
        "trial_id",
        "general_exclusion_criteria",
        "general_exclusion_criteria_evidence",
    ]
    missing = [col for col in required if col not in matches.columns]
    if missing:
        raise ValueError(f"matches is missing required columns: {', '.join(missing)}")

    resolved_config = config or load_default_preset()
    llm_config = dict(resolved_config.llm_exclusion_criteria)
    prompt_template = _load_prompt_template(str(llm_config["prompt_file"]).strip())
    messages_list = [
        _build_messages(
            prompt_template.format(
                patient_boilerplate=str(row["general_exclusion_criteria_evidence"]),
                trial_boilerplate=str(row["general_exclusion_criteria"]),
            )
        )
        for _, row in matches.iterrows()
    ]
    responses, reasonings, model_metadata = _run_llm_check(
        matches,
        config=resolved_config,
        section_name="llm_exclusion_criteria",
        messages_list=messages_list,
    )
    parsed = [_parse_exclusion_result(response) for response in responses]

    output = matches[["patient_id", "trial_id"]].copy()
    output["llm_exclusion_criteria_pass"] = [passed for passed, _ in parsed]
    if resolved_config.debug_mode:
        output["llm_exclusion_criteria_answer_text"] = responses
        output["llm_exclusion_criteria_reasoning_text"] = reasonings
        output["llm_exclusion_criteria_parse_status"] = [
            parse_status for _, parse_status in parsed
        ]
    output = output.reset_index(drop=True)

    if return_metadata:
        metadata_payload = {
            "package": package_metadata(),
            "config_snapshot": config_snapshot(resolved_config),
            "model_metadata": {
                "llm_exclusion_criteria_checker": model_metadata,
            },
        }
        return output, metadata_payload
    return output