公司动态
MetaboLLM:用大语言模型构建代谢物预测图,打通代谢组学数据分析新路径
之前在分析代谢组学数据时我一直被一个问题困住质谱仪下机后得到的代谢物列表虽然名称、分子式、峰面积都清清楚楚但要让这些孤立的化合物产生生物学意义往往需要人工去翻数据库、查通路、比对文献。一个包含几百个代谢物的项目光做功能注释和通路富集就要花掉好几天而且很多代谢物之间是否存在上下游关系靠肉眼根本看不出来。最近读到 MetaboLLM 相关的工作它专门面向代谢组学场景把大语言模型LLM的生化知识理解能力和图结构结合起来用来做生化知识集成以及预测性代谢物图构建。这篇文章就把我理解到的核心思路、技术链路和一套可运行的模拟验证流程整理出来。不管你是做代谢组学数据分析的还是研究大模型垂直领域应用的都可以参考这条路径。1. 背景代谢组学与知识图谱的碰撞1.1 代谢组学到底在分析什么代谢组学Metabolomics研究的是生物体内所有小分子代谢物的集合。这些代谢物包括氨基酸、脂质、有机酸、糖类、核苷酸等分子量通常在 1000 Da 以下。与基因组学、转录组学相比代谢组学离生物表型更近因为代谢物本身就是细胞活动的直接产物。在实际项目中代谢组学的常见任务是发现疾病相关的差异代谢物。解析代谢通路中哪些节点发生了改变。通过代谢物之间的网络关系推测可能的生物学机制。结合转录组、蛋白组进行多组学联合分析。但问题是代谢组学数据本身是多层次、高噪声的。一个代谢物可能参与多条通路一个通路又关联多个代谢物。要把这些关系梳理清楚传统做法高度依赖人工知识库比如 HMDB、KEGG、MetaCyc 等。1.2 传统代谢物分析流程的三大痛点痛点一注释结果碎片化。质谱鉴定出来的代谢物通常只有一个 ID 和一套表征信息但这些代谢物在哪些通路中出现、由哪些酶催化、上下游是什么信息分散在多个数据库里整理起来非常耗时。痛点二功能注释依赖人工规则。在做富集分析时我们通常先把代谢物映射到 KEGG ID 或 HMDB ID再做通路富集。一旦代谢物名称不规范或者数据库 ID 匹配不上这条代谢物就容易被当成“未知物”丢掉。痛点三缺乏动态关联能力。传统知识库是静态的代谢物之间的关系是预先定义好的。如果你希望根据当前实验的特定上下文发现一些新的代谢物关联静态知识库帮不上忙。1.3 为什么 LLM 能切入代谢组学大语言模型在自然语言和生物文本上学习了大量隐含知识。它能够理解“alpha-ketoglutarate 是 TCA 循环的中间产物”“L-phenylalanine 可以转化为 tyrosine”这类生化描述并且能把不同来源的文本知识统一成结构化关系。MetaboLLM 的设计目标很直接利用 LLM 的生化知识理解能力把非结构化的代谢物信息与结构化的代谢通路知识融合起来然后构建一个可预测的代谢物图。这个图不仅反映已知关系还能对缺失的代谢物关联进行预测帮助研究者缩短从数据到机制解释的链路。2. MetaboLLM 核心概念2.1 MetaboLLM 是什么MetaboLLM 的全称是 A metabolomics-specialized large language model for biochemical knowledge integration and predictive metabolite graph construction。从名字可以看出这个模型不是一个简单的对话机器人而是面向代谢组学场景的专用 LLM 系统。它的核心能力可以拆成两块生化知识集成把代谢物注释文本、通路数据库、文献描述等异构知识统一整合到模型可计算的表示空间中。预测性代谢物图构建基于整合后的知识构建一个以代谢物为节点、生化关系为边的图并具备预测潜在边或潜在节点的能力。如果把整个系统看作一条流水线输入是代谢物文本信息输出是一个代谢物关系图以及图上的预测结果。2.2 生化知识集成Biochemical Knowledge Integration生化知识集成的难点不在“存储”而在“对齐”。同一代谢物在不同数据库里有不同写法。例如Citric acidCitrate柠檬酸CHEBI:30769C00158KEGG这些其实指向同一个化合物。LLM 的作用是把这些变体统一映射到一个标准化表示上同时补充每个代谢物的生化特征例如参与的通路、催化的酶、上下游产物。在实际设计上知识集成通常包括代谢物实体识别从自由文本中抽取出代谢物名称。实体标准化将别名映射到标准 ID。关系抽取从句子中提取“催化”“转化为”“参与通路”等关系。知识融合将抽取结果和数据库记录合并形成统一的知识表示。2.3 预测性代谢物图构建Predictive Metabolite Graph Construction图构建的目标是得到一张代谢物关系图 G (V, E)其中 V 是代谢物节点E 是代谢物之间的生化关系边。传统方法构建的图大多来自已知通路边是人工注释的。MetaboLLM 的“预测性”体现在两个方面边预测对于图中不存在的代谢物对根据它们的表示向量相似度和通路上下文预测是否可能存在生化关系。节点预测输入一个新的代谢物判断它应该被插入到图的哪个位置比如属于哪条通路、在哪两个代谢物之间发生转化。这种预测能力对非模式生物、稀有样本、新化合物注释场景特别有价值因为这些情况下可供参考的已知关系非常少。2.4 与通用 LLM 的区别通用 LLM 也可以回答“什么是柠檬酸循环”但它的知识是宽泛的不会针对代谢组学数据做深度消歧、不会输出图结构、也不会根据质谱鉴定结果去推理代谢物间的可能关系。MetaboLLM 这类垂直模型通常需要在通用大模型基础上做领域微调或设计专门的提示词和结构化输出头让模型输出可被机器解析的图格式而不是自然语言段落。如果只是简单使用 ChatGPT 问几个代谢通路问题那和 MetaboLLM 不是一个层面的东西。后者是一个可嵌入分析流水线的计算组件。3. 环境准备与项目规划3.1 实验环境说明MetaboLLM 本身并不是一个已经打包好的 pip 库论文或开源实现通常会拆分为模型调用层、知识融合层、图构建层。下面我的示例环境以通用数据科学环境为例不绑定具体版本重点展示流程设计思路。如果你的项目希望完整复现建议准备操作系统Ubuntu 20.04 / 22.04macOS 也可。Python3.9 以上。深度学习环境支持 PyTorch 的 GPU 机器可选如果只做推理则 CPU 也可以。大模型推理可以使用本地部署的开源模型也可以通过 API 访问服务商模型。图分析工具NetworkX、pandas、matplotlib。注意本文示例代码不依赖 MetaboLLM 官方仓库而是模拟其核心工作流方便你在还没有开放权重或接口的情况下理解原理。3.2 推荐工具链用途推荐工具说明数据处理pandas、numpy读取代谢物列表、特征矩阵大模型调用transformers / openai SDK生化知识抽取、标准化图构建networkx创建图、计算度、连通性分析可视化matplotlib、pyvis绘制代谢物网络图路径预测scikit-learn简单相似度或分类模型实验记录jupyter notebook / vscode分步调试和记录3.3 项目目录结构我建议把整个工作流拆成独立模块方便后续替换数据源或模型接口。metabollm_demo/ ├── data/ │ ├── metabolites.csv # 输入的代谢物列表 │ └── pathway_reference.csv # 通路参考知识 ├── src/ │ ├── preprocessing.py # 代谢物文本标准化 │ ├── llm_integration.py # LLM 知识抽取 │ ├── graph_builder.py # 代谢物图构建 │ ├── predictor.py # 边预测和路径预测 │ └── visualize.py # 图可视化 ├── output/ │ ├── graph.pkl │ └── metabolic_graph.png └── main.py这套结构的好处是每层都可以单独测试。即使你现在没有可用的 LLM 接口也可以先构建图结构再逐步替换知识补全模块。4. 核心原理拆解从文本到图的完整链路4.1 代谢物文本标准化第一步是把输入数据整理成 LLM 能理解的形式。原始质谱导出的代谢物列表通常长这样代谢物KEGG_ID样本1峰面积样本2峰面积L-PhenylalanineC000791523.41890.2Pyruvic acidC0002288.3102.5在喂给模型之前需要做标准化标识。比如把“Pyruvic acid”统一为“pyruvate”把“L-Phenylalanine”统一为“phenylalanine”。这一步的目的是减少 LLM 对名称变体的敏感度。复用代码片段# 文件路径src/preprocessing.py import re import pandas as pd ALIAS_MAP { pyruvic acid: pyruvate, citric acid: citrate, alpha-ketoglutarate: 2-oxoglutarate, } def normalize_metabolite_name(name: str) - str: name name.strip().lower() name re.sub(r\s, , name) return ALIAS_MAP.get(name, name) def load_metabolite_file(path: str) - pd.DataFrame: df pd.read_csv(path) df[normalized_name] df[metabolite].apply(normalize_metabolite_name) return df这里的 ALIAS_MAP 可以根据项目实际使用的数据库扩展。对于大型项目可以考虑用 KEGG API 或 HMDB 的别名表做全量映射。4.2 生化知识抽取与融合标准化之后的代谢物信息并不包含“代谢物之间的关系”。这一步需要借助 LLM 从文本或知识库描述中抽取关系三元组。关系三元组形式(代谢物A, 关系类型, 代谢物B) (代谢物A, 参与通路, 通路名称) (代谢物A, 催化酶, 酶名称)为了让模型输出固定结构最好在提示词中定义 JSON 输出格式。示例提示词模板如下你是一个代谢组学知识抽取助手。给定代谢物名称请输出该代谢物的生化知识包括 1. 参与的代谢通路pathways 2. 在该通路中的上下游代谢物neighbors 3. 可能参与的酶enzymes 请严格使用 JSON 格式输出不要输出额外文本。下面是调用大模型接口的示意代码使用通用的 API 风格# 文件路径src/llm_integration.py import json from typing import Dict, Any def build_prompt(metabolite_name: str) - str: return f你是一个代谢组学知识抽取助手。给定代谢物名称请输出该代谢物的生化知识。 代谢物{metabolite_name} 请返回如下 JSON 结构 {{ pathways: [通路名称], neighbors: [下游代谢物名称], enzymes: [酶名称] }} def extract_biochemical_knowledge( metabolite_name: str, llm_completion_fn, ) - Dict[str, Any]: prompt build_prompt(metabolite_name) response llm_completion_fn(prompt) try: return json.loads(response) except json.JSONDecodeError: # 如果模型输出不规范做一次容错处理 return {pathways: [], neighbors: [], enzymes: []}这里的llm_completion_fn是一个占位函数你需要根据实际使用的模型封装。如果使用 Hugging Face transformers可以参考如下方式封装# 文件路径src/llm_integration.py补充示例 from transformers import pipeline pipe pipeline(text-generation, modelyour-model-path) def local_llm_completion(prompt: str) - str: output pipe(prompt, max_new_tokens200, do_sampleFalse) return output[0][generated_text]注意不同模型对 JSON 输出的稳定性差异很大生产环境建议使用约束解码或先抽取后校验的策略。如果模型返回的 JSON 不合法宁可重试一次也不要直接丢弃知识。4.3 预测构图策略拿到每个代谢物的生化知识后下一步是把这些知识映射为网络图。图构建的核心逻辑是如果代谢物 A 的 neighbors 中包含代谢物 B则在 A 和 B 之间添加一条边。如果 A 和 B 属于同一条通路可以为它们添加一条“共通路”边。边的权重可以来自 LLM 的置信度也可以来自共现次数。基础构图代码# 文件路径src/graph_builder.py import networkx as nx def build_graph(metabolite_knowledge: dict) - nx.Graph: metabolite_knowledge 结构 { phenylalanine: { pathways: [Phenylalanine metabolism], neighbors: [tyrosine], enzymes: [phenylalanine hydroxylase] }, ... } G nx.Graph() for metabolite, info in metabolite_knowledge.items(): G.add_node( metabolite, pathways;.join(info.get(pathways, [])), enzymes;.join(info.get(enzymes, [])), ) for neighbor in info.get(neighbors, []): G.add_edge(metabolite, neighbor, relationbiochemical) # 补充分支如果两个节点在同一个通路但没有相邻关系可以添加共通路边 pathway_map {} for node, attr in G.nodes(dataTrue): pathways attr.get(pathways, ) for p in pathways.split(;): if p: pathway_map.setdefault(p, []).append(node) for members in pathway_map.values(): for i in range(len(members)): for j in range(i 1, len(members)): n1, n2 members[i], members[j] if not G.has_edge(n1, n2): G.add_edge(n1, n2, relationco_pathway) return G这样构建出来的图既包含直接的生化转化关系也包含同一通路内的共现关系。实际应用中可以通过relation属性区分不同边类型。4.4 质量评估方法图构建完之后不能直接拿去做下游分析。至少需要检查三个指标节点覆盖率有多少输入的代谢物成功出现在图中有没有因为名称标准化失败而丢失节点。边密度图的边数是否合理。如果边数过高说明“共通路”关系过于宽泛如果边数过低说明知识抽取不足。连通分量正常的代谢物网络应该是一个或多个有限连通分量。如果出现大量孤立节点说明知识抽取的 neighbors 覆盖不够。代码示例# 文件路径src/graph_builder.py补充示例 def evaluate_graph(G: nx.Graph) - dict: n_nodes G.number_of_nodes() n_edges G.number_of_edges() components list(nx.connected_components(G)) isolated list(nx.isolates(G)) return { nodes: n_nodes, edges: n_edges, connected_components: len(components), isolated_nodes: len(isolated), density: nx.density(G), }如果孤立节点占比超过 30%建议优先检查 LLM 的 neighbors 抽取质量而不是盲目调构图参数。5. 实战基于 MetaboLLM 思路的代谢物图构建示例下面给出一个完整的模拟实验数据是手工构造的用于跑通流程。你可以把它替换成自己的代谢物列表。5.1 准备模拟代谢物数据创建data/metabolites.csvmetabolite,KEGG_ID,abundance L-Phenylalanine,C00079,1523.4 Pyruvic acid,C00022,88.3 Citric acid,C00158,2031.9 L-Tyrosine,C00082,567.2 Fumaric acid,C00122,732.5 L-Malic acid,C00149,890.1 2-Oxoglutarate,C00026,422.7 Succinic acid,C00042,301.8 L-Glutamic acid,C00025,1100.2 Acetyl-CoA,C00024,0.55.2 使用 LLM 补充生化描述我们写一个稍微完整的流程脚本。为了便于运行这里的llm_completion_fn使用一个 mock 函数返回模拟的 JSON。真实使用时替换成你的模型接口即可。# 文件路径main.py import json import pandas as pd from src.preprocessing import load_metabolite_file, normalize_metabolite_name from src.llm_integration import extract_biochemical_knowledge from src.graph_builder import build_graph, evaluate_graph from src.visualize import draw_graph # 1. 读取数据 metabolite_df load_metabolite_file(data/metabolites.csv) print(读取到代谢物数量, len(metabolite_df)) # 2. 模拟 LLM 返回结果 def mock_llm_completion(prompt: str) - str: # 实际项目中请替换为真实模型调用 mock_knowledge { phenylalanine: { pathways: [Phenylalanine metabolism], neighbors: [tyrosine, phenylpyruvate], enzymes: [phenylalanine hydroxylase], }, pyruvate: { pathways: [Glycolysis, Pyruvate metabolism], neighbors: [acetyl-coa, lactate], enzymes: [pyruvate kinase], }, citrate: { pathways: [TCA cycle], neighbors: [isocitrate, acetyl-coa], enzymes: [citrate synthase], }, tyrosine: { pathways: [Phenylalanine metabolism, Tyrosine metabolism], neighbors: [fumarate, acetoacetate], enzymes: [tyrosine aminotransferase], }, fumarate: { pathways: [TCA cycle], neighbors: [malate, succinate], enzymes: [fumarase], }, malate: { pathways: [TCA cycle], neighbors: [oxaloacetate, fumarate], enzymes: [malate dehydrogenase], }, 2-oxoglutarate: { pathways: [TCA cycle], neighbors: [succinyl-coa, glutamate], enzymes: [isocitrate dehydrogenase], }, succinate: { pathways: [TCA cycle], neighbors: [fumarate, succinyl-coa], enzymes: [succinyl-coa synthetase], }, glutamate: { pathways: [Glutamate metabolism], neighbors: [2-oxoglutarate], enzymes: [glutamate dehydrogenase], }, acetyl-coa: { pathways: [TCA cycle, Fatty acid metabolism], neighbors: [citrate, oxaloacetate], enzymes: [citrate synthase], }, } return json.dumps(mock_knowledge.get(unknown, {})) # 3. 知识抽取 knowledge {} for name in metabolite_df[normalized_name]: info extract_biochemical_knowledge(name, mock_llm_completion) knowledge[name] info print(f完成知识抽取{name}) # 4. 构建图 G build_graph(knowledge) print(图评估指标, evaluate_graph(G)) # 5. 可视化 draw_graph(G, output_pathoutput/metabolic_graph.png)5.3 构建代谢物关联图上面的build_graph函数已经完成了图构建。为了能看到具体效果我们再做一次简单可视化。# 文件路径src/visualize.py import matplotlib.pyplot as plt import networkx as nx def draw_graph(G: nx.Graph, output_path: str output/metabolic_graph.png): plt.figure(figsize(12, 8)) pos nx.spring_layout(G, seed42, k0.6) nx.draw_networkx_nodes(G, pos, node_size800, node_color#4C72B0, alpha0.9) nx.draw_networkx_edges(G, pos, edge_color#BBBBBB, alpha0.6) nx.draw_networkx_labels(G, pos, font_size8, font_color#333333) plt.axis(off) plt.title(Predictive Metabolite Graph (Demo)) plt.tight_layout() plt.savefig(output_path, dpi200) print(f图已保存至{output_path})5.4 图分析与路径预测图建好之后一个很常见的任务是寻找两个代谢物之间的最短路径或者预测某个节点缺失的关联。下面用 networkx 做路径分析# 文件路径src/predictor.py import networkx as nx def find_shortest_path(G, source, target): try: path nx.shortest_path(G, sourcesource, targettarget) return path except nx.NetworkXNoPath: return None def predict_missing_edge(G, node_a, node_b, candidate_edges): 简单的边预测如果 node_a 和 node_b 与图中已有的共同节点存在共通路关系 则返回一个可能的连接建议。 common_neighbors list(nx.common_neighbors(G, node_a, node_b)) if common_neighbors: return {node_a, node_b, via, common_neighbors[0]} return None示例# 继续 main.py 的流程 from src.predictor import find_shortest_path path find_shortest_path(G, citrate, glutamate) print(citrate - glutamate 最短路径, path)预期输出类似citrate - glutamate 最短路径 [citrate, 2-oxoglutarate, glutamate]这是因为我们在 mock 知识中citrate 和 2-oxoglutarate 都属于 TCA 循环而 2-oxoglutarate 又有指向 glutamate 的边。5.5 运行与验证在项目根目录执行pip install pandas numpy networkx matplotlib python main.py如果一切正常会看到如下输出读取到代谢物数量 10 完成知识抽取phenylalanine 完成知识抽取pyruvate ... 图评估指标 {nodes: 10, edges: 16, connected_components: 1, isolated_nodes: 0, density: 0.3555} 图已保存至output/metabolic_graph.png citrate - glutamate 最短路径 [citrate, 2-oxoglutarate, glutamate]这里展示的是一个非常简化的工作流。真实项目中你的 LLM 输出可能来自一个个独立的 API 请求而且需要增加缓存和错误重试机制。6. 常见问题与排查思路这个流程看起来简单实际跑起来会遇到不少问题。我把高频问题整理成表格方便你快速排查。问题现象常见原因解决思路代谢物节点缺失名称标准化失败或 LLM 返回的空列表检查 ALIAS_MAP 是否覆盖了输入名称查看 LLM 原始响应图边数异常偏高“共通路”关系过度引入导致稠密网络只对核心通路的代谢物使用 co_pathway 边或设置最小共现阈值LLM 返回的 JSON 无法解析模型指令遵循能力不足输出多余文本使用约束解码、few-shot 示例或者重试一次并把错误输出记录到日志图中大量孤立节点neighbors 抽取覆盖不足提示词中增加“如果该代谢物有已知上下游产物请至少给出1个”约束运行太慢每个代谢物都调用一次 LLM没有做缓存增加本地缓存例如基于代谢物名称的字典或 SQLite 缓存不同批次构图结果不一致LLM 生成存在随机性设置 do_sampleFalse固定 temperature0并在提示词中要求确定输出无法复现论文中的图指标数据、模型、提示词与原文不一致先对齐数据处理逻辑再对齐模型版本和知识库版本在排查时建议遵循以下顺序先看数据层输入列表里有没有空值、重复值、非标准名称。再看模型层直接打印 LLM 原始输出确认 JSON 是否完整。再看构图层检查relation属性区分 biochemical 边和 co_pathway 边。最后看指标用evaluate_graph输出节点数、边数、孤立点数判断是哪一层导致异常。这样的排查思路比盲目调参有效得多。7. 最佳实践与工程建议7.1 数据治理层面建立代谢物别名标准表并把 KEGG、HMDB、ChEBI 三种 ID 统一维护。输入的代谢物名称不要直接作为图节点 ID建议用标准 ID 作为主键名称作为属性。对每个 LLM 输出都要记录来源方便追溯哪些知识来自模型生成哪些来自数据库注释。处理大规模数据时尽量把代谢物按通路分批处理不要一次性塞进单个图里减少内存压力。7.2 模型调用层面优先选择温度参数更低的推理模式。知识抽取任务不是创作任务随机性越低越好。设计固定输出模板并对输出做 schema 校验。只要 schema 不对就触发重试。建立缓存机制。同一代谢物重复调用 LLM 的成本完全可以避免。如果使用了开源模型建议用领域语料继续微调。通用的指令微调模型在生化命名识别上表现不够稳定。7.3 图构建层面不要把“同一通路”和“直接转化关系”混为一谈。建议用不同的边颜色或线型区分。图构建完成后至少做一次连通分量分析确认没有意外的大陆块或完全孤立的节点群。如果图的规模较大优先考虑 Neo4j 这类图数据库来存储而不是只依赖 NetworkX。边权重不要直接使用 LLM 的置信度因为不同模型的置信度不可比。建议使用共现计数或通路共现频率。7.4 生产环境注意事项对批量代谢物进行 LLM 知识抽取时注意第三方服务的调用频率限制。模型输出的知识存在幻觉风险凡是要下结论的边必须经过数据库验证或人工复核。涉及疾病机制、用药分析等场景时生化关系图只能作为辅助假设不能替代专业判断。如果要接入自动分析流水线建议把模型输出和下游分析解耦中间增加一个基于规则的校验层。8. 总结与学习路线本文围绕 MetaboLLM 的设计目标拆解了生化知识集成和预测性代谢物图构建的核心流程。我们从代谢组学数据处理的问题出发梳理了文本标准化、LLM 知识抽取、图构建、图评估和路径预测的完整链路并用一个最小可运行的 Python 示例演示了这套思路。如果你未来真的要在项目中落地类似系统需要重点关注的三个环节是代谢物名称标准化的覆盖度、LLM 结构化输出的稳定性、以及图评估指标是否真正反映生物学意义。这三块决定了下游分析能不能让人信服。接下来可以继续学习的方向包括基于图神经网络的代谢物-疾病关联预测、KEGG 通路自动对齐方法、以及如何把 MetaboLLM 输出的图结构嵌入到多组学联合分析流程中。建议先拿小规模数据把链路跑通再逐步扩大范围和复杂度。如果本文对你有帮助可以收藏备用。项目落地中遇到具体问题也欢迎在评论区交流。