验证策略与生命周期:验证计划、实施、持续验证与退化验证

聊到ADMET验证,很多团队上来就写测试用例、跑脚本,结果后面一塌糊涂。我这些年带过十几个ADMET项目,有一个深刻体会——验证不是动作,是体系。从计划到实施再到持续维护,每一步走歪了,后面都得补坑。

这一章我把验证生命周期拆成四个阶段来讲,附带一些我踩过的坑。

1. 验证计划:别急着动手,先画蓝图

我习惯在项目启动后第一周,专门花两天做验证计划。不是写一堆文档应付审核,是真的把它当施工图纸来画。

1.1 计划里必须有的东西

  • 范围与目标:验证哪些ADMET环节?吸收、分布、代谢、排泄还是毒性?每个环节验证到什么深度?
  • 资源与工具:用哪个ADMET预测平台?是否搭配体外实验数据?计算节点几台?
  • 时间线与里程碑:什么时候完成基础验证?什么时候做增量验证?什么时候回归?
  • 接受标准:每个验证项的通过条件,比如预测值与实验值的误差≤多少。
验证计划模板片段(我个人项目常用,仅供参考)
Project: ADMET-001-CYP450
验证范围: CYP3A4、CYP2D6底物预测
目标指标: 灵敏度≥0.85, 特异性≥0.80, AUC≥0.90
工具: Machine Learning v3.2 + 体外数据清洗脚本V2.0
验证数据: 公开数据集(ChEMBL) + 内部测试集(N=200)
接受标准: 预测值与实验值误差在±0.5 log单位以内
时间表: 
  第1周:数据准备与清理
  第2周:基线模型验证
  第3周:交叉验证与调优
  第4周:最终确认报告

你想想看,没有接受标准,验证结果到底是过还是不过?我见过一个团队辛辛苦苦跑了两周,最后发现预测准确率才60%,可项目要求是85%。这就是计划没写清楚带来的浪费。

1.2 避坑指南:不要只堆测试用例

我曾经犯过一个错误:在计划里列了50多个测试用例,但没写清楚每个用例对应的数据来源和版本。结果测试执行时数据对不上,返工花了一周。从那以后,我要求每个用例必须附带“数据指纹”——文件名、版本号、MD5校验值。

2. 验证实施:动手做,但别忘了记录

计划落地就是实施阶段。我的做法是边做边记,别等全跑完了再补报告,因为很多细节你根本记不住。

2.1 实施流程三步走

  1. 搭建环境 — 确认计算平台、数据库、模型版本与计划一致。
  2. 运行验证脚本 — 执行预定义的测试用例,每个用例独立运行。
  3. 记录原始结果 — 截图、日志、输出文件都要带时间戳。
我的习惯:每个验证步骤都生成一个log文件,文件名格式:验证_步骤名_YYYYMMDD_HHMMSS.log。这样即使半年后回头查,也知道当时跑的是什么版本。

2.2 实施中的常见问题

问题 表现 我的处理方式
数据版本不一致 同一个模型两次验证结果差异大 在计划阶段就固定数据版本,用Git LFS管理
环境依赖冲突 脚本在不同节点运行出错 使用Docker容器封装环境,保证可复现
人为操作遗漏 忘记跑某个用例 用任务看板(Trello/Excel)逐项打勾

说白了,实施阶段最怕的就是“随意”。我见过一个同事为了省事,把20个用例合在一个脚本里跑,结果有一个失败也没发现……后面查了两天。

3. 持续验证:验证不是一锤子买卖

很多团队做完一次验证就扔那儿了,等模型升级或数据更新后又得重来。其实应该建立持续验证机制。

3.1 什么时候需要触发持续验证?

  • 模型更新:换了新算法或新参数
  • 训练数据扩充:增加了新的体外实验数据
  • 外部数据源变更:比如ChEMBL发布新版本
  • 定期回归:我建议每季度至少做一次完整回归
持续验证CI配置片段(我在GitLab CI里使用)
variables:
  MODEL_VERSION: "v3.2"
  TEST_DATA: "external_validation_set_2023Q4.csv"

stages:
  - validate

validate-model:
  stage: validate
  script:
    - python run_validation.py --model $MODEL_VERSION --data $TEST_DATA
    - python check_acceptance.py --results validation_results.json
  artifacts:
    paths:
      - validation_results.json
      - logs/
  only:
    - tags
    - schedules

注意这里我用的是GitLab CI,每次打tag或定时触发都会自动跑验证。结果自动归档到制品,谁都能看到。

3.2 持续验证的收益率

我算过一笔账:一个ADMET模型从开发到上线,如果只做一次验证,发现问题再修复,平均花两周;如果做了持续验证,每次小改动后几分钟就知道结果,整个项目周期缩短约30%。嗯,真的值。

但是要注意:持续验证不是无脑跑。我曾经在CI里把全量测试集跑一遍,一次需要40分钟,开发人员每次分支提交都等,烦得不行。后来改成只跑核心子集(10分钟),全量回归留到合并请求阶段。

4. 退化验证:守住底线,别越改越差

这个词是我从软件测试里借来的。说白了就是检查新改动有没有破坏已有的正确预测。

4.1 退化验证怎么做

  1. 建立“黄金验证集”——一组经过人工确认、完全正确的测试数据。
  2. 每次模型更新后,先用黄金验证集跑一遍。
  3. 对比新结果与基线结果,任何预测值偏差超过阈值就算退化。
  4. 退化项必须修复后才能合并到主分支。
我用过的一个退化检测脚本
#!/bin/bash
# regression_check.sh
BASELINE_FILE="baseline_results_v3.1.json"
NEW_FILE="results_v3.2.json"
THRESHOLD=0.1  # 允许的误差阈值

python compare_results.py \
  --baseline $BASELINE_FILE \
  --new $NEW_FILE \
  --threshold $THRESHOLD \
  --output regression_report.html

if [ $? -ne 0 ]; then
  echo "退化检测失败,请检查新模型"
  exit 1
fi

4.2 我踩过的一个退化坑

有一次我优化模型,跑CYP3A4预测,新模型整体AUC从0.88提升到了0.92,高兴得不行。结果退化验证发现,原有的一类高活性化合物(IC50 < 10 nM)预测准确率从95%暴跌到了70%。——原来我优化的方向偏向了低活性区域,高活性的特征反而被削弱了。幸亏有退化验证,不然直接上线就出大问题。

5. 生命周期怎么串起来?

上面四个阶段不是孤立的。下面这张图是我个人常用的验证生命周期框架,每次启动新项目我都在白板上画一遍。

ADMET验证生命周期 验证计划 验证实施 持续验证 退化验证 验证报告 说明 实线箭头:主流程 虚线箭头:报告后更新计划回归 每个阶段都输出中间产物 我的经验: 验证计划→实施→持续→退化 形成闭环,每次循环都生成报告 推荐周期:每月一次完整循环

从计划开始,到实施,再到持续验证和退化验证,最后输出报告。报告反过来又会影响下一轮的计划——这就是生命周期。闭环的好处是每次迭代都在前一次的基础上提升,不会丢失已有的成果。

6. 总结几个原则

  • 计划阶段多想一步:接受标准、数据溯源、资源分配,写在纸上比临时拍脑袋强百倍。
  • 实施阶段留痕:所有操作log、中间结果、版本号,确保未来可追溯。
  • 持续验证用自动化:CI/CD跑起来,让机器帮你守门。
  • 退化验证是安全网:别光看新指标涨了多少,先看老能力掉没掉。

最后说一句:ADMET验证不是什么高大上的东西,它就是一套可复现的、带记录的、能自动跑的流程。你把这四个阶段做扎实了,不管是FDA pre-IND申报还是内部决策,都不用慌。