所有合成 AI 模型都建立在反应数据之上。数据的覆盖面与质量直接决定模型能力的上限,而各个数据源的特点差别很大。
三个主要数据源
| USPTO | Reaxys | Pistachio | |
|---|---|---|---|
| 来源 | 美国专利文本挖掘 | 期刊 + 专利,人工审编 | 专利文本挖掘(商业) |
| 规模 | 约 100~180 万条 | 数千万条 | 数百万条 |
| 许可 | 公开免费 | 商业订阅(昂贵) | 商业许可 |
| 数据质量 | 中等(自动抽取) | 高(人工审编) | 中高 |
| 条件信息 | 部分 | 详细 | 较详细 |
| 产率 | 部分有 | 较全 | 部分 |
| 原子映射 | 需自行处理 | 提供 | 提供 |
| 用途 | 学术研究、开源模型 | 工业检索与建模 | 工业建模 |
USPTO 是几乎所有开源合成 AI 工具的训练数据(AiZynthFinder、ASKCOS 等)。理解它的局限,就理解了这些工具的局限。
USPTO 数据集的版本
# 常见的几个版本(都源自 Lowe 的文本挖掘工作)
#
# USPTO-full 约 180 万条,未去重
# USPTO-MIT 约 48 万条,清洗后,常用于反应预测
# USPTO-50K 5 万条,按反应类型分类,常用于逆合成基准
# USPTO-STEREO 保留立体化学信息
#
# 获取:
# https://figshare.com (搜索 USPTO reactions)
# 或通过 rxn-dataset 等工具包
# 数据格式(反应 SMILES):
# 反应物>试剂>产物
# CC(=O)O.OCC>[H+]>CCOC(C)=O
数据质量问题:必须知道
- 只有成功的反应。这是最根本的局限。专利与文献不报告失败的实验,所以模型学不到「什么条件行不通」。这解释了为什么合成 AI 会自信地给出不可行的建议。
- 文本抽取错误:从专利文本自动抽取时会出错——反应物与试剂混淆、化学计量错误、产物识别错误。
- 条件信息不完整:专利常写「在适当溶剂中,适当温度下」,具体条件缺失。
- 原子映射质量:反应物到产物的原子对应关系是模板提取的基础,自动映射(如 RXNMapper)有错误率。
- 产率不可靠:专利中的产率可能是最优值或估计值。
- 反应类型分布极不均衡:酰胺偶联、Suzuki 偶联、Boc 脱保护等占了很大比例,罕见反应样本极少。这导致模型对常见反应表现好,对罕见反应几乎无能为力。
- 专利偏倚:反映的是工业界的合成偏好,某些学术上重要的反应代表性不足。
数据处理流程
from rdkit import Chem
from rdkit.Chem import AllChem
import re
def clean_reaction_smiles(rxn_smiles):
"""清洗反应 SMILES"""
try:
parts = rxn_smiles.split(">")
if len(parts) != 3:
return None, "bad_format"
reactants, reagents, products = parts
# 1) 解析检查
r_mols = [Chem.MolFromSmiles(s) for s in reactants.split(".") if s]
p_mols = [Chem.MolFromSmiles(s) for s in products.split(".") if s]
if any(m is None for m in r_mols + p_mols):
return None, "parse_failed"
if not p_mols:
return None, "no_product"
# 2) 只保留主产物(最大的)
main_product = max(p_mols, key=lambda m: m.GetNumHeavyAtoms())
# 3) 原子守恒粗检(产物原子应来自反应物)
from collections import Counter
def counts(mols):
c = Counter()
for m in mols:
for a in m.GetAtoms():
if a.GetSymbol() != "H":
c[a.GetSymbol()] += 1
return c
rc, pc = counts(r_mols), counts([main_product])
if any(pc[el] > rc.get(el, 0) for el in pc):
return None, "atom_imbalance"
# 4) 排除平凡反应(产物 = 某个反应物)
p_canon = Chem.MolToSmiles(main_product)
if p_canon in [Chem.MolToSmiles(m) for m in r_mols]:
return None, "trivial"
# 5) 排除过小或过大的反应
if main_product.GetNumHeavyAtoms() < 5:
return None, "too_small"
return {
"reactants": ".".join(Chem.MolToSmiles(m) for m in r_mols),
"reagents": reagents,
"product": p_canon,
}, None
except Exception as e:
return None, f"error:{type(e).__name__}"
# 典型清洗后保留率:50%~70%
# 一定要统计各类失败原因,这能暴露数据源的系统性问题
原子映射
# 原子映射是模板提取的前提:需要知道产物中每个原子来自哪个反应物原子
pip install rxnmapper
from rxnmapper import RXNMapper
rxn_mapper = RXNMapper()
results = rxn_mapper.get_attention_guided_atom_maps([
"CC(=O)O.OCC>>CCOC(C)=O"
])
print(results[0]["mapped_rxn"])
print(f"置信度: {results[0]['confidence']:.3f}")
# 输出形如:
# [CH3:1][C:2](=[O:3])[OH:4].[OH:5][CH2:6][CH3:7]>>
# [CH3:1][C:2](=[O:3])[O:5][CH2:6][CH3:7]
# 置信度低的映射应剔除 —— 错误的映射会产生错误的模板
模板提取
# 从映射好的反应中提取反应模板(反应规则)
# 常用工具:rdchiral(处理立体化学的模板提取与应用)
pip install rdchiral
from rdchiral.template_extractor import extract_from_reaction
reaction = {
"_id": 0,
"reactants": "[CH3:1][C:2](=[O:3])[OH:4].[OH:5][CH2:6][CH3:7]",
"products": "[CH3:1][C:2](=[O:3])[O:5][CH2:6][CH3:7]",
}
template = extract_from_reaction(reaction)
print(template["reaction_smarts"])
# 模板的「半径」影响泛化能力:
# 半径小(只含反应中心)→ 泛化好但可能应用到不合适的底物
# 半径大(含更多环境) → 特异性好但泛化差
#
# 实践中常提取多个半径的模板,或用统计频率筛选
开放数据的新进展
- ORD(Open Reaction Database):结构化的开放反应数据库,格式规范(含完整条件、产率、分析数据),并鼓励提交阴性结果——这正是现有数据源最缺的;
- 高通量实验数据集:某些公开的 HTE 数据集包含系统变化的条件与完整的产率(含低产率),质量远高于文献挖掘数据;
- 电子实验记录本数据:企业内部数据质量最高但不公开——这是自建团队的潜在优势。
关键要点
- USPTO 免费但质量中等,是所有开源合成 AI 工具的训练基础;
- 「只有成功反应」是最根本的局限,解释了合成 AI 为何会给出不可行建议;
- 反应类型分布极不均衡,常见反应表现好、罕见反应几乎无能为力;
- 自建团队的优势在于内部数据包含失败案例,这是公开数据没有的。
延伸资源
- 逆合成工具:385《AiZynthFinder》、386《ASKCOS》;反应预测:388《反应产物预测》、389《反应条件与产率预测》;
- 数据资源见「数据资源」模块。