关于 Fittest
Fittest 是面向分子与材料研究的模型评估 MCP 服务,由三个机器学习原子间势组成的模型委员会判断预测可信度,并决定是否应交由 DFT。它为研究人员提供结构检查、可信度区间和判断依据;托管版本从 Transition1x 查询 DFT 标签,而非实时计算。
主要功能
- 01使用 MACE-MPA-0、AIMNet2 和 Orb-v3 评估结构
- 02按模型分歧和校准数据给出可信度判断
- 03返回推荐模型、力信息及判断原因
- 04支持批量结构检查和逐结构错误反馈
- 05提供委员会状态与使用统计
适用场景
- 01筛查候选分子并决定是否需要 DFT 验证
- 02检查机器学习势在目标结构上的预测可信度
- 03查看委员会判断依据和模型之间的分歧
MCP 相关
托管 MCP 服务通过 streamable HTTP 向客户端提供 check_structures、explain、swarm_status 和 usage_stats 工具。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://fittest-mcp.westus2.cloudapp.azure.com/mcpclaude mcp add --transport http pavel-tk-fittest https://fittest-mcp.westus2.cloudapp.azure.com/mcp{"mcpServers":{"pavel-tk-fittest":{"type":"http","url":"https://fittest-mcp.westus2.cloudapp.azure.com/mcp"}}}在 Cursor 中打开{"servers":{"pavel-tk-fittest":{"type":"http","url":"https://fittest-mcp.westus2.cloudapp.azure.com/mcp"}}}在 VS Code 中打开{"mcpServers":{"pavel-tk-fittest":{"type":"http","url":"https://fittest-mcp.westus2.cloudapp.azure.com/mcp"}}}{"mcpServers":{"pavel-tk-fittest":{"serverUrl":"https://fittest-mcp.westus2.cloudapp.azure.com/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
详细介绍
Fittest
适者生存,而非最聪明者。 一个不断进化的 Agent 委员会,决定哪些任务能获得计算资源和实验室时间。
智能并不稀缺,真实数据却很稀缺。ML 模型每次筛选数百万种候选分子和材料,但只有少数会进行高保真计算(DFT)或实验室实验。Fittest 是一个由三个独立的基础机器学习原子间势(MLIP:MACE-MPA-0、AIMNet2、Orb-v3)和四个角色 Agent(Skeptic、Calibrator、Oracle、Curator)组成的委员会,它们共享一份日志。对于每种结构,委员会都会决定采用哪个答案、对其信任到什么程度,以及哪些结构需要获取真实数据。在本仓库中,真实数据是从 Transition1x 读取的 DFT 数据(查询数据,而非实时计算);对于实验室时间,决策方式相同。
该项目探讨两个问题,每个问题都通过基线或预先注册的规则进行检验:
- 如果由模型组成委员会来决策,会怎样? 它们之间的分歧会告诉委员会何时应保持审慎(§2.3、§3.3)。
- 委员会能否不断进化,以给出更好的预测? 可以,一旦确定了新成员的测试方式:微调后的子代取代其父代(§2.5)。
本项目为 NVIDIA ALCHEMI 挑战赛开发于 ScienceClaw 2026(MIT Media Lab),基于 NVIDIA ALCHEMI Toolkit 0.3.0-rc。 曾用名为 TrustSwarm;旧 GitHub URL 会重定向到此处。
- 代码:本仓库(
fittest/包,MIT 许可证) - 托管的 MCP 服务:
https://fittest-mcp.westus2.cloudapp.azure.com/mcp - 权威数据,均由结果文件生成:
results/RESULTS.md(想法 1)、results/evolution/SUMMARY.md(想法 2)以及results/story_numbers.json(scripts/story_numbers.py:批评者数值、运行 F 的谱系及其绝对误差)
TL;DR
- 问题:最好的模型会在关键处悄无声息地失准。 在 287 个留出的 Transition1x 反应中,每个模型的力误差都在过渡态处达到峰值——过渡态是决定反应速率的能量势垒顶端。AIMNet2 在反应物处表现领先(中位数为 0.22 eV/Å,而 Orb 为 0.35 eV/Å),但到了过渡态便失去优势(0.46 vs 0.47),且没有任何预警。它自身的种子集成也没有发出预警:其分歧幅度比误差小 2.4 倍。
- 理事会:每项决策都有负责人,没有中央规划者。 三个模型独立作答,彼此看不到对方的答案。校准员维护历史表现记录并选择要提供的答案;质疑者随机审查可信答案并行使否决权;预言者使用真实标签预算;策展者培育和淘汰成员。他们只通过仅追加日志进行协调,因此每项决策都可重放。这些 Agent 是确定性程序,而不是大模型;大模型 Agent 会将整个理事会作为一个工具使用(MCP)。
- 构想 1:由理事会作出决策(无数据泄漏的划分,每组进行 200 次 DFT 标签查询)。
- 独立模型之间的分歧无需标签,就能标记出最佳模型出错的情况:针对“AIMNet2 是否出错”的 AUROC 为 0.917(池划分,1,672 帧)。同一模型的副本过度自信:其分歧幅度比误差小 2.4–36 倍。
- 提供的力 RMSE 为 0.206 eV/Å,而最佳基线为 0.286(−28%)。理事会通过 200 个标签发现,AIMNet2 和 Orb 的平均值是最佳答案;事后使用评估标签选出的这个平均值表现相当(0.202)。
- 增加一个角色,即质疑者随机审查可信答案,可将校准误差(ECE)从 0.370 降至 0.079(4.6 倍)。
- 负面结果:理事会自身的风险评分对剩余错误的排序不如简单基线(AUROC 为 0.73,而基线为 0.80–0.87)。
- 最差的模型是最好的评论者。 作为答题者,MACE-MPA-0 在 99.9% 的评估帧上出错(Orb 为 91.3%,AIMNet2 为 57.2%)。作为评论者,它是唯一一个被移除后会降低理事会错误识别能力的基础模型:在 491 次适应度检查中,平均 ΔAUROC 为 +0.040(AIMNet2 为 −0.067,Orb 为 −0.037)。
- 构想 2:让理事会进化(预先注册,包含失败结果)。策展者使用理事会已经付费获取的标签培育微调子代;子代必须在从未用于训练的标签上胜过其亲代,而没有贡献的成员会被淘汰。最初的四种设计(运行 A–D)未通过规则或未获确认。诊断揭示了原因:测试中针对少量标签的能量检查只是噪声,淘汰了表现最好的子代。采用仅检查力的测试后,运行 F(12 个新种子,两组各查询 800 次),进化中的理事会在 12 个种子中的 12 个都胜过静态理事会:−0.026 eV/Å [−0.030, −0.021](−12%);在来自新化学分子式的 2,475 个结构上也提升了 −14%,此前没有任何运行读取过这些结构。总体而言,在相同评估帧上,相对于构想 1 的最佳基线,误差为 0.181 vs 0.286 eV/Å(−37%),且低于事后选出的平均值。培育了 108 个子代,最终理事会中有 43 个成员,并淘汰了 36 个基础模型中的 32 个。注意:尚未进行筛选的理事会扩张(运行 E)就已带来 −0.018 的提升,占 −0.026 的大部分;筛选本身的贡献尚未单独分离。
- 立即使用。 将托管 MCP 服务添加到 Claude Code:
claude mcp add --transport http fittest https://fittest-mcp.westus2.cloudapp.azure.com/mcp, 然后询问 “使用 fittest 检查我是否可以信任这个水分子的 ML 势能:O 0 0 0, H 0.96 0 0, H -0.24 0.93 0。” 结构绝不会被存储(日志记录政策)。
目录
- 立即使用 — MCP 服务、本地安装、Python API、ALCHEMI 钩子
- 工作原理 — 问题、委员会、Idea 1、以最差模型为批评者、Idea 2 (演化)、ALCHEMI 用法
- 验证 — 数据、划分、指标、Idea 1 消融实验、自我修复
- 失败之处与局限 — 以及后续步骤
- 复现
- 仓库结构图、隐私、许可证、致谢
1. 立即使用
1.1 托管 MCP 服务(无需安装)
fittest-mcp 通过可流式传输的 HTTP 向任何 MCP 客户端提供委员会服务。三个模型 Agent
(MACE-MPA-0、AIMNet2、Orb-v3)作为常驻 CPU 进程运行在 Azure VM 上,它们之间的分歧会根据最终运行中学到的 Calibrator 状态转化为判定
(fittest/snapshots/trust_snapshot.json,与 results/trust_snapshot.json 相同)。首页:
https://fittest-mcp.westus2.cloudapp.azure.com/,公开统计数据见
/stats,运行状况见
/health。完整指南:docs/MCP.md。
| 工具 | 输入 | 返回内容 |
|---|---|---|
check_structures | structures:XYZ 文本(单帧或多帧;原子可单独列出,也可用 ,/; 分隔)、一个 {Z or symbols, R} 对象,或二者混合的列表(Å);include_forces(默认 false) | 每个结构:verdict(trust / send_to_dft)和 verdict_reasons;包含 trust_score_90ci 和 labels_behind_score 的 trust_score;推荐模型或混合模型及其 served_members;served_energy_eV 和 reference_energy_eV(整个批次使用一个固定模型 AIMNet2);最大/平均力(eV/Å);sigma_F 与 tau;各模型的能量和最大力;domain_warning。无法解析的结构会得到单独的 {index, error} 条目,其余批次仍会进行评分 |
explain | 一个结构 | 使用相同规则得出的相同判定,并以文字说明原因;σ_F 与 τ;Calibrator 分桶(σ_F 范围、平均力范围、其中的 oracle 标签)以及其中每个候选项的后验概率 P(correct) 和区间;各成员与委员会均值的偏差;成对力 RMS;偏离最大的成员;不确定性最高的三个原子 |
swarm_status | 无 | 回答者(MACE-MPA-0、AIMNet2、Orb-v3、实时状态、声誉)、批评者(Skeptic)、协调者(Calibrator、Oracle、Curator);账本;校准域、τ、判定规则和支持的元素;运行 A、B、C 的演化家族树(results/evolution/、results/evolution_aimnet/ 中的 family_tree.json,以及每个 results/evolution_c/<budget>/ 中的 family_tree.json) |
usage_stats | 无 | 用户(定义)、调用总数 / 外部调用数 / 内部调用数、各工具调用数、首次和最后一次调用 |
限制:每次调用 ≤ 20 个结构,每个结构 ≤ 100 个原子;非周期性,坐标范围在 ±1000 Å 内;原子间距不得小于 0.3 Å;元素符号必须准确(Cl 或 cl;PDB 风格的 C1 可以,含义不明确的 CA 或 HE1 会报错);每客户端速率限制(突发 20 次,之后每 2 秒 1 次),另有每 IP 限制;每个请求限时 120 秒;模型评估按顺序执行。
判定规则。 check_structures、explain 和用量统计均采用同一条规则。只有同时满足以下四项,结构才会获得
trust:
- 所有模型 Agent 均支持该结构中的元素(AIMNet2 的支持范围最小;完整委员会支持
H B C N O F Si P S Cl As Se Br I),否则判为
send_to_dft,原因是unsupported_elements,且不提供 信任分数; - 力不能全部为零(若每个模型的最大 |F| < 0.05 eV/Å,则意味着存在对称性或处于精确平衡状态,此时分歧不包含任何信息);
- σ_F < τ;
trust_score≥ 0.5。 否则,判定结果为send_to_dft,并在verdict_reasons中列出所有未通过的条件。 τ = 0.620 eV/Å 为固定值:它是 round-0 池中 σ_F 的第 70 百分位数,Calibrator 的阈值规则从未改变过这个值。trust_score是 Calibrator 根据 Transition1x 上的 DFT 预言机标签和先验 Beta(2, 1),针对结构所在的(σ_F,平均 |F|)分桶,计算出的已服务候选答案正确概率 P(served answer correct) 的 Beta 后验均值,因此其值永远不会恰好为 1。它还包含trust_score_90ci(90% 可信区间)和labels_behind_score(该分桶中的 DFT 标签数量);标签较少的分桶会有较宽的区间,因此请结合区间解读分数。“正确”指力 RMSE ≤ 0.25 eV/Å,且相对能量误差 ≤ 0.25 eV(相对于反应物)。§3.3 中的 ECE 0.080 针对的是 D 臂的风险分数(isotonic P(served wrong) 和 Skeptic 的 p_S 中的较大值);除下面的 12 帧抽查外,尚未测量此逐桶trust_score的校准情况。
Claude Code
claude mcp add --transport http fittest https://fittest-mcp.westus2.cloudapp.azure.com/mcp
Cursor(~/.cursor/mcp.json)
{ "mcpServers": { "fittest": { "url": "https://fittest-mcp.westus2.cloudapp.azure.com/mcp" } } }
Claude Desktop / claude.ai:设置 → 连接器 → 添加自定义连接器 →
https://fittest-mcp.westus2.cloudapp.azure.com/mcp。
示例提示词:“使用 fittest 检查我是否可以信任这个水分子的 ML 势能:O 0 0 0,H 0.96 0 0,H -0.24 0.93 0。” 原子之间可用换行、逗号或分号分隔。在 Round-2 验证运行中,逐字使用此提示词,结果为 trust,信任分数为 0.857(90% CI 为 0.61–0.99,依据 4 个标签),建议使用 AIMNet2,σ_F = 0.378 eV/Å,低于 τ = 0.620 eV/Å(docs/MCP.md,验证日志)。
托管 CPU 与 GPU 运行的比较。 在 results/service_demo.xyz 的 12 个留出的 Transition1x 帧上,托管服务的 σ_F ≥ τ 标记与此前的 GPU 运行(results/service_demo.json)完全一致,为 12/12,|Δσ_F| 最大值为 0.0005 eV/Å。根据判定规则,12 个帧中有 7 个可信,且其中没有 DFT 错误帧;此前仅基于 τ 的规则将 2 个 DFT 错误帧判为可信。
适用范围。 Calibrator 从气相 C/H/N/O Transition1x 反应中学习,这些反应最多包含 7 个重原子,包括过渡态和 NEB 路径。对于委员会仍支持但元素不属于 C/H/N/O 的情况、较大的分子、孤立原子或片段,以及异常短的键,会添加 domain_warning;在这些情况下,信任分数属于外推结果。绝对能量采用各模型自身的参考基准(MACE 和 Orb 使用 PBE,AIMNet2 使用 ωB97M),因此不同模型的 served_energy_eV 值不可比较;若某批次使用的服务模型不同,则会附带 energy_warning。请改为比较不同结构的 reference_energy_eV(始终使用 AIMNet2)。
1.2 本地 MCP 服务
# demo only: a plain uvx install has no model agents
claude mcp add fittest-demo -- uvx --from git+https://github.com/Pavel-Tk/fittest fittest-mcp --fake-models
# real models: install into an environment that has them (documented, not yet tested end to end)
uv venv fittest-env --python 3.12
uv pip install --python fittest-env/bin/python "fittest[models] @ git+https://github.com/Pavel-Tk/fittest" \
--extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match # CPU torch
# optional: Orb-v3 in its own env (orb-models conflicts with the Toolkit), as in scripts/setup_cpu.sh
uv venv orb-env --python 3.12
uv pip install --python orb-env/bin/python torch --index-url https://download.pytorch.org/whl/cpu
uv pip install --python orb-env/bin/python "dm-tree>=0.1.9" orb-models ase numpy \
--extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match
# then register ONE of these two (same name, alternatives):
claude mcp add fittest-local -- $PWD/fittest-env/bin/fittest-mcp # (a) MACE + AIMNet2 only
claude mcp add fittest-local -e FITTEST_ORB_PYTHON=$PWD/orb-env/bin/python -- $PWD/fittest-env/bin/fittest-mcp # (b) full committee
直接通过 uvx --from git+… 安装时不包含模型 Agent。它只能提供 --fake-models,即不代表任何实际判断结果的 CPU 占位模型(适合测试连接);不加此标志时,工具会返回错误,提示使用 --fake-models、[models] 额外依赖和托管服务。若要获得实际判断结果,请安装到包含模型的环境中,并让客户端指向该环境里的 fittest-mcp。本文档介绍了本地安装实际模型的方式,但尚未进行端到端测试(从全新环境到得出判断结果);经过测试的路径是托管服务。
[models] 额外依赖通过 ALCHEMI Toolkit 安装 MACE-MPA-0 和 AIMNet2。Orb-v3 需要使用自己的 Python 环境,因为 orb-models 固定的依赖项与 Toolkit 存在冲突;请将 FITTEST_ORB_PYTHON 设为该环境的 Python。只安装 MACE 和 AIMNet2 时,服务提供的是部分委员会,且每个响应都会带有警告:τ 以及 Calibrator 的分桶和账本都是基于包含三个模型的完整委员会构建的,因此判断结果仅为近似值。本地模式通过 stdio 在 CPU 上运行:上述命令会安装仅支持 CPU 的 torch。若要使用 --device cuda,则两个环境都需要安装支持 CUDA 的 torch(不使用 CPU 索引安装,就像 scripts/setup_gpu.sh 所做的那样)。它会为每个已安装的模型 Agent 启动一个进程,各自使用随机 socket 密钥,只将日志写入 ~/.fittest-mcp/usage.sqlite,绝不会向任何地方报告。
1.3 Python API:信任服务
git clone https://github.com/Pavel-Tk/fittest && cd fittest
uv venv .venv --python 3.11 && source .venv/bin/activate # Windows: .venv\Scripts\activate
uv pip install -e ".[dev,service]"
from fittest.service import TrustSnapshot, score, fake_predictors, connect_models
snap = TrustSnapshot.load("results/trust_snapshot.json") # Calibrator state from the final run
# real model agents (one process each; GPU or CPU):
# clients = connect_models(snap.models, base_port=6300, orb_python="/path/to/orb/env/python", device="cuda")
# predictors = {m: c.predict for m, c in clients.items()}
predictors = fake_predictors(snap.models) # CPU stand-ins: wiring only, verdicts meaningless
water = {"Z": [8, 1, 1], "R": [[0, 0, 0], [0.96, 0, 0], [-0.24, 0.93, 0]]}
for r in score([water], predictors, snap):
print(r["sigma_F"], r["flagged"], r["trust"], r["recommended_model"], r["action"])
# keys: sigma_F, sigma_F_max, mean_abs_fbar, flagged, trust, recommended_model, bucket,
# action ("send to oracle / DFT" | "use <candidate>"), served_forces, served_members, per_model
同一函数的 HTTP 和 CLI 封装:
python -m fittest.service serve --snapshot results/trust_snapshot.json --port 8000 [--fake-models]
curl -X POST localhost:8000/trust -H 'content-type: application/json' \
-d '{"systems":[{"Z":[8,1,1],"R":[[0,0,0],[0.96,0,0],[-0.24,0.93,0]]}]}'
python -m fittest.service score my_molecules.xyz --snapshot results/trust_snapshot.json
如果快照学习时使用的模型 Agent 缺失,score 会引发异常:σ_F 及其分桶只有对生成它们的委员会才有意义。
1.4 ALCHEMI 钩子:DisagreementHook
一个可直接用于任何 FusedStage、FIRE2 或 NEB 运行的 Toolkit 钩子,适用于包含两个或更多模型的任意委员会。在准入时以及每隔 every 步,它会请求委员会中的每个成员提供力(每个模型各进行一次往返请求,并发执行),计算每个系统的 σ_F,并标记 σ_F ≥ τ 的系统。设置 graduate=True 时,被标记的系统会获得 status = exit_status,在下一个 refill_check 时离开批次,SizeAwareSampler 会补入新系统;被标记的系统则进入你的 DFT 队列。
from nvalchemi.dynamics import FIRE2, ConvergenceHook, FusedStage, SizeAwareSampler
from nvalchemi.dynamics.base import DynamicsStage
from fittest import paths
from fittest.hook import DisagreementHook
from fittest.model_server import spawn
from fittest.models.mace_batched import BatchedMACE
committee = {m: spawn(m, 6100 + k, python=paths.model_python(m)).connect() # one process per model agent
for k, m in enumerate(["mace_mpa0", "aimnet2", "orb"])}
flagged = []
hook = DisagreementHook(committee, tau=0.57, # eV/Å; float, or a zero-arg callable read at every check
every=10, stage="both", # pristine geometry at admission + every 10 steps
graduate=True, # flagged -> leaves the batch, sampler refills the slot
id_map=lambda sid: ds.load_order[sid],
on_flag=lambda rec: flagged.append(rec["key"]))
driver = BatchedMACE().model # any Toolkit BaseModelMixin drives the dynamics
relax = FIRE2(model=driver, dt=0.05, n_steps=50, convergence_hook=ConvergenceHook.from_fmax(0.05))
for h in driver.make_neighbor_hooks():
relax.register_hook(h, stage=DynamicsStage.BEFORE_COMPUTE)
sampler = SizeAwareSampler(ds, max_atoms=1024, max_edges=None, max_batch_size=48)
fused = FusedStage(sub_stages=[(0, relax)], sampler=sampler, sinks=[], refill_frequency=1, hooks=[hook])
with fused:
fused.run(batch=None, n_steps=20000)
hook.records[flagged[0]] # sigma_admission, checks[{step, sigma, sigma_max, tau, energy}], at_flag{Z, R, forces}
hook.summary() # n_flagged, round trips, gather time, dead models, failures
ds 是任何遵循 Toolkit sampler 协议的数据集;完整示例见
docs/REPRODUCE.md §2。对于 NEB,请使用
NEB(..., extra_hooks=[DisagreementHook(..., graduate=False)]);不使用动力学时,请使用
fittest.hook.DisagreementMonitor(committee, tau).check(keys, Z, R, batch, step=0, phase="x")。
委员会成员可以是 ModelClient、带有 .predict(Z, R, batch[, charge]) 的对象,或返回 (E, F) 的普通可调用对象。若某个成员引发异常或超时,系统会记录该情况;连续失败达到 max_failures 次后会将其停用;只要仍有两个成员响应,检查就会继续。若要将自己的模型添加为 Agent,请参阅 docs/REPRODUCE.md §3。
2. 工作原理
2.1 问题:真实数据稀缺,而模型在关键处悄然失效
发现流程是一个漏斗。GPU 上的 ML 模型每次筛选数以亿计的候选项,而现在 Agent 会设置并检查运行情况。真正稀缺的是地面真值:为少数最终进入流程末端的候选项分别进行高保真模拟或实验室实验。这就引出两个问题:哪些候选项应该获得地面真值?哪些低成本答案无需地面真值也值得信赖?两者都需要知道模型何时出错,但模型不会主动说明。
实验室需要数月时间来判断某个基础 MLIP 是否足以用于自己的化学研究。模型会为每种结构返回一个数值,却不会在结构超出其训练范围时发出警告。在 3,157 个留出的 Transition1x 测试帧(287 个反应)中,所有模型的力 RMSE 中位数相对于 DFT(ωB97x/6-31G(d))均从反应物阶段到过渡态阶段上升(results/fig/numbers.json,fig1)。表现最好的模型 AIMNet2 在反应物阶段明显领先,而在决定反应走向的过渡态阶段则与 Orb 持平:
| model | reactant | path | TS | TS / reactant |
|---|---|---|---|---|
| MACE-MPA-0 | 0.520 | 0.569 | 0.681 | 1.31× |
| AIMNet2 | 0.220 | 0.287 | 0.461 | 2.1× |
| Orb-v3 (omat) | 0.351 | 0.392 | 0.468 | 1.33× |
(eV/Å,每帧力 RMSE 的中位数。)

2.2 委员会:Agent 与黑板
每个 Agent 都持有私有信息,并且只通过只追加的
黑板(fittest.blackboard.Blackboard)与其他 Agent 交流;完整的 arm-D 日志位于
results/blackboard_armD.jsonl,共 5,921 个事件。轮次驱动器推进时钟,不做任何决策;没有中央规划器。这些 Agent 是确定性程序,并非大模型:相同输入会产生相同决策,而大模型 Agent 可以将整个委员会作为工具(§1)。
| agent | 私有持有的信息 | 决策内容 | 发布内容 |
|---|---|---|---|
| ModelAgent ×3 (MACE-MPA-0, AIMNet2, Orb-v3) | 自身权重(在独立的 OS 进程中运行;Orb 在独立的 Python 环境中运行)、自身预测、由 oracle 揭示的误差历史 | 针对每个标记系统,为 DFT 标签出价多少:bid = rep · (1 − exp(−(σ + d_m) / 2 s_m)),其中 d_m 是自身预测与均值的偏差,s_m 是其学习到的误差尺度 | prediction、bid |
Stream(PoolStream) | 到达计划 | 不做决策:被动提供无标签结构 | system |
Monitor(DisagreementMonitor) | — | 标记(σ_F ≥ τ)或放行;是 ALCHEMI hook 的 CPU 双胞版本 | flag、pass |
| Oracle | DFT 标签(Transition1x 查找结果)、预算 | 决定哪些出价会获支付:先进行探索审计,再支付每轮总出价最高的前 k 个 | oracle_result(唯一的标签通道) |
| Skeptic | 留出的参考反应(skeptic_ref)和植入的已知失败案例 | 当其 k=7 个最近参考案例均有误时,否决“可信”判定;植入已知失败案例;将每轮预算的 25% 用于随机审计可信系统 | plant、veto、bid |
| Calibrator | 账本:每个(候选项、上下文桶)的正确性 Beta 后验分布 | 决定要提供什么(单个模型或子集均值,例如 mean(aimnet2+orb))、信任分数、阈值 τ、声誉 | verdict、threshold、reputation |
| Curator | 微调计算资源 | 决定修复哪个模型(账本误差最高的模型),以及是否发布修复(必须通过所有验收检查) | finetune_report |
flowchart LR
S["Stream<br/>label-free structures"] --> P["ModelAgents x3<br/>MACE · AIMNet2 · Orb<br/>(one process each)"]
P -->|"prediction"| M{"Monitor / DisagreementHook<br/>σ_F ≥ τ ?"}
M -->|"pass"| C["Calibrator<br/>ledger · verdict · trust"]
M -->|"flag"| B["Bids<br/>ModelAgents + Skeptic"]
K["Skeptic<br/>private references,<br/>planted failures"] -->|"veto, audits"| B
C -->|"verdict"| K
B --> O["Oracle<br/>k DFT labels / round"]
O -->|"oracle_result: true error<br/>of every candidate"| C
C -->|"reputation"| P
C -->|"threshold τ"| M
C -->|"worst model + labels"| U["Curator<br/>LoRA fine-tune + gate"]
U -->|"finetune_report"| C
Calibrator 提供的结果。 候选项是模型的所有非空子集均值(3 个单模型、3 个双模型、1 个三模型 consensus)。上下文桶不依赖标签:σ_F 分位数区间(4 档)× 平均 |F̄| 区间(3 档)。
每个桶都提供后验正确概率最高的候选项。其风险分数是等距回归得到的 P(所提供答案错误 | 特征);特征(σ_F 或所提供候选项成员之间的离散程度)通过自身标签进行按反应分组的 5 折交叉验证选出(选用 σ_F:CV AUROC 为 0.756,而离散程度为 0.752)。τ = 满足账本中 P(错误 | σ ≥ τ) ≥ 0.5 的最小 σ,并且不低于第 0 轮 σ_F 的第 70 百分位数。最终运行中,τ 始终保持在该下限(0.620;见 §4)。
最终运行(arm D)的情况。 共进行 200 次 oracle 调用:50 次探索审计,150 次通过出价赢得(共提交 9,745 次出价)。hook 标记了 601 个系统;Skeptic 否决了 1,788 个可信判定(其中 1,202 个针对池中的系统;对评估集的否决仅供参考)。在评估集中,Calibrator 对 1,485 个帧中的 1,373 个提供 mean(aimnet2+orb),对 112 个提供 aimnet2。最终声誉几乎相同(aimnet2 0.89、mace_mpa0 0.89、orb 0.89、skeptic 0.86)。
2.3 想法 1:让委员会共同决策
这个想法源自大模型:Mixture-of-Agents 会询问多个模型,再由聚合器做出决定。这里的成员是相互独立的基础 MLIP,由不同团队使用不同数据训练。与多 Agent 辩论不同,它们永远看不到彼此的答案,也不会被推动着达成一致;它们之间的分歧就是信号。
信号。 对于在含有 n 个原子的结构上预测力 F_m 的 M 个模型:
F̄_i = mean_m F_m,i
s_i = sqrt( mean_m ||F_m,i − F̄_i||² ) per-atom spread
σ_F = mean_i s_i per-structure disagreement (eV/Å)
(fittest.signals.force_spread;钩子使用完全相同的向量化版本,并已通过一致性测试。)
- 由独立模型组成的委员会(MACE-MPA-0、AIMNet2、Orb):Spearman(σ_F,AIMNet2 力误差) 0.73;离散度约为误差的 1.8×。
- 种子集成(随附的四个 AIMNet2 成员):Spearman 为 0.68,但离散度仅约为误差的 0.4×——过度自信。
- 在 1,485 个评估帧上:AIMNet2 集成的中位误差是其离散度的 2.4×;四个 MACE LoRA 种子(B′ 组)的离散程度不足 36×(离散度为 0.008 eV/Å,误差为 0.278 eV/Å)。
种子集成可以很好地对误差排序,同时离散程度严重不足:排序能力与校准是不同的属性。这就是委员会使用由不同团队基于不同数据训练的模型的原因。

委员会如何利用它(完整消融实验见 §3.3):分歧能标记出最佳模型出错的情况(针对“AIMNet2 出错”的 AUROC 为 0.917,池划分);校准器会为每个上下文分桶选出最佳子集,误差为 0.206 eV/Å,而最佳基线为 0.286(−28%);怀疑者对可信答案进行随机审计,将 ECE 从 0.370 降至 0.079。委员会自身的风险分数对剩余错误的排序不如基线的分数(AUROC 为 0.73,对比 0.80–0.87)。
2.4 最差的模型是最好的批评者
进化循环(§2.5)会为每个成员评分,评估其两种角色:作为答题者(没有它时,服务误差会增加多少,Δ_ans),以及作为批评者(没有它时,分歧信号的 AUROC 会下降多少,Δ_crit)。对所有进化运行中三种基础模型的每次适应度评估进行汇总(results/story_numbers.json):
| 基础模型 | 作为答题者时出错(评估) | 批评者:平均 Δ_crit(移除时损失的 AUROC) | 检查次数 | Δ_crit CI 高于 0 的检查次数 |
|---|---|---|---|---|
| MACE-MPA-0 | 99.9% | +0.040 | 491 | 157 |
| Orb-v3 | 91.3% | −0.037 | 503 | 33 |
| AIMNet2 | 57.2% | −0.067 | 528 | 15 |
这里的“出错”指在 1,485 个评估帧上的力 RMSE > 0.25 eV/Å(results/fig/numbers.json)。委员会从不单独使用 MACE 提供答案,但移除 MACE 这款基础模型会持续损害委员会的错误检测能力。我们的解读(未经验证):MACE 使用了不同的数据(PBE 材料)训练,并且会在其他模型存在共同盲点的地方与它们产生分歧。需要注意的是:在 GPU 上的 F 轮运行中,循环在 12 个种子中有 12 个淘汰了基础 MACE;在只繁育 AIMNet2 子代的 CPU 运行中,基础 MACE 在 24 个种子中有 18 个存活下来(E-cpu、F-cpu)。
2.5 想法 2:让委员会进化
状态:在 F 轮运行中得到确认(预注册、12 个新种子,并再次在任何运行都未读取过的帧上验证)。此前有四种设计未能成功或未获确认;结果均已报告。完整说明、对照和探索性运行见:
results/evolution/SUMMARY.md。
静态委员会的成员固定不变。进化循环(fittest/evolution.py、fittest/evolution_c.py、scripts/evolve_c.py)探究:与静态对照组使用相同的 DFT 预算时,一个能繁育、测试并淘汰自身成员的委员会能否提供更好的答案。一代进化,如 F 轮运行所示(results/evolution_c/PREREG.md、results/evolution_f/PREREG.md):
flowchart LR
T["1 Triage<br/>members predict the pool;<br/>Calibrator chooses what to serve"] --> O["2 Oracle<br/>200 labels per generation:<br/>75% highest σ_F, 25% audits of trusted frames"]
O --> F["3 Fitness<br/>marginal contribution<br/>answerer Δ_ans · critic Δ_crit"]
F --> S["4 Selection<br/>retire members whose<br/>contribution CI includes 0"]
S --> B["5 Breeding<br/>one child per family,<br/>fine-tuned where the council is weak"]
B --> G["6 Gate<br/>child ≤ parent force RMSE<br/>on select labels; clones rejected"]
G --> H["7 Hot-swap<br/>survivors + gated children;<br/>ledger re-fitted"]
H --> T
- 预算与控制组。 4 代 × 200 次 Transition1x 查询 = 800,两组相同。静态控制组运行相同的分诊和预言机流程,成员固定为 MACE-MPA-0 +
AIMNet2 + Orb。每次运行的每一代都在相同的 1,485 个评估帧上评分,并使用 1,000 次共享的反应自助法重采样,因此比较是配对的。评估数据不会反馈:只有最终评分器
(
EvalScorer)会读取评估标签。 - 繁育/选择划分。 池中的 16 个端点几何组件一次性划分为选择集 (6 个组件、561 帧、51 个反应)和繁育集(10 个组件、1,111 帧、101 个反应);每代的标签中,40% 分配给选择集,60% 分配给繁育集。子代仅使用繁育标签训练;门控和适应度使用选择标签,而没有任何成员使用这些标签训练(已断言)。
- 生态位(不使用标签):
flagged= σ_F ≥ τ₀(池中 σ_F 的第 70 百分位数,即高分歧、类似过渡态的区域),trusted= 其余部分。只有flagged会繁育专才,因为委员会在该区域能力较弱,且分诊会在此处分配标签。 - 繁育。 在第 0、1、2 代之后,策展器会从每个家族(AIMNet2、Orb-v3、MACE-MPA-0)中当前适应度最高的成员繁育一个子代,并使用
flagged生态位的繁育标签进行训练。仅微调头部(AIMNet2 的mlps.2+outputs、Orb 的heads、MACE 的model.readouts),使用 Adam,训练 200 步,采用力 + 相对反应能量损失。后续子代会将其父代的学习率和能量权重乘以 ½ 或 2 进行变异,并从父代的头部权重开始训练。 - 门控。 在生态位的选择标签上,子代的力 RMSE 必须 ≤ 其父代。**克隆拒绝:**子代与某个成员相对于总体平均力的偏差之间的 Pearson r > 0.95,或逐帧力 RMS 差异中位数 < 0.02 eV/Å。未通过的子代会胎死腹中,但仍保留在家族树中。运行 A–D 还要求相对于反应物的 ΔE MAE ≤ 父代;运行 A 还要求 ALCHEMI 的
build_acceptance_report从头训练比率 ≤ 1.01;运行 F 则取消了能量检查(见下文)。 - 适应度 = 对委员会的边际贡献,使用干净标签:
- 应答者:
Δ_ans(m) = err(P \ m) − err(P),其中 err 是以错误度量单位表示的平均服务误差(F_RMSE / 0.25 + |ΔE_rel| / 0.25),服务答案来自通过折外方式拟合的校准器(按反应分组的 5 折),因此成员不会因过拟合其评分所用标签而显得有用; - 评判者:
Δ_crit(m) = AUROC(σ_F(P) → P wrong) − AUROC(σ_F(P \ m) → P\m wrong); - 400 次配对反应自助法重采样为每个 Δ 计算 SE 和 95% CI;适应度 = Δ_ans/SE_ans + Δ_crit/SE_crit;角色(应答者或评判者)由较大的 z 分数决定。
- 应答者:
- 选择。 每次成员退出后重新计算。当某成员的两个 Δ 的 CI 下界均不大于 0,且适应度 ≤ 0.5 时,该成员符合资格;当委员会成员超过 3 人时,淘汰符合资格者中适应度最低的成员;随后当委员会成员超过 6 人时,淘汰适应度最低的成员。基础模型也可以退役。
- 决策规则(运行 F,在运行前固定):平均 Δ 服务力 RMSE 的种子级 95% t 区间(演化组 − 静态组,评估集,最终一代)完全低于 0;12 个种子中显著变差的不超过 1 个;且种子级 ECE 不退步。运行 A–C 使用了更严格的规则:每个种子都必须显著获胜,且相较于该运行自身的第 0 代也必须获胜。
每项预注册设计(Δ = 最终一代 − 相同预算下的静态组,评估集上的服务力 RMSE,eV/Å;* = 配对 CI 不包含 0;E 和 F:种子级均值及其 95% t 区间):
| 运行 | 设计 | 种子数 | Δ 力 RMSE | 结论 |
|---|---|---|---|---|
| A | MACE LoRA 子模型;以 rel-E 和 ALCHEMI 报告作为门控;预算 200 | 2 | +0.010 * / −0.011 * | 失败 |
| B | AIMNet2 头部微调;预算 200 | 2 | −0.001 / −0.024 * | 失败(需每个种子都通过) |
| C | 三个系列的细分专家;预算 200 / 400 / 800 | 每个预算 2 个 | 6 个种子-预算单元中有 2 个保持 | 失败 |
| D | C + 保护基础模型 + 10% rel-E 容差;新种子 | 6(CPU 为主) | 6 个中有 4 个保持,需 5 个 | 未确认 |
| E | 不经筛选地扩展(保留基础模型,不设门控、不剪枝);新种子 | 12 | −0.018 [−0.024, −0.013],10 个更好 / 0 个更差 | 已确认 |
| F | C,使用仅针对力的门控;新种子 | 12 | −0.026 [−0.030, −0.021],12 个更好 / 0 个更差 | 已确认 |
运行 F 还通过了原始的逐种子规则,其相对能量误差(−0.039 eV)和 ECE(−0.021)均低于静态方案。
之前未读取过的帧。 运行 F 的修复方案源自对较早评估结果的诊断,因此在评分前预先登记了对从未读取过的帧进行检查
(PREREG_fresh_frames.md,
FRESH_FRAMES.md):2,475 个结构、225 个反应、Transition1x 验证集
中的公式。运行 F:−0.026 [−0.034, −0.019],12 个种子中 12 个更好(服务力 RMSE 从 0.191 → 0.164 eV/Å,
−14%)。运行 E:−0.018 [−0.026, −0.011],12 个种子中 12 个更好。
从绝对值来看(results/story_numbers.json):在评估集上,演化后的委员会
服务力为 0.181 eV/Å(12 个种子的均值),而静态委员会为 0.207,事后 AIMNet2+Orb 平均值为 0.202,Idea 1
基线中的最佳结果为 0.286(−37%)。基线的预测不使用标签,因此其误差不受预算影响。
谱系(运行 F,GPU,12 个种子,results/evolution_f/gpu*/b800*/family_tree.json):繁育了 108 个子模型
(每个种子 9 个),9 个夭折,6 个因克隆而被拒绝,50 个后来退役,43 个进入最终委员会。36 个基础模型中有
32 个退役(MACE 12 个、Orb 12 个、AIMNet2 8 个),最终委员会各有 3 到 6 个成员。AIMNet2 和 Orb 形成了真正的谱系(子模型的子模型);36 个 MACE 子模型中有 33 个再次由基础模型繁育而来。
过程中的发现
- 能量检查是噪声。 运行 A–C 的大多数子模型未通过反应相对能量门控
(运行 A:18 个中有 15 个夭折;GPU 运行 C:54 个中有 36 个,其中 35 个是因 rel-E)。在 CPU 上,该检查的
符号与评估结果仅有 38% 的一致率(r = −0.15),而选择集上的力变化可以预测评估结果(r = 0.87)。在 AIMNet2
子模型中有 39/114 个通过该检查,而 Orb 子模型为 91/114;最终表现差于静态方案的运行都没有留下 AIMNet2 专家
(
DIAGNOSIS.md)。运行 F 只移除了这一项检查。 - 扩展与筛选。 不经筛选地扩展委员会(运行 E)在不同种子上得到 −0.018,运行 F 的完整循环得到 −0.026。一个 假对照(学习率为 0 的子模型;CPU,探索性)表明,运行 E 的力提升来自学习。要确定筛选本身的额外贡献,需要在相同种子上进行两组对照 (§4)。
- 预算。 运行 F 的设计在 400 个标签时没有显著效果(−0.010 [−0.023, +0.004]),在 1,600 个标签时则有提升 (−0.030);此结果为探索性,种子为 24–29。该循环需要足够多的标签。
- 噪声。 运行间噪声约为 0.02 eV/Å(仅静态委员会在不同种子间就从 0.202 变为 0.220),配对置信区间只覆盖评估集重采样。因此,运行 D–F 使用 6 到 12 个新种子,并采用种子级区间。
运行 A 和 B 的家族树:results/fig/fig8_family_tree_run{A,B}_s{0,1}.png;逐代曲线:
results/fig/fig7_evolution_run{A,B}_s{0,1}.png;预算轴:results/evolution_c/fig9_budget.png。
2.6 ALCHEMI Toolkit 的使用方式
| Toolkit 功能(0.3.0-rc) | 用途 | 证据 |
|---|---|---|
In-flight batching:FusedStage.run(batch=None) + SizeAwareSampler + FIRE2 | 600 个 Transition1x 池帧在弛豫过程中流式处理;被标记的系统离开批次,采样器会补入新系统 | results/screen_alchemi.json |
Hook 协议(stage、frequency、__call__(ctx, stage)、ON_ADMISSION / AFTER_STEP) | DisagreementHook 收集委员会的力,并通过设置 status = exit_status 使系统毕业 | fittest/hook.py、tests/test_hook.py(GPU 上的 7 项测试,包括一次真实的 FusedStage 运行) |
MACEWrapper、AIMNet2 wrapper、make_neighbor_hooks | 模型 Agent 和动力学驱动器 | fittest/models/、fittest/model_server.py |
批处理 NEB(示例 11 模式)、extra_hooks | 在一个批次中处理 8 个反应 × 10 个图像,hook 负责观测(graduate=False) | results/neb.json |
FineTuningStrategy + LoRAConfig、fit_atomic_reference_energies | Curator 根据 oracle 标签对 MACE-MPA-0 进行 LoRA 修复 | scripts/finetune.py、fittest/mace_lora.py |
evaluate_accuracy + build_acceptance_report | Curator 的上线/不上线检查之一 | results/ablation.json → D 臂 finetune.report |
In-flight 筛查(600 个池帧、MACE-MPA-0 驱动器、τ = 0.571 = 缓存 σ_F 的第 70 百分位数、 每 10 步检查一次、每个系统最多 50 个 FIRE2 步骤、L4 GPU):
| 已标记 | 260(入场时 180 个,弛豫期间 80 个) |
| 已收敛 / 达到步数上限 | 68 / 272 |
| 补入事件 / 通过补入机制纳入的系统 | 202 / 552 |
| 耗时、吞吐量 | 131 s,1,500 atom-steps/s;委员会数据收集占总耗时的 42% |
| 入场时 hook 的 σ 与离线 σ 对比 | 600 帧上的最大 |Δ| 为 2.8 × 10⁻⁶ eV/Å |
| 事后统计:委员会力 RMSE 均值 | 已标记 0.549 eV/Å,未标记 0.376 eV/Å |
批处理 NEB(8 个反应、AIMNet2 驱动器、爬山图像,全部 8 个在 21 s 内收敛):沿 DFT 参考能带,σ_F 与力误差一致(按反应计算的 Spearman 中位数为 0.96,合并后为 0.85;两个反应分别为 0.12 和 0.16)。σ_F 不能反映相对能量误差(Spearman 中位数为 0.14,合并后为 −0.20)。8 个反应中,σ_F 最大值出现在 DFT 过渡态的有 3 个,距离过渡态不超过一个图像的有 6 个。

3. 验证
3.1 数据与划分
- Transition1x(ωB97x/6-31G(d);C、H、N、O;中性;≤ 7 个重原子)。共 5,632 帧:反应物、产物、TS 和采样得到的 NEB 路径图像。
- Transition1x 官方划分依据化学式。在测试集公式内部,Transition1x 会在不同反应间重复使用反应物几何,因此按反应划分会造成数据泄漏:池与评估集之间存在 732 个近重复端点几何。最终划分将共享任一反应物或产物几何的反应归入同一连通分量(37 个分量,287 个反应),再按分量划分:池与评估集之间共有 0 个共享端点几何和 0 个近重复项(最大 |ΔR| < 10⁻³ Å)
(
results/split_report.json)。
| 划分 | 来源 | 帧数 | 反应数 | 谁能看到标签 |
|---|---|---|---|---|
pool | T1x test | 1,672 | 152 | Oracle,每次付费调用一个 |
eval | T1x test | 1,485 | 135 | 运行期间无人可见;仅用于最终评分 |
skeptic_ref | T1x val | 1,221 | 111 | 仅 Skeptic 可见 |
planted | T1x val | 1,254 | 114 | Skeptic 植入;标签保密 |
Pool 和 eval 仍共享化学式。
- 模型与数据泄漏。 MACE-MPA-0(MPtrj + sAlex,PBE/PBE+U)、AIMNet2(ωB97M-D3,所提供集成中的成员 0)、Orb
orb-v3-conservative-inf-omat(OMat24,PBE/PBE+U)。已排除在 OMol25 上训练的 Orb 模型:OMol25 重新计算了 Transition1x 几何。详情见:docs/data_and_models.md。
3.2 指标,在运行前固定
- 错误 ⇔ 力 RMSE > 0.25 eV/Å 或 |ΔE_rel| > 0.25 eV(相对于反应物的能量,因此各模型的参考能量会相互抵消)。在
ablation.json(by_threshold)中给出了 0.15 和 0.4 阈值下的敏感性。 - AUROC:该组的警告分数能否对其自身提供的错误答案进行排序?也会与共同目标进行比较(AIMNet2 错误),因为 AIMNet2 出现在每个组中。
- Recall@K:收到过 oracle 调用的错误答案所占比例。
- 植入错误捕获率:已植入的已知失败案例(AIMNet2 力 RMSE > 0.4)中被标记、否决或检查的比例。
- 评估集上的提供答案误差(力 RMSE、相对能量 MAE)、该组 P(wrong) 的 ECE 和 Brier、静默失败(错误严重,F-RMSE > 0.4,且未经检查便受到信任)、信任比例。
- 95% CI:按反应进行 1,000 次 bootstrap 重采样,各组之间配对。
- 预算:每组 200 次 Transition1x 标签查询(每轮 40 次 × 5 轮)。
3.3 消融:思路 1(最终运行,v4)
| 组 | 模型 | 警告分数 | 提供的答案 |
|---|---|---|---|
| A_single | AIMNet2 | max|F| | AIMNet2 |
| A_random | AIMNet2 | 随机 | AIMNet2 |
| B_seed | AIMNet2 × 4 个随附种子 | seed σ_F | 集成平均值 |
| B′ (B_mace_seeds) | MACE-MPA-0 × 4 个 LoRA 种子,在 D 组的 160 个标签上微调 | seed σ_F | 集成平均值 |
| C_collective | MACE + AIMNet2 + Orb | σ_F | 集成平均值 |
| C_audit | C + Skeptic 对受信任系统进行的随机审计 | σ_F | 集成平均值 |
| D (Fittest) | MACE + AIMNet2 + Orb + 所有 Agent | Calibrator 风险 / Skeptic | Calibrator 的建议 |
结果文件中将组 D 记作 D_fittest,位于 results/ablation.json 中。重命名前写入的结果文件使用了标签 D_trustswarm;
仅更改了该标签,未更改任何数字。
| 组 | 评估集 AUROC | 相对于 AIMNet2 错误的 AUROC | Recall@K | 植入错误捕获率 | 评估集提供答案 F-RMSE (eV/Å) | 评估集提供答案 ΔE MAE (eV) | 评估集 ECE | 评估集 Brier | 评估集信任比例 |
|---|---|---|---|---|---|---|---|---|---|
| A_single | 0.838 [0.81, 0.87] | 0.792 | 0.131 | 0.600 | 0.317 [0.30, 0.33] | 0.121 | 0.175 | 0.267 | 0.000 |
| A_random | 0.499 [0.47, 0.53] | 0.518 | 0.121 | 0.325 | 0.317 [0.30, 0.33] | 0.121 | 0.538 | 0.554 | 0.898 |
| B_seed | 0.802 [0.77, 0.84] | 0.802 | 0.166 | 0.700 | 0.286 [0.28, 0.30] | 0.110 | 0.426 | 0.428 | 0.000 |
| B′ MACE 种子 | 0.867 [0.84, 0.90] | 0.483 | 0.157 | 0.500 | 0.304 [0.29, 0.32] | 0.493 | 0.263 | 0.267 | 0.000 |
| C_collective | 0.802 [0.77, 0.84] | 0.917 | 0.159 | 0.350 | 0.293 [0.28, 0.31] | 0.221 | 0.370 | 0.374 | 0.000 |
| C_audit | 0.802 [0.77, 0.84] | 0.917 | 0.138 | 0.375 | 0.293 [0.28, 0.31] | 0.221 | 0.079 | 0.189 | 0.419 |
| D Fittest | 0.730 [0.69, 0.76] | 0.738 | 0.186 | 0.450 | 0.206 [0.20, 0.22] | 0.151 | 0.080 | 0.185 | 0.708 |
包含所有 CI 和数据池指标的完整表格:results/RESULTS.md。
Fittest (D) 与各基线比较,配对 95% CI(better / worse:差值的 CI 不包含 0):
| D 对比 | 评估集 AUROC | Recall@K | 植入错误 | 提供答案 F-RMSE | ECE | Brier | 评估集静默失败 |
|---|---|---|---|---|---|---|---|
| A_single | worse | n.s. | n.s. | better | better | better | n.s. |
| A_random | better | better | n.s. | better | better | better | better |
| B_seed | worse | n.s. | n.s. | better | better | better | n.s. |
| B′ MACE 种子 | worse | n.s. | n.s. | better | better | better | n.s. |
| C_collective | worse | n.s. | better | better | better | better | n.s. |
| C_audit | worse | n.s. | n.s. | better | n.s. | n.s. | n.s. |
显著结果
- 已给出的答案:Fittest 的力 RMSE(0.206 eV/Å)优于所有基线;在 40% 的评估帧上出错,而基线为 54–73%。这一提升来自仅凭 200 个标签发现了
mean(aimnet2+orb);没有任何基线使用子集候选项。事后利用评估标签选出的固定 AIMNet2+Orb 平均模型得分为 0.202 eV/Å,表现同样好。预算扫描:每轮 k = 20 / 40 / 80 个标签时,得分分别为 0.202 / 0.206 / 0.204 eV/Å。 - 校准:ECE 为 0.080,Brier 为 0.185,优于 A_single、A_random、B、B′ 和 C;与 C_audit 持平。这是 arm D 风险分数的校准情况;托管 MCP 服务的
trust_score(按桶计算的 Beta 后验)是另一种指标,除 12 帧抽查外,尚未测量其校准情况(§1.1)。校准方面的提升来自 Skeptic 对可信答案进行的随机审计。
未能做到的方面
- 错误排序:Fittest 的 AUROC(0.730)显著低于 A_single、B、B′、C 和 C_audit。
- 静默失败:Fittest 在评估集上的结果为 0/96,在池中的结果为 1/115;与五个非随机基线相比无显著差异——其中四个基线不信任任何内容,因此按定义错误数为零。
- 人为植入的失败:检出 0.45 个,而基线为 0.33–0.70 个;仅优于 C_collective。

AIMNet2 和 Orb 取平均值为何有效(评估集,仅针对力,以 0.25 eV/Å 为错误阈值):AIMNet2 单独使用时,在 57.2% 的帧上出错;AIMNet2+Orb 均值模型将这一比例降至 26.3%;加入 MACE 后这一比例回升至 54.3%;AIMNet2 种子均值模型的错误率为 51.6%。

3.4 自我修复(Curator)
Curator 选中了 mace_mpa0(账本中力 RMSE 最高,为 0.80 eV/Å;Orb 为 0.51,AIMNet2 为 0.43),并移交了 186 个预言机标签;GPU 作业使用其中 160 个训练 LoRA 适配器,另留出 26 个(3 个完整几何分量,与训练数据没有共享几何结构)。
| 检查项(必须全部通过) | 来源 | 数值 | 限值 | 结果 |
|---|---|---|---|---|
| 留出集力 RMSE 未变差 | Fittest | 1.355 → 0.692 eV/Å | ≤ 基础模型 | 通过 |
| 留出集相对能量 MAE 未变差 | Fittest | 0.314 → 0.364 eV | ≤ 基础模型 | 失败 |
| 相对于同等规模从头训练学生模型的最差错误比 | ALCHEMI build_acceptance_report | 1.404 | ≤ 1.0 | 失败 |
| ALCHEMI 报告通过 | ALCHEMI | false | true | 失败 |
未发布。未发布的适配器在评估集上的力 RMSE 中位数本可达到 0.279 eV/Å,而基础模型为 0.558 eV/Å(仅见图示;从未提供服务)。

4. 失败与局限
以下内容也见 results/RESULTS.md(“失败与注意事项”)。
- 错误排序更差。 AUROC 为 0.730,而简单基线为 0.80–0.87。D 组的风险分数 根据中标标签学习得出,而这些标签集中在较高的 σ 值上。
- 标签存在选择偏差。 在 v1 中,Oracle 只为被标记的(高 σ)系统提供标签,因此从未测试过实际给予信任的情形。v2 加入了 Skeptic 对受信任系统的随机审计(每轮预算的 25%);这减轻了偏差,但未能消除。
- 发现并修复了数据泄漏。 v1–v2 按反应划分数据;Transition1x 会重用反应物几何结构,因此训练池与评估集有 732 个近重复端点。v3 按几何结构连通分量划分(共享数为 0)。Curator 最初的留出集也存在泄漏(9 个留出反应各自有一个端点与训练集共享),后来改为按完整连通分量划分。v1 中的植入案例定义为“MACE 预测错误”,这对包含 MACE 的组有利;从 v2 起改为“AIMNet2 严重预测错误”。
- 修复被自身的门槛拦截。 力的误差从 1.355 降至 0.692 eV/Å,相对能量误差却从 0.314 升至 0.364 eV,且 ALCHEMI 从头训练比率为 1.404 > 1.0。
- τ 始终没有变化。 Calibrator 的阈值在所有轮次中都停留在第 0 轮的下限(0.620):标记依据的是第 70 百分位规则,而非学习结果。
- 信誉度几乎没有区分度(0.86–0.89):按信誉度加权的竞标行为与竞标总和相同。
- 静态委员会的已服务答案增益等于事后选择(0.202 对 0.206 eV/Å);进化后的委员会低于这一水平(0.181,§2.5)。扫描中每笔预算分别推荐了哪个候选项,未予记录。
- 理论水平。 MACE-MPA-0 和 Orb-v3-omat 是 PBE 材料模型,AIMNet2 使用 ωB97M-D3,标签则使用 ωB97x/6-31G(d)。模型之间从不比较绝对能量;每个误差中都有一部分来自理论水平差异,而非模型失效。
- 标签来自查表,而非实时 DFT。 Oracle 会返回存储的 Transition1x 标签。
- 消融实验是对 GPU 预测结果的 CPU 重放。 Agent 在 GPU 上重放模型 Agent 进程缓存的预测结果,钩子逻辑则由其 CPU 对应实现(
DisagreementMonitor)运行。ALCHEMI 钩子本身在 600 帧的在途筛选和 NEB 中运行;消融实验不会使用该筛选的 Oracle 队列。 - 校准范围狭窄。 信任度数值是在含有不超过 7 个重原子的 C/H/N/O 反应化学体系上学习得到的。在水、金属、带电或周期性体系上,这些数值属于外推。
- 进化。 在 F 轮运行(§2.5)之前,四种设计(A–D 轮运行)均告失败或未获确认。F 轮运行的修复方案是在查看早期评估结果后找到的;对从未读取过的帧进行的预注册检查通过了,但该设计尚未在第二个数据集上测试。不进行筛选而直接扩增(E 轮运行)就能获得大部分增益,而筛选本身额外带来的增益尚未单独测量。在 F 轮运行的全部 12 个 GPU 种子中,最佳评审模型 MACE(§2.4)都已退役。A–C 轮运行在每种条件下只有两个种子;对于需要每个种子都获胜的规则而言,统计效力较低。C 轮运行的首次 GPU 尝试无效(OOM 子进程被计作死胎),因此未予引用;干净的 GPU 重跑(三个族群)才是忠实的 C 轮运行,而 C′(CPU,仅 AIMNet2)是报告中的偏离方案。额外种子和设计变体均属探索性实验,在相同评估划分上运行,并已明确标注。详情:
results/evolution/SUMMARY.md。 - 合成冒烟测试(
scripts/make_synthetic.py)表明整个流程可以运行,但这并非证据。
后续计划
- 使用实时 DFT,而不是查询 Transition1x。
- 在相同的种子上比较筛选与增长,单独评估筛选带来的效果。
- 为子模型建立可靠的能量测试。 F 测试目前只依据力来评估子模型。由于少数几个标签上的能量测试结果只是噪声,而非因为能量不重要,因此我们取消了这项检查;有足够的标签后,就可以再次根据反应能来评估子模型。
- 让委员会自行确定规模。 委员会目前已经会扩增和缩减规模(最终由 3 至 6 名成员组成),但 3 和 6 这两个上限和下限是我们设定的。
- 让新的模型系列加入。 目前只有 AIMNet2、Orb 和 MACE 参与繁育。
- 在同一理论层级组建委员会, 以区分模型失效与理论层级差距。
- 让实验室参与决策: 对实验采用与 DFT 相同的决策方式。
5. 复现
5.1 CPU,从全新克隆开始(几分钟)
git clone https://github.com/Pavel-Tk/fittest && cd fittest
uv venv .venv --python 3.11 && source .venv/bin/activate
uv pip install -e ".[dev,service]"
pytest # CPU suite; GPU-only hook tests skip
python scripts/make_synthetic.py # synthetic frames + predictions
python scripts/run_ablation.py --frames data/synthetic/frames.pkl --preds data/synthetic/preds --out results/synthetic
python -m fittest.service serve --snapshot results/trust_snapshot.json --fake-models --port 8000
python scripts/story_numbers.py # critic values, run F lineages and absolute errors, from committed results
使用真实模型 Agent 的 CPU 虚拟机(托管 MCP 服务运行的环境:Ubuntu 24.04,8 个 vCPU,无 GPU):
bash scripts/setup_cpu.sh [WORKDIR] # core env (CPU torch + ALCHEMI Toolkit 0.3.0-rc + MACE + AIMNet2) and an Orb env
缓存的预测结果(data/frames.pkl、data/preds/、data/ckpt/,共 23 MB)已被 gitignore 忽略;请从运行了下方步骤 1 的机器上复制这些文件。之后,所有 CPU 结果步骤(2、5、7、图表、RESULTS.md)均可在没有 GPU 的情况下运行。
5.2 GPU(Colab L4),所有结果文件
bash scripts/setup_gpu.sh .. # toolkit 0.3.0-rc (cu13) + core env, Orb env, Transition1x (6.6 GB, md5-checked)
| 步骤 | 命令 | 写入内容 | L4 耗时 |
|---|---|---|---|
| 1 帧 + 预测 | python scripts/predict_pool.py --build-frames --models aimnet2,aimnet2_m0,aimnet2_m1,aimnet2_m2,aimnet2_m3,orb,mace_mpa0 --base-port 6000 | data/frames.pkl、data/preds/*.npz、results/predict_status.json | 约 2.5 分钟 |
| 2 信号分析 | python scripts/analyze_signal.py --frames data/frames.pkl --preds data/preds | results/signal.{json,png} | 数秒(CPU) |
| 3 运行中筛选 | python scripts/screen_alchemi.py --split pool --max-frames 600 --every 10 --n-steps 50 --score-labels --base-port 6100 | results/screen_alchemi.json | 131 秒 + 约 60 秒启动服务 |
| 4 批量 NEB | python scripts/run_neb.py --driver aimnet2 --base-port 6103 | results/neb.json、results/neb_sigma.png | 21 秒 + 约 60 秒 |
| 5 消融实验 | python scripts/run_ablation.py --frames data/frames.pkl --preds data/preds --out results/ --budget-per-round 40 --rounds 5 --seed 0 --budgets 20,40,80 | results/ablation*.{json,png}、blackboard_armD.jsonl、trust_snapshot.json、oracle_labels_armD.json | 约 12 秒(CPU) |
| 6 策展式修复 | python scripts/finetune.py --frames data/frames.pkl --labelled-uids results/oracle_labels_armD.json --model mace_mpa0 --out data/preds/mace_lora_curated.npz --ckpt data/ckpt/mace_lora_curated --epochs 40 --seed 0 --predict-uids all | data/preds/mace_lora_curated.npz、data/ckpt/mace_lora_curated/acceptance_report.json | 约 2 分钟 |
| 6′ B′ 种子 | 步骤 6,使用 --seeds 0,1,2,3 | data/preds/mace_seed{0..3}.npz | 约 6 分钟 |
| 7 再次进行消融实验 | 步骤 5(arm D 重放微调过程;B′ 使用这些种子) | results/ablation.* | 约 12 秒 |
| 8 报告 + 图表 | python scripts/write_results.py && python scripts/make_figures.py | results/RESULTS.md、results/fig/* | 数秒 |
| 9 服务演示 | python scripts/demo_service.py --snapshot results/trust_snapshot.json | results/service_demo.json | 约 1 分钟 |
| 10 演化,运行 A(MACE LoRA 后代) | python scripts/evolve.py --frames data/frames.pkl --preds data/preds --out results/evolution --seeds 0,1 --threads 2 --parallel 3 --python <core env python>,然后运行 python scripts/write_evolution_summary.py --evo results/evolution | results/evolution/(summary_tables.md、verdict.json、family_tree.json、generations.json) | 每个种子约 85 分钟(CPU) |
| 11 演化,运行 B(AIMNet2 后代 + 最新对照组) | python scripts/evolve.py --frames data/frames.pkl --preds data/preds --out results/evolution_aimnet --family aimnet2 --seeds 0,1 --controls newest --control-seeds 0,1 --python <core env python>,然后运行 write_evolution_summary.py --evo results/evolution_aimnet | results/evolution_aimnet/ | 每次种子运行约 5 分钟(CPU,--parallel 3) |
| 12 演化,运行 C(利基专家模型) | python scripts/evolve_c.py run --budget {200,400} --arms static,evolved --seeds 0,1 $O、--budget 800 --arms static,evolved,noselect --seeds 0 $O、--budget 800 --tag _s1 --arms static,evolved,noselect --seeds 1 $O,其中 O="--out results/evolution_c --core-python <core> --orb-python <orb> --gpu-slots 2 --parallel 3",然后运行 evolve_c.py summarize --out results/evolution_c。C′:使用 --out results/evolution_c/cpu_aimnet2_run --device cpu --families aimnet2 执行相同操作 | results/evolution_c/(summary.json、summary_table.md、fig9_budget.png) | 在一台 L4 上约 1 小时(两个进程);C′ 约 12 分钟(CPU) |
| 13 演化图表 | python scripts/make_evolution_figures.py --evo results/evolution --seed {0,1} --run-label A 和 --evo results/evolution_aimnet --run-label B;将输出重命名为 *_run{A,B}_s{0,1} | results/fig/fig7_evolution*.png、fig8_family_tree*.png | 数秒 |
arm-D 标签集由 md5 固定(ad5f14229a51679267d4fd9456feb589、docs/STATUS_core.md);v3 和 v4 报告变更未对其造成影响。环境变量(FITTEST_T1X、FITTEST_CORE_PYTHON、FITTEST_ORB_PYTHON、FITTEST_NEB_DIR、FITTEST_LOG_DIR)和每个步骤的详细信息:docs/REPRODUCE.md。
6. 仓库结构
fittest/
agents/ ModelAgent, Oracle, Skeptic, Calibrator, Curator, PoolStream, DisagreementMonitor
blackboard.py append-only event log (JSONL audit trail)
signals.py σ_F, errors, wrongness
candidates.py subset-mean candidates the Calibrator can serve
hook.py DisagreementHook (ALCHEMI Toolkit) + toolkit-agnostic DisagreementMonitor
model_server.py one process per model agent (own Python env if needed) + client
models/ Toolkit wrappers (batched MACE, AIMNet2 calculator, I/O)
mace_lora.py LoRA checkpoint format + loader
ablation.py arms, metrics, paired bootstrap
round_driver.py the clock
service.py trust service: score(), FastAPI app, CLI
mcp_server.py fittest-mcp (MCP tools: check_structures, explain, swarm_status, usage_stats)
usage_log.py privacy-preserving usage log of the MCP server
evolution.py evolutionary loop (fitness, selection, breeding, gate)
snapshots/ packaged Calibrator snapshot used by the MCP server
scripts/ GPU and CPU job scripts (see §5), setup_gpu.sh, setup_cpu.sh
results/ every number in this README; RESULTS.md; fig/; earlier versions v1–v3
docs/ DESIGN.md (contract), REPRODUCE.md, alchemi_api_notes.md, data_and_models.md, MCP.md
tests/ CPU pytest suite (synthetic data; no GPU or Transition1x needed)
deploy/ hosted MCP: Caddy (TLS) + systemd units for fittest-mcp and warm CPU model agents
隐私:托管 MCP 服务记录哪些日志
每个工具描述、服务说明以及每条 check_structures 响应都会概述此政策
(fittest/usage_log.py、docs/MCP.md):
- 每次调用记录(SQLite 中的一行):UTC 时间、工具(或
unknown)、传输方式、匿名客户端 ID、 内部测试标记、结构数量、原子数量、判定数量、每个结构的失败情况、延迟、 成功/错误状态,以及错误类别(input_error、invalid_arguments、unknown_tool、not_ready、rate_limited、busy、timeout或异常类型;绝不记录错误消息,因为其中可能包含输入)。每次调用都会记录,包括未知工具和架构验证失败。托管模式下,日志存储在 SQLite 数据库/var/lib/fittest-mcp/usage.sqlite中,由非特权系统用户fittest-mcp所有。 - 客户端 ID = HMAC-SHA256(密钥盐值,客户端名称 | 远程 IP),截取前 16 个十六进制字符。客户端版本不会纳入计算,因此升级或伪造版本字符串不会生成新 ID。盐值是随机的服务端文件(
/var/lib/fittest-mcp/salt,权限模式为 600,绝不提交到代码库),因此无法反推出 ID。托管模式下,IP 来自 Caddy,Caddy 会覆盖 X-Forwarded-For。 - 应用不会存储原始 IP,也不会将其写入访问日志:uvicorn 的访问日志已关闭,Caddy 的访问日志会删除远程 IP、客户端 IP、X-Forwarded-For、X-Real-IP、Forwarded、 Cf-Connecting-Ip 和 True-Client-Ip 字段。自 2026-10-31 19:11 UTC 起,Caddy 的错误日志和未映射主机日志也会删除这些字段;对任何其他主机名(例如裸 IP)的请求都会返回 404,且不会记录。在此之前,系统日志中有 140 条 Caddy 记录包含客户端 IP(9 个不同 IP:502 重启期间的 2 条错误记录,以及 138 条裸 IP 请求,其中大多来自扫描器);这些记录会一直保留到日志轮换。
- 绝不存储或记录:结构、坐标、元素列表、结构名称和结果。服务自身的日志行只包含工具名称以及错误类别或异常类型。一项测试会扫描数据库原始字节,查找预先植入的结构名称和坐标;另一项测试会检查失败调用是否未将输入写入日志。
- 用户 = 从
check_structures或explain收到至少一个结构判定的不同客户端 ID,不包括内部测试客户端(标头X-Fittest-Internal: 1;若某个客户端 ID 带有此标头出现过,则会将其登记为内部客户端)。调用swarm_status或usage_stats,以及所有结构都解析失败的调用,均不计入。迄今为止的所有测试都标记为内部测试。注意:共用公共 IP 和客户端名称的用户会合并为一个用户(例如办公室或场所的 Wi-Fi,以及 claude.ai / Claude Desktop 自定义连接器;它们通过 Anthropic 的共享出口 IP 发起调用,因此所有 claude.ai 用户可能会被计为一个用户);同一个人在多个网络或客户端上使用会被计为多次;从不同 IP 使用不同客户端名称仍可能虚增计数。应将其视为粗略的活跃度指标,而非人数。汇总计数公开于/stats。 - **发现并修复的隐私漏洞:**首次部署时,uvicorn 的访问日志未关闭,导致客户端 IP 写入 systemd 日志。之后关闭了访问日志并清理了日志;再次检查发现,测试客户端的 IP 在服务和 Caddy 日志以及 Caddy 访问日志中均未出现(0 次)。
- 本地(stdio)模式只会在你的设备上记录日志(
~/.fittest-mcp/usage.sqlite)。
许可证
MIT(LICENSE)。模型权重和数据集各自遵循其许可证。
致谢与参考资料
- NVIDIA ALCHEMI Toolkit 0.3.0-rc — 在途批处理、钩子、批量 NEB、LoRA 微调和验收报告。https://github.com/NVIDIA/nvalchemi-toolkit
- Transition1x — M. Schreiner、A. Bhowmik、T. Vegge、J. Busk、O. Winther,“Transition1x – a dataset for building generalizable reactive machine learning potentials”,Sci. Data 9,779(2022)。 doi:10.1038/s41597-022-01870-w
- MACE / MACE-MP — I. Batatia 等,“A foundation model for atomistic materials chemistry”,arXiv:2401.00096;I. Batatia、D. P. Kovács、G. N. C. Simm、C. Ortner、G. Csányi,“MACE: Higher order equivariant message passing neural networks for fast and accurate force fields”,NeurIPS 2022。检查点
medium-mpa-0。 - AIMNet2 — D. M. Anstine、R. Zubatyuk、O. Isayev,“AIMNet2: a neural network potential to meet your neutral, charged, organic, and elemental-organic needs”,Chem. Sci.(2025)。 doi:10.1039/D4SC08572H
- Orb-v3 — B. Rhodes 等,“Orb-v3: atomistic simulation at scale”,arXiv:2504.06231。检查点
orb-v3-conservative-inf-omat。 - LoRA — E. J. Hu 等,“LoRA: Low-rank adaptation of large language models”,arXiv:2106.09685。
- 关于基础 MLIP 异构委员会的最接近先例:Y. Liu 等,“Heterogeneous ensemble enables a universal uncertainty metric for atomistic foundation models”,arXiv:2507.21297。基于委员会的查询式主动学习:J. S. Smith 等,J. Chem. Phys. 148,241733(2018)。更多内容见
docs/data_and_models.md。 - 借鉴自大模型的模式:J. Wang 等,“Mixture-of-Agents enhances large language model capabilities”,arXiv:2406.04692;与多 Agent 辩论的对比:Y. Du 等,“Improving factuality and reasoning in language models through multiagent debate”,arXiv:2305.14325。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。