文档

MO 把一份声明式 YAML 模板同时当作三样东西用:上传表单的字段定义、 CSV→RDF 转换与 SHACL 校验的依据、以及特征工程与贝叶斯优化的配置。 本页说明本体分层、两套 API 的边界,以及建模方法学上几个不能照抄的决定。

本体分层

抽象基类只放在 mato:,子域各自扩展。判据很直接:一个概念要进 mato:,它必须在三个子域里都成立。组成模型正是反例——位点分数按定义 和为 1,而 MOF 投料是无上界的摩尔当量,硬统一只能靠丢弃当量或凭空归一化, 所以两套组成模型并存,mato: 一行未改。

前缀模块版本说明
mato: 核心跨域基座
https://mo.chemdb.top/ontology/
0.2.0 Material / Process / Phase / Property / Measurement / DataRecord / DataSource 等抽象基类,三个子域共用,加子域时零改动。
photochem: 光化学(钙钛矿)
https://mo.chemdb.top/ontology/photochem/
0.2.0 ABX3 位点-离子组成模型、旋涂/反溶剂/退火工艺、器件层叠、PDP B+ 扩展(稳态 PCE、PL 峰、ISOS 稳定性协议、认证标志)。
adhesive: 胶粘剂
https://mo.chemdb.top/ontology/adhesive/
0.1.0 组分-角色(component-with-role)组成模型、7 化学体系 × 10 应用场景,粘度强制携带温度 + 剪切速率 + 测试方法三元组。
mof: 钛基 MOF 氧化脱硫
https://mo.chemdb.top/ontology/mof/
0.1.0 投料-角色 + 摩尔当量(调节剂常 30–100 eq,不复用位点分数模型);合成 / 结构 / 脱硫三段分离建节点,每个脱硫效率节点强制携带萃取剂标志。

每个类与属性都带 @en / @zh 双语标签,并对齐 EMMO 1.0.0。 对齐方向遵循 SKOS 惯例:X skos:broadMatch Y 表示 Y 是更宽的 EMMO 概念; EMMO 1.0.0 里没有干净对应物的占位概念用 relatedMatch, 且逐条写明差距在哪。

可用模板

加子域的成本是写一份 spec,不是改 mo_ml/。

模板本体模块字段优化目标建模
胶粘剂配方
adhesive · v0.1.0
adhesive 21 5 单段
MOF 氧化脱硫
mof-ods · v0.2.0
mof 33 10 2 段级联
钙钛矿太阳能电池
perovskite · v0.1.0
photochem 28 7 单段

两套 API

公共语料 API 与租户平台 API 是两个进程,分工不是风格问题: Oxigraph 的存储锁是排他的,所以读图的 mo-api 只能单 worker 跑, 而不碰图的平台服务可以多 worker。前缀因此也分开。

公共语料 API

基址 /api · 匿名可读 · 交互式文档 /api/docs

方法路径说明
GET /api/stats 语料统计:样本数、三元组数、类与属性计数、各数据源 SHACL 结论
GET /api/structures OPTIMADE 结构列表,支持完整 1.1 filter 文法与 _mato_* 提供方字段
GET /api/info OPTIMADE 元信息;/info/structures 给出字段级描述
POST /api/sparql 对三元组库执行 SPARQL;/queries 列出内置模板
GET /api/domains 已加载的领域模板(spec id、字段数、优化目标)
GET /api/models 已训练的代理模型清单,按 domain × target 展开
POST /api/predict 给定配方预测目标值,返回 μ 与 σ
POST /api/recommend 贝叶斯优化推荐:EI / UCB / 纯 μ,按 target 的标定默认值选择

平台 API(租户自有数据)

基址 /platform/api · 需 ChemDB 登录 · 交互式文档 /platform/api/docs

方法路径说明
GET /platform/api/me 当前身份(匿名可调,返回 null 而非 401)
GET /platform/api/templates 官方模板列表;/templates/{id} 给出单份 spec 摘要
GET/POST /platform/api/projects 列出 / 创建项目(需登录)
GET/PATCH/DELETE /platform/api/projects/{id} 项目详情、改名、删除(删除即删目录)
GET/PUT /platform/api/projects/{id}/spec 读取 / 覆盖项目自己的模板副本
POST /platform/api/projects/{id}/datasets/preview 上传预览:提出列映射,不落盘
POST /platform/api/projects/{id}/datasets 确认映射后入库:校验 → RDF → SHACL → parquet
GET /platform/api/projects/{id}/datasets/{ds}/rows 逐行读取原始数据(网页查看/编辑器的数据源);/csv 下载原始文件;/report 校验报告
DELETE /platform/api/projects/{id}/datasets/{ds} 删除数据集及其原始文件 / RDF / 报告
POST /platform/api/projects/{id}/jobs 提交训练 / 推荐 / 工单任务(提交时计费)
GET /platform/api/projects/{id}/jobs/{job_id} 任务状态与结果;/worksheet 下载实验工单 CSV
GET/DELETE /platform/api/projects/{id}/models 项目已训练模型清单;/models/{file} 删除指定模型(删除后需重新训练)
GET/PATCH /platform/api/projects/{id}/experiments 推荐实验的回填闭环

登录状态来自 ChemDB:MO 不校验会话签名、不持有 ChemDB 密钥、也没有用户表, 而是把 cookie 转给 ChemDB 换取身份。攻破 MO 伪造不出 ChemDB 登录。 积分同理由 ChemDB 记账。不存在的项目 id 与他人的项目 id 都返回 404—— 403 会确认该 UUID 存在,那是一个跨租户的存在性预言机。

方法学:三个不能照抄的默认值

采集函数按 target 标定

钙钛矿 PCE 用 UCB β=0.5,其余目标用 EI ξ=0.01。差异的前提是 38k 样本把 σ 压得很小, 所以要抑制探索;20–40 点的小样本域要的恰好相反(β 1.0–2.0)。 spec 里覆盖默认值必须同时写 calibrated_on,测试会强制。

GP 噪声有下限

24 点上不设下限的 WhiteKernel 会把噪声优化到 ~1e-10,训练点处 σ→0, EI 与 UCB 一起退化成贪心取 μ,而 R²(train)=1.000 会让这一切看起来很成功。 那个下限是整个代理模型里最吃重的一行。

q-batch 要的是多样性

一次高压釜装 6 个样,所以推荐返回 6 个彼此不同的配方,不是排名前 6。 惩罚半径由候选池自身的成对距离分布推出——在 40 维标准化空间里, 固定半径没有意义,退化后会把 6 次实验花在 6 个几乎相同的配方上。

级联域(如 MOF)不是一个回归拍在一张平表上:A 段是合成条件→结构描述符, B 段是结构描述符 + 脱硫条件→性能。A 段的输出就是 B 段的输入, 所以特征构建不能用「凡是 target 名一律剔除」的粗规则——那会静默地把级联拆成 两个互不相关的模型,而两个都照样训得出、照样打得分。 结构描述符也按整行自举采样而非各自独立抽取:BET 比表面积与缺陷分数物理耦合, 独立抽会造出「高比表面 + 零缺陷」这种不存在的候选,而 GP 会很乐意往那片空洞里外推。

数据流与信任边界

公共语料:CSV → RDF Turtle → SHACL 校验 → Oxigraph → SPARQL → OPTIMADE API → 可视化看板(胶粘剂看板)。 租户数据走同一套转换与校验代码,但落在项目自己的目录里, 从不进入 SPARQL 端点——跨租户读取路径因此根本不存在,删项目就是删目录。

模板一旦可被用户编辑,就不再是可信配置:项目副本以 trusted=False 加载, 不能设置 RDF 构建器或示例数据、不能改指本体模块, 继承来的标定说明会被强制加上「未针对本项目标定」前缀。 RDF 构建器是注册表键名而不是导入路径——否则改一行 YAML 就等价于执行代码。