InChIKey:化学结构索引、盐型处理与申报踩坑
InChI 和 InChIKey 解决的不是'怎么把分子画出来',而是'怎么让不同系统认同这是同一个分子'。前者是完整描述,后者是短得多、适合索引和交换的摘要。做数据库、做申报、做跨平台比对时,真正好用的往往是后者。
它为什么会被拿来做'化学身份证'
InChIKey 的长度固定,只有 27 个字符。这个长度对数据库字段、URL、条码、表单校验都比较友好,也更适合做唯一键。它不是通用意义上的加密哈希,重点也不在'保密',而在把 InChI 的化学语义压缩成一个稳定的标识。
原文里提到的分段可以这样理解:
- 前 14 位主要反映分子骨架和连接关系;
- 中间 8 位更多承载立体化学、电荷、自由基等信息;
- 最后 1 位是版本和校验相关的信息。
这套设计的实际意义很直接:同一个分子在 PubChem、ChEMBL、DrugBank 这类系统里,能用同一把钥匙串起来;而手写名称、SMILES 这类输入,往往会因为规范不同而出问题。
一个能直接拿去查库的例子
InChIKey=UHOVQNZJYSORNB-UHFFFAOYSA-N
以苯为例,这个 Key 就是常见的标准写法。它能稳定指向一个结构,但不能反过来直接还原成完整 InChI。需要回查时,还是得借助数据库或解析服务。
生成逻辑:可重复,但不是可逆
InChIKey 的价值在于确定性。同样的输入、同样的规则、同样的工具链,输出就应该一致。它不是 base64(sha256(InChI)) 这种直白映射,背后有自己的化学规范化流程。
对实际使用来说,别纠结实现细节是不是某个现成哈希函数。更重要的是你是否在同一套规则下生成它。盐型、互变异构、立体化学、金属配位,这些地方只要输入不一致,Key 就会变。
立体异构体和盐型,最容易出错
这两个地方是我最建议先核对的。
比如 (R)-lactic acid 和 (S)-lactic acid,主骨架一样,但立体化学不同,所以中间那段会变。再比如游离碱和盐,很多时候看起来'差不多',但申报时它们就是两种不同的结构表达。若工具链忽略了离子对,最后生成的 Key 就会和数据库里的记录对不上。
原文里提到的 NMPA 现场核查案例,本质上就是这个问题:企业提交的是盐形式,工具却按游离碱去算,结果结构一致性被质疑。这个坑不算罕见,尤其是在旧版工具链里。
代码里该怎么做
用 RDKit 生成时,关键不是'能不能出结果',而是'有没有把该保留的信息保住'。像 -RecMet、-SNon 这类参数,很多人平时不会特意去看,但真碰到盐、金属配合物、立体化学,差一点就会错。
from rdkit import Chem
import re
def safe_inchikey_from_smiles(smi: str, options: str = "-SRel -RecMet") -> str:
"""安全生成 InChIKey:自动处理错误、空值、校验"""
try:
mol = Chem.MolFromSmiles(smi)
if mol is None:
raise ValueError(f"Invalid SMILES: ")
inchi = Chem.inchi.MolToInchi(mol, options=options)
inchi:
ValueError()
key = Chem.inchi.InchiToInchiKey(inchi)
key re.(, key):
ValueError()
_validate_inchikey_checksum(key):
ValueError()
key
Exception e:
() -> :
(key) == key[] == key[] ==
examples = [
,
,
,
,
]
smi examples:
key = safe_inchikey_from_smiles(smi)
()


