4. 核查规则的形式化表达
临床数据核查的起点往往是一句自然语言,例如“受试者必须有知情同意日期”“访视日期不能早于知情同意日期”“若出现严重不良事件,必须记录其转归”。这些句子对临床人员清晰,但对程序不可执行。形式化表达的任务,就是把临床逻辑翻译成机器可判定、可复用、可追溯的规则对象。它包含三层工作:把语义拆成可判定的条件与结论,把规则归入合适的类别,并为每条规则建立元数据,使其能被规则引擎加载、被版本管理、被审计追踪。
从临床逻辑到可执行规则
一条可执行规则通常由四部分组成:作用域(对哪些受试者、哪些访视、哪些表单生效)、触发条件(在什么数据状态下评估)、判定表达式(布尔表达式或集合运算)、结果动作(产生何种质疑、严重级别、提示文本)。以“访视日期不能早于知情同意日期”为例,形式化后为:
rule_id: R-TIME-001
scope: subject.all_visits
trigger: visit_date IS NOT NULL AND icf_date IS NOT NULL
expression: visit_date >= icf_date
violation: "访视日期({visit_date})早于知情同意日期({icf_date})"
severity: HIGH
action: raise_query(field=visit_date, type=DATE_ORDER)
这里的关键不是语法,而是把“不能早于”精确映射为“大于等于”。临床语言中的“不能”“必须”“应当”需要统一映射为可判定的比较、存在量词或逻辑组合。例如“必须有知情同意日期”映射为 icf_date IS NOT NULL;“若发生 SAE 则必须有转归”映射为 IF sae_occurred = 'Y' THEN sae_outcome IS NOT NULL。映射过程中最容易出错的是边界与空值:日期相等是否允许、缺失值是否参与比较、多选字段如何判定“包含”。这些必须在规则定义阶段明确,而不是留给引擎默认行为。
规则分类:四类核查逻辑
按核查目的,规则可分为完整性、一致性、逻辑性和时序性四类。它们关注的错误类型不同,触发时机和严重级别也往往不同。
| 类别 | 核查目标 | 典型表达式 | 示例 |
|---|---|---|---|
| 完整性 | 必填项是否缺失 | field IS NOT NULL | 知情同意日期为空 |
| 一致性 | 同一信息在不同位置是否一致 | A = B 或 A ∈ set(B) | AE 表单中的受试者编号与筛选表一致 |
| 逻辑性 | 字段间语义是否矛盾 | IF P THEN Q | 性别为男但记录了妊娠 |
| 时序性 | 事件先后顺序是否合理 | date1 <= date2 | 访视日期早于知情同意日期 |
四类规则并非互斥。一条规则可能同时具备逻辑性和时序性,例如“若受试者已退出,则退出日期必须晚于末次访视日期”。分类的价值在于组织规则库、分配严重级别和确定执行顺序。通常完整性规则最先执行,因为缺失值会干扰后续比较;时序性规则依赖日期字段,应放在日期完整性检查之后。
规则元数据建模
规则元数据是规则可管理、可追溯的基础。没有元数据的规则只是一段代码,无法回答“这条规则为什么存在”“谁在什么时候改过”“它对应哪个方案版本”。一个实用的规则元数据模型至少应包含以下字段:
- rule_id:全局唯一标识,建议采用“类别缩写-模块-序号”,如 R-TIME-001。
- rule_name:人类可读名称,用于报告和沟通。
- category:完整性、一致性、逻辑性、时序性之一。
- scope:作用域,指定表单、访视、受试者子集。
- trigger:触发条件,决定规则何时被评估。
- expression:判定表达式,规则的核心逻辑。
- severity:严重级别,如 HIGH、MEDIUM、LOW。
- message_template:质疑文本模板,支持字段占位符。
- source:规则来源,如方案章节、CRF 注释、数据管理计划。
- version:版本号,配合生效日期实现版本管理。
- status:草稿、启用、停用、废弃。
元数据建模的难点在于版本与生效范围。同一条规则在方案 V1.0 和 V2.0 中可能不同,因此规则必须绑定方案版本和生效日期。规则引擎在评估时,应根据当前受试者所属的方案版本加载对应规则集,而不是加载最新规则。这样才能保证历史数据的核查结果可复现。
规则表达的整体结构
下面用一张结构图展示从临床逻辑到可执行规则、再到规则分类与元数据挂载的整体关系。图中左侧是临床语义输入,中间是形式化转换,右侧是规则对象及其元数据字段,底部是四类规则的执行顺序。
在实际工程中,规则元数据通常以结构化文件(如 JSON 或 YAML)存储,由规则引擎加载。下面是一条时序性规则的元数据示例,展示了字段如何组织:
{
"rule_id": "R-TIME-001",
"rule_name": "访视日期不早于知情同意日期",
"category": "时序性",
"scope": { "form": "VISIT", "field": "visit_date" },
"trigger": "visit_date != null && icf_date != null",
"expression": "visit_date >= icf_date",
"severity": "HIGH",
"message_template": "访视日期({visit_date})早于知情同意日期({icf_date})",
"source": "方案 V2.0 第 6.3 节",
"version": "1.2",
"status": "启用"
}
当规则以这种形式存在时,数据管理员可以在不修改代码的情况下新增、停用或调整规则;稽查人员可以按 rule_id 追溯每条质疑的来源;统计人员可以确认核查逻辑与方案版本一致。形式化表达、分类和元数据建模三者结合,才使临床数据核查从人工经验走向可执行、可审计的自动化工程。