ATOM框架:基于树搜索与智能体协同的分子多目标优化

ATOM框架:基于树搜索与智能体协同的分子多目标优化
1. 项目概述当分子优化遇上“多目标”与“树形智能体”在药物发现、材料设计这些硬核领域里我们常常面临一个经典困境你费尽心思优化一个分子让它对某个靶点的活性比如抑制某种病毒达到了极致结果却发现它的水溶性差到根本没法做成药或者合成路线复杂得像个迷宫成本高得吓人。这就是典型的**多目标优化Multi-Objective Optimization, MOO**问题——你手里不止一个“KPI”它们往往相互冲突此消彼长。传统的做法要么是“拍脑袋”给不同目标分配权重强行揉成一个综合分数要么是像无头苍蝇一样在庞大的化学空间里随机试错效率低下且难以获得真正均衡的优质解。最近一个结合了智能体Agents与树Tree搜索思想的新框架——ATOMAgents on a Tree for Molecular Optimization为解决这个难题提供了一条清晰、高效的路径。简单来说它不再把分子优化看作一个“黑箱”的数值优化问题而是模拟一群有策略的“化学家”智能体在一棵不断生长的“决策树”上协同探索。每个智能体负责推进分子结构沿着某个特定方向比如提高活性进行修改而整棵树则记录了所有可能的修改路径和结果。通过这种路径协同Pathwise Coordination机制系统能系统地探索如何平衡多个目标最终找到一系列在活性、可合成性、毒性等多个维度上都表现不错的“帕累托最优”分子。这不仅仅是又一个“AI for Science”的噱头。ATOM的核心价值在于它将抽象的优化问题转化为了一个可解释、可干预、可并行化的搜索过程。对于药物化学家而言这意味着你可以清晰地看到分子是如何一步步被改进的理解每一步修改的意图是哪个智能体驱动的甚至可以在关键节点进行人工引导。它适合任何需要在庞大、离散的化学空间中进行多目标、理性设计的场景无论是寻找新的先导化合物还是优化已知材料的性能。2. ATOM框架的核心设计思路拆解2.1 为什么是“树”而不是“黑箱”在深入ATOM的细节之前我们必须先理解它选择“树”作为核心数据结构的深层逻辑。化学空间本质上是离散且组合爆炸的。一个分子由原子和化学键构成每一次修改比如增加一个甲基、替换一个官能团都像是走到一个岔路口选择一条分支。传统的深度生成模型如VAE、GAN或强化学习RL通常将分子编码为一个连续的向量在这个“潜空间”里进行优化。虽然高效但这个过程像个黑箱你输入起点和终点模型直接给你一个结果中间的演变路径模糊不清且修改可能不符合化学规则比如产生不合理的价键。树形结构完美地契合了化学空间这种组合式、分步演进的特性。在ATOM中树的根节点是初始分子。每一个子节点都代表对父节点分子进行一次合理的、单步的化学修改我们称之为“动作”。这样从根节点到任意一个叶子节点的路径就是一系列具体的、可追溯的化学操作序列。这种设计的优势显而易见可解释性与可追溯性任何被发现的优秀分子你都能回溯它的完整“合成”或“修饰”路径知道是哪一步修改带来了关键性的提升。这对于化学家理解结构-活性关系SAR至关重要。保证化学合理性每一步动作都可以由基于规则的化学引擎或经过训练的生成模型来保证确保生成的子节点分子在化学上是有效的避免了黑箱模型可能产生的荒谬结构。自然支持多目标探索不同的优化目标如活性、类药性可以引导智能体探索树的不同分支。树结构使得我们可以同时维护和比较通往不同目标的多种路径。2.2 “智能体”在树上扮演什么角色ATOM中的“智能体Agents”并非完全独立的、拥有复杂策略的AI实体。在这里它们更贴切地可以被理解为具有特定偏好的搜索引导器。通常我们会为每一个优化目标配备一个或多个智能体。例如在药物优化中我们可能有三个智能体Agent_A主攻活性、Agent_S主攻可合成性、Agent_T主攻低毒性。每个智能体的核心职责是评估和选择。当搜索进行到树的某个节点即一个候选分子时评估智能体会根据自己负责的目标对这个分子进行打分。例如Agent_A会调用一个活性预测模型来打分。选择智能体会基于评估分数决定从当前节点出发应该优先探索哪些“动作”来生成子节点。它可能倾向于选择那些预计能最大程度提升自身目标分数的动作。关键在于这些智能体并非各自为战。它们共享同一棵搜索树。Agent_A探索到的、活性很高的分支可能会被Agent_S“看到”并尝试在其基础上进行提高可合成性的修改。这种通过共享树结构实现的隐式通信与协同就是“Pathwise Coordination”的精髓。智能体们沿着不同的优化维度推进搜索但它们的工作成果即树上的节点和路径是共享的从而能够发现那些能同时满足多个目标的折衷路径。2.3 多目标优化的核心帕累托前沿的搜寻多目标优化的目标不是找到一个“最好”的解而是找到一组帕累托最优Pareto Optimal解集也称为帕累托前沿Pareto Front。一个解是帕累托最优的意味着在没有任何一个目标性能变差的情况下无法再改进任何一个其他目标。ATOM框架搜寻帕累托前沿的策略非常直观并行播种从初始分子根节点开始多个智能体同时开始探索。路径评分与选择不仅对单个节点评分更对从根节点到该节点的整条路径进行多目标综合评价。一条路径的“好坏”取决于它末端分子在各个目标上的表现。前沿维护与聚焦算法会动态维护一个当前发现的近似帕累托前沿。搜索资源如计算时间会倾向于分配给那些有可能改进当前前沿的路径和节点。例如一个分子如果在某个目标上很差但在另一个目标上极具潜力它仍然可能获得探索机会因为它有可能通过后续修改“补齐短板”从而挤进前沿。这种基于树和路径的搜索使得我们能够系统地探索目标空间的不同区域而不是收敛到某个单一的、可能过度偏向某个目标的解。3. ATOM实现的关键技术环节与实操要点3.1 分子表示与动作空间定义要让智能体在树上“行走”我们首先要定义树的“枝干”是什么即动作空间Action Space。分子表示通常采用SMILES字符串或分子图Graph。SMILES字符串简洁易于处理分子图则能更自然地表示结构信息更适合图神经网络。在ATOM的实现中分子图更为常见因为化学修改动作可以很直观地定义为对图节点的增加、删除或修改。动作空间定义这是保证化学合理性的第一道关卡。常见的动作类型包括原子/官能团添加在指定位置添加一个原子如C、N、O或一个预定义的官能团如-OH、-CH3。原子/官能团删除移除一个原子或官能团需保证剩余分子依然有效。键的修改改变两个原子之间的键型单键、双键、三键。环的构建或打开这是一个高级动作能显著改变分子骨架。实操心得定义动作空间时约束比自由更重要。初期不要追求动作类型的全面而应基于化学常识进行严格限制。例如禁止生成五价碳、禁止在芳香环上随意添加双键等。可以使用RDKit这样的化学信息学工具包来验证每个动作产生的子节点分子是否“合法”通过SanitizeMol检查。一个常见的技巧是维护一个“允许添加的官能团”列表这个列表可以来自类似ChEMBL的常见药效团以保证生成分子的类药性。3.2 智能体的策略如何评估与选择每个智能体需要一个“大脑”来指导行动即策略函数。这个函数输入当前节点分子输出对可能动作的偏好评分。实现方案通常有两种基于模型的预测器为每个目标训练一个独立的预测模型。例如用图神经网络GNN训练一个活性预测模型给Agent_A使用用基于规则的计算器如SA Score评估合成复杂度给Agent_S使用。智能体的策略就是选择那些能让预测分数提升最大的动作。基于多臂老虎机的选择器将每个可能的动作视为一个“老虎机臂”。智能体通过多次尝试探索来估计每个动作的“期望奖励”即平均能带来多少目标分数提升。然后使用UCBUpper Confidence Bound等算法来平衡“利用”选择当前估计最好的动作和“探索”尝试次数少的动作。在ATOM中更常用的是第一种与第二种的结合用预测模型给出期望奖励的估计再用探索策略如epsilon-greedy来决定最终选择哪个动作。动作的生成与筛选从一个分子出发可能的化学修改是海量的。不可能全部枚举。因此需要有一个候选动作生成器。这可以是一个基于规则的枚举器如枚举所有可能添加的官能团位置也可以是一个小的生成式模型如一个经过训练的分子翻译模型。生成一批候选动作比如50-100个后再由智能体的策略函数进行快速评分和排序选择Top-K个进行实际展开生成子节点。3.3 树搜索算法的具体实现ATOM的核心搜索流程可以看作一个多智能体协同的蒙特卡洛树搜索MCTS变体。以下是其核心循环的伪代码逻辑# 初始化 tree Tree(root_molecule) pareto_front [] # 帕累托前沿存储分子 多目标分数向量 for episode in range(total_episodes): # 1. 选择 (Selection) # 从根节点开始根据多目标权衡策略如帕累托优势比较、标量化权重选择一条待扩展的路径和叶子节点。 leaf_node tree.select_leaf_node_using_multi_objective_policy() # 2. 扩展 (Expansion) # 如果该叶子节点未被充分探索则为其生成子节点。 if leaf_node.visit_count expansion_threshold: # 各智能体为当前叶子节点分子生成候选动作并评分 candidate_actions [] for agent in agents: actions_for_this_agent agent.propose_actions(leaf_node.molecule) candidate_actions.extend(actions_for_this_agent) # 去重并根据某种聚合策略如加权和、帕累托排序选择最佳的几个动作进行扩展 selected_actions aggregate_and_select(candidate_actions, aggregation_strategy) for action in selected_actions: new_molecule apply_action(leaf_node.molecule, action) if is_valid(new_molecule): new_node tree.create_child_node(leaf_node, new_molecule, action) # 3. 模拟/评估 (Simulation/Evaluation) # 对新节点进行多目标评估调用各目标的预测模型 score_vector evaluate_multi_objective(new_molecule) new_node.scores score_vector # 更新帕累托前沿 update_pareto_front(pareto_front, new_molecule, score_vector) # 4. 回溯 (Backpropagation) # 将新节点的评估信息分数、帕累托改进信息沿着路径回溯到根节点更新路径上节点的统计信息如访问次数、平均分数向量。 # 这有助于后续的选择策略更偏向于有潜力的方向。 tree.backpropagate(leaf_node, score_vector) # 最终从帕累托前沿中输出优化后的分子集合。 return pareto_front关键参数与设计选择aggregation_strategy聚合策略如何综合不同智能体的建议简单加权求和需要预设权重、按帕累托层级筛选、还是让智能体轮流主导这是一个需要根据问题调优的超参数。expansion_threshold控制探索与利用。阈值太高树扩展慢阈值太低搜索可能过于贪婪陷入局部最优。回传信息在标准MCTS中回传的是模拟得到的胜率。在ATOM中回传的可以是多目标分数向量或者一个标量化的“改进量”例如新节点是否支配了父节点是否进入了帕累托前沿。3.4 多目标评估与帕累托前沿管理评估模块是驱动搜索的“指挥棒”。每个目标都需要一个快速、相对准确的评估器oracle。高保真度评估器例如基于物理的模拟计算结合能、真实的实验数据。这些通常计算成本高无法用于每一步评估。代理模型Surrogate Model这是ATOM能运行的关键。我们为每个目标训练一个快速的机器学习预测模型如GNN、随机森林用于在搜索过程中进行成千上万次的评估。这些代理模型需要在搜索开始前用一个初始分子数据集进行预训练并在搜索过程中可以定期用新发现的高质量分子进行在线更新主动学习。帕累托前沿的动态管理是一个算法核心。我们需要一个高效的数据结构如使用Deb的NSGA-II中的快速非支配排序来维护和更新前沿。在树搜索的选择阶段我们可以设计策略来优先选择那些能产生“前沿贡献者”的路径。例如一个节点的“价值”可以根据其支配的区域内未探索空间的大小来评估。4. 实战构建从零搭建一个简易ATOM原型假设我们的目标是优化一个分子同时提升其药物活性Predicted pIC50和水溶性LogS。我们将使用RDKit处理化学用简单的随机森林作为代理模型实现一个高度简化的ATOM流程。4.1 环境准备与依赖安装# 创建虚拟环境 conda create -n atom_moo python3.9 conda activate atom_moo # 安装核心依赖 pip install rdkit-pypi pip install scikit-learn pip install numpy pandas pip install networkx # 用于构建树结构4.2 定义分子、动作与评估器import rdkit.Chem as Chem from rdkit.Chem import AllChem, Descriptors from rdkit.Chem.Draw import IPythonConsole from sklearn.ensemble import RandomForestRegressor import numpy as np class MolecularNode: 树节点类存储分子及其信息 def __init__(self, smiles, parentNone, actionNone): self.smiles smiles self.mol Chem.MolFromSmiles(smiles) if isinstance(smiles, str) else smiles self.parent parent self.action action # 从父节点到此节点所执行的动作 self.children [] self.scores {} # 存储各目标分数如 {pIC50: 6.5, LogS: -3.2} self.visit_count 0 def add_child(self, child_node): self.children.append(child_node) # 定义简单的动作空间在某个原子上添加几个常见官能团 ALLOWED_FRAGMENTS_SMILES [[CH3], [OH], [NH2], [F], [Cl], CO, C#N] def get_possible_actions(node): 为一个分子节点生成所有可能的单步添加动作 actions [] mol node.mol if mol is None: return actions # 遍历分子中每个非氢原子作为连接点 for atom_idx in range(mol.GetNumAtoms()): atom mol.GetAtomWithIdx(atom_idx) # 这里简化处理只考虑在非芳香碳、氮、氧上连接 if atom.GetSymbol() in [C, N, O] and not atom.GetIsAromatic(): for frag_smi in ALLOWED_FRAGMENTS_SMILES: # 创建一个动作描述在原子idx上连接片段frag_smi action (attach, atom_idx, frag_smi) actions.append(action) return actions def apply_action(node, action): 应用动作生成新的分子SMILES action_type, atom_idx, frag_smi action mol Chem.RWMol(node.mol) frag_mol Chem.MolFromSmiles(frag_smi) if frag_mol is None: return None # 将片段合并到母体分子上这里是非常简化的合并实际需处理连接点和价态 # 注意这是一个示意性函数真实的分子合并需要更复杂的化学逻辑如处理连接键、氢原子等 # 此处为演示我们直接生成一个无效的SMILES实际项目应使用RDKit的CombineMols等函数 combined_smiles f{Chem.MolToSmiles(node.mol)}.{frag_smi} # 错误示例仅示意 # 应使用new_mol Chem.CombineMols(node.mol, frag_mol) 并正确连接 # 这里我们跳过复杂实现假设有一个函数 connect_fragment 能正确连接 try: new_mol connect_fragment(node.mol, atom_idx, frag_mol) # 假设的函数 new_smiles Chem.MolToSmiles(new_mol) if new_smiles and Chem.MolFromSmiles(new_smiles): # 验证有效性 return new_smiles except: pass return None # 代理评估器示例用随机森林实际需用真实数据训练 class SurrogateEvaluator: def __init__(self): self.model_pIC50 RandomForestRegressor() self.model_LogS RandomForestRegressor() # 这里应有一个用初始数据集训练模型的过程此处省略 # self.train(models, initial_dataset) def predict(self, smiles_list): 预测一批分子的pIC50和LogS # 特征提取简化版使用RDKit描述符 features [] valid_smiles [] for smi in smiles_list: mol Chem.MolFromSmiles(smi) if mol: # 计算一些简单的2D描述符作为特征 feat [ Descriptors.MolWt(mol), Descriptors.NumHAcceptors(mol), Descriptors.NumHDonors(mol), Descriptors.TPSA(mol), Descriptors.MolLogP(mol), ] features.append(feat) valid_smiles.append(smi) features np.array(features) # 使用预训练的模型进行预测此处为模拟返回值 pred_pIC50 np.random.rand(len(features)) * 4 5 # 模拟5-9之间的值 pred_LogS np.random.randn(len(features)) # 模拟正态分布值 return {smi: {pIC50: p, LogS: l} for smi, p, l in zip(valid_smiles, pred_pIC50, pred_LogS)}4.3 实现协同树搜索循环import random from collections import defaultdict class SimpleATOM: def __init__(self, root_smiles, evaluator, agents_weights): agents_weights: 字典定义每个智能体目标的偏好权重如 {pIC50: 0.7, LogS: 0.3} self.root MolecularNode(root_smiles) self.evaluator evaluator self.agents_weights agents_weights self.objectives list(agents_weights.keys()) self.tree_nodes {root_smiles: self.root} self.pareto_front [] # 存储节点 分数向量 # 初始化根节点分数 init_scores self.evaluator.predict([root_smiles]).get(root_smiles, {k:0 for k in self.objectives}) self.root.scores init_scores self.pareto_front.append((self.root, list(init_scores.values()))) def is_dominated(self, scores_vec_a, scores_vec_b): 判断分数向量a是否被b支配假设所有目标都是最大化 # b支配a的条件b在所有目标上都不差于a且至少在一个目标上严格优于a not_worse all(b a for a, b in zip(scores_vec_a, scores_vec_b)) strictly_better any(b a for a, b in zip(scores_vec_a, scores_vec_b)) return not_worse and strictly_better def update_pareto_front(self, node): scores_vec [node.scores.get(obj, 0) for obj in self.objectives] new_front [] is_dominated_flag False for front_node, front_vec in self.pareto_front: if self.is_dominated(scores_vec, front_vec): # 新节点被前沿中某个节点支配不加入 is_dominated_flag True new_front.append((front_node, front_vec)) elif not self.is_dominated(front_vec, scores_vec): # 互不支配保留旧的前沿节点 new_front.append((front_node, front_vec)) # 如果新节点支配旧节点旧节点将被丢弃不加入new_front if not is_dominated_flag: # 新节点不被任何现有前沿节点支配加入前沿 new_front.append((node, scores_vec)) # 移除被新节点支配的节点在上面的循环中已实现 self.pareto_front new_front def select_node(self): 简化版选择策略从当前所有叶子节点中根据UCB分数选择 leaf_nodes [n for n in self.tree_nodes.values() if not n.children] # 简单获取叶子节点 if not leaf_nodes: return self.root # 计算每个叶子节点的UCB分数这里用多目标加权和作为价值Q ucb_scores [] for node in leaf_nodes: # Q值各目标分数的加权和 q_value sum(node.scores.get(obj, 0) * self.agents_weights[obj] for obj in self.objectives) # UCB公式: Q c * sqrt(ln(parent_visits) / node_visits) c 1.414 # 探索常数 parent_visits node.parent.visit_count if node.parent else 1 exploit q_value explore c * np.sqrt(np.log(parent_visits 1) / (node.visit_count 1e-5)) ucb exploit explore ucb_scores.append(ucb) selected_idx np.argmax(ucb_scores) return leaf_nodes[selected_idx] def expand_and_evaluate(self, node, num_expand3): 扩展选中的节点 possible_actions get_possible_actions(node) if not possible_actions: return # 为每个动作让每个“智能体”评估其期望价值简化用随机分数模拟 action_scores defaultdict(list) for action in possible_actions: # 模拟应用动作并预测这里简化直接随机生成一个目标分数变化量 for obj in self.objectives: # 模拟智能体评估这个动作可能对该目标带来的增益 # 实际中这里应该调用一个快速评估函数可能基于子结构指纹或轻量级模型 score_delta random.uniform(-0.5, 1.0) # 随机增益 action_scores[action].append(score_delta) # 聚合各智能体的评分加权求和 aggregated_scores {} for action, scores in action_scores.items(): aggregated sum(s * w for s, w in zip(scores, self.agents_weights.values())) aggregated_scores[action] aggregated # 选择得分最高的几个动作进行实际扩展 top_actions sorted(aggregated_scores.items(), keylambda x: x[1], reverseTrue)[:num_expand] new_nodes [] for action, _ in top_actions: new_smiles apply_action(node, action) if new_smiles and new_smiles not in self.tree_nodes: child_node MolecularNode(new_smiles, parentnode, actionaction) node.add_child(child_node) self.tree_nodes[new_smiles] child_node new_nodes.append(child_node) # 批量评估新节点 if new_nodes: smiles_list [n.smiles for n in new_nodes] score_dict self.evaluator.predict(smiles_list) for node in new_nodes: node.scores score_dict.get(node.smiles, {}) self.update_pareto_front(node) node.visit_count 1 node.visit_count 1 def search(self, iterations100): 主搜索循环 for i in range(iterations): selected_node self.select_node() self.expand_and_evaluate(selected_node) if i % 20 0: print(fIteration {i}, Pareto Front size: {len(self.pareto_front)}) # 搜索结束后返回帕累托前沿上的分子 pareto_molecules [node for node, _ in self.pareto_front] return pareto_molecules # 运行示例 if __name__ __main__: root_smi CC(O)Oc1ccccc1C(O)O # 阿司匹林SMILES作为起点 evaluator SurrogateEvaluator() # 需替换为真实训练的评估器 atom_optimizer SimpleATOM(root_smi, evaluator, agents_weights{pIC50: 0.6, LogS: 0.4}) results atom_optimizer.search(iterations50) print(f搜索完成找到 {len(results)} 个帕累托最优候选分子。) for i, node in enumerate(results[:5]): # 打印前5个 print(f{i1}. SMILES: {node.smiles}, Scores: {node.scores})注意以上代码是一个高度简化的概念验证原型。真实的ATOM实现涉及大量细节如正确的分子操作库使用RDKit的Chem.ReplaceSubstructs、Chem.CombineMols等、高效的化学空间动作枚举、准确的代理模型、更复杂的树策略如基于帕累托排序的选择以及并行化扩展。此代码旨在阐明工作流程不可直接用于生产。5. 常见问题、挑战与进阶优化方向在实际操作中即使理解了框架也会遇到诸多挑战。以下是一些常见问题及解决思路。5.1 化学空间的动作枚举爆炸问题问题即使是一个中等大小的分子可能的单步修改位置和片段组合也极其庞大生成所有候选动作在计算上不可行。解决方案基于反应的模板不枚举所有原子-片段连接而是使用一组预定义的、化学上合理的反应模板如来自USPTO数据库的常见反应。这极大地缩小了动作空间并保证了生成分子的可合成性。这是目前主流方法。生成式模型引导训练一个条件生成模型如Graph-to-Graph模型输入当前分子和目标如“提高活性”直接输出几个最有可能的修改后分子。用生成模型代替穷举枚举。启发式过滤在枚举后使用快速的、基于规则的过滤器如排除分子量激增、脂水分配系数LogP过高的修改提前淘汰大部分不良候选。5.2 代理模型不准导致的搜索偏差问题代理模型的预测误差会误导智能体的选择可能使搜索偏离真正的高质量区域。解决方案不确定性估计使用能提供不确定性估计的模型如高斯过程、贝叶斯神经网络、集成模型。在树搜索中可以倾向于探索那些代理模型预测不确定性高的区域探索或者预测值高且置信度高的区域利用。主动学习与在线更新定期将搜索中发现的新分子用高保真但昂贵的方法如实验、精确计算进行评估并将这些新数据点加入训练集重新训练或微调代理模型使其在感兴趣的区域越来越准。多保真度代理维护多个不同计算成本和精度的代理模型。在搜索初期或快速筛选时使用廉价模型对进入“决赛圈”的候选分子再用更精确的模型复核。5.3 多目标间的权衡与聚合策略问题如何聚合不同智能体的建议固定的权重如{pIC50: 0.6, LogS: 0.4}可能无法找到多样化的帕累托解。解决方案帕累托排序选择在树的选择阶段不进行标量化聚合。而是比较不同路径末端分子的帕累托层级使用快速非支配排序优先选择非支配层级高的路径。这能更好地维持解的多样性。权重动态调整运行多个并行的搜索线程每个线程使用不同的权重向量例如从均匀分布中采样。这本质上是权重和方法能有效地扫描整个帕累托前沿。基于参考点的搜索允许用户指定一个“理想点”即各个目标的期望值然后搜索最小化到该理想点距离如切比雪夫距离的分子。这更符合实际项目中“有明确指标要求”的场景。5.4 计算效率与并行化问题树搜索和分子评估即使是代理模型可能很耗时如何加速解决方案异步并行树搜索多个工作进程同时进行选择-扩展-评估-回传循环并异步地更新共享的树结构和帕累托前沿。需要处理好并发访问的锁问题。批量评估不要逐个分子调用评估模型而是收集一批候选分子后进行批量预测充分利用GPU或CPU的并行计算能力。树结构的剪枝定期对树进行剪枝移除那些被严重支配所有目标都差于其他节点且访问次数很少的子树释放内存。5.5 与实验闭环的集成问题ATOM最终的目的是指导真实实验如何将计算与实验结合解决方案构建一个计算-实验自动化闭环。ATOM计算平台输出一批如10-20个帕累托前沿上的候选分子。自动化合成与测试平台如流动化学、高通量筛选对这些分子进行实验验证。将实验得到的真实数据活性、溶解度等反馈回系统用于更新代理模型并作为新的搜索起点。迭代进行让模型在真实数据的反馈下不断进化越来越准。这种闭环能将“试错”过程从实验室转移到计算机模拟中大幅降低实验成本加速研发周期。

最新新闻

日新闻

周新闻

月新闻