关于 BioMapper
BioMapper 是用于将生物实体名称映射到标准化知识图谱标识符的 Python 客户端和 MCP 服务,面向生物医学数据处理与跨数据集协调。它支持批量和文件映射,并为结果提供结构证书。
主要功能
- 01映射代谢物、脂质、蛋白质和基因名称
- 02返回标准化知识图谱标识符
- 03支持批量映射和数据集文件流处理
- 04提供映射结果结构证书
- 05本地协调已解析的数据集
适用场景
- 01统一不同来源的生物实体标识符
- 02批量处理化合物或实验室数据
- 03连接已解析的跨队列数据集
MCP 相关
该包包含供 Agent 使用的 MCP 服务,可通过 `uvx biomapper` 启动,让 MCP 客户端调用实体映射能力。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx biomapperBIOMAPPER_MCP_ROOTSFolders map_file may read and write, path-separated (needed when the client shares no roots)BIOMAPPER_API_KEY密钥Optional API key; the hosted deployment is keylessBIOMAPPER_BASE_URLOverride the API root (staging or a local engine)BIOMAPPER_MCP_HOMEWhere job state lives (default ~/.cache/biomapper/mcp)本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
10收录的工具列表 · 更新于 1 天前
此工具无需参数。
详细介绍
biomapper
用于 BioMapper2 API 的 Python 客户端 — 将生物实体名称映射到标准化的知识图谱标识符(CHEBI、HMDB、PubChem、RefMet 等)。
from biomapper import map_entity
result = map_entity("L-Histidine")
print(result.primary_curie) # RM:0129894
print(result.confidence_tier) # high
print(result.ids_for("CHEBI")) # ['15971']
print(result.equivalent_ids_for("HMDB")) # ['HMDB0000177']
安装
# Core (async HTTP client + Pydantic models)
pip install biomapper
# With the external benchmark suite
pip install 'biomapper[benchmarks]'
核心安装包含供 Agent(Claude Code、Claude Desktop、其他 MCP 客户端)使用的 MCP 服务;使用 uvx biomapper 启动(参见通过 Agent 使用(MCP))。
使用 uvx biomapper 时请使用 1.6.2 或更高版本。 1.6.0 和 1.6.1 将服务放在 mcp extra 中(uvx --from 'biomapper[mcp]' biomapper-mcp);该命令在 1.6.2 上仍然有效。
使用 harmonize_cohorts() 和歧义链接标记时请使用 1.5.6 或更高版本(参见协调)。
无需密钥即可调用托管部署时请使用 1.5.4 或更高版本(参见 API 密钥)。
使用基准测试套件时请使用 1.5.3 或更高版本。 更早发布的版本(包括 1.4.0)既不包含 biomapper.benchmarks,也不包含 benchmarks extra,因此对这些版本运行 pip install 'biomapper[benchmarks]' 会警告 extra 未知,并且只安装核心客户端。1.5.2 包含该套件,但其 extras 发布时为空,因此相同的命令会安装不含 pandas、requests、rdkit、openpyxl 或 defusedxml 的核心客户端,且套件在首次导入时就会失败;如果固定使用 1.5.2,请手动安装这些依赖。1.5.3 是首个 benchmarks extra 实际包含其依赖的版本。变更日志记录了哪些版本已发布到索引;1.5.0 和 1.5.1 已打标签,但未发布。
Notebook
notebooks/biomapper_tutorial.ipynb:完整演示协调协议,无需密钥且固定构建版本:解析两个队列面板,通过仅含标识符的 CURIE 集合将其关联,并读取一份已认证和一份被拒绝的结构证书。notebooks/monti_overlap_benchmark.ipynb:比较 BioMapper 与 Monti 等人 2026 年在 NECS 跨队列重叠上的表现,以四个队列的已链接计数覆盖率为依据,并对 NECS 到 Arivale 的链接进行结构认证;结果从固定运行中重放,并附带一项小型实时检查。notebooks/ukbb_arivale_harmonization_sop.ipynb:使用此软件包协调两个队列的标准操作流程,以 UK Biobank × Arivale(代谢物、蛋白质、临床实验室指标)为例:纳入规则、映射、匹配、验证,以及根据 Activity 2 里程碑断言的结果;通过随附的面板元数据离线重放。
API 密钥(可选)
托管部署(https://biomapper.expertintheloop.io)无需 API 密钥。从 1.5.4 起,客户端默认无需密钥:未配置密钥时不会发送 X-API-Key 标头,并且所有入口点(包括同步封装函数)都可以按下方示例正常工作。
密钥仅用于可自托管或需身份验证的部署。通过 api_key= 传入,或在环境中设置:
export BIOMAPPER_API_KEY=your-key-here
也可以在项目根目录的 .env 文件中设置:
BIOMAPPER_API_KEY=your-key-here
除非传入 anonymous=True,否则会发送已配置的密钥。当 BIOMAPPER_API_KEY 已设置而你仍要强制进行无密钥调用时,请使用 BioMapperClient(anonymous=True)。如果部署确实需要密钥,而请求中未发送密钥,首次请求会抛出 BioMapperAuthError 并说明原因。
1.5.4 之前的版本在未配置密钥时会抛出 BioMapperConfigError,其同步封装函数也无法访问无需密钥的部署;请升级,或直接使用 BioMapperClient(anonymous=True)。
快速开始
单项查询(同步)
from biomapper import map_entity
result = map_entity("L-Histidine")
print(result.resolved) # True
print(result.primary_curie) # RM:0129894
print(result.chosen_kg_id) # CHEBI:15971
print(result.chosen_kg_id_review) # None (or 'divergent_refmet' when a ChEBI conflict is flagged for review)
print(result.confidence_score) # 2.489
print(result.confidence_tier) # high (≥2.0)
print(result.ids_for("CHEBI")) # ['15971']
print(result.ids_for("refmet_id")) # ['RM0129894']
# KG equivalent IDs — all identifiers from the resolved knowledge graph node
print(result.kg_equivalent_ids) # {'CHEBI': ['15971', '44637'], 'HMDB': ['HMDB0000177'], ...}
print(result.equivalent_ids_for("HMDB")) # ['HMDB0000177']
批量映射(同步)
from biomapper import map_entities, summarize
records = [
{"name": "L-Histidine"},
{"name": "Glucose", "identifiers": {"HMDB": "HMDB00122"}},
{"name": "Sphinganine"},
]
results = map_entities(records, progress=True) # tqdm bar with [notebook]
summary = summarize(results)
print(f"{summary.resolved}/{summary.total_queried} resolved")
print(f"Resolution rate: {summary.resolution_rate:.1%}")
print(summary.vocabulary_coverage)
输入会按每个请求 1000 个实体自动分块,并调用原生 POST /map/batch 端点,因此 10,000 条记录只需 10 次往返。
数据集上传(同步)
对于较大的输入,可直接将 TSV/CSV 文件交给服务,并以流式方式接收结果。服务通过
POST /map/dataset/stream 端点逐行处理文件:
from pathlib import Path
from biomapper import map_dataset_file_sync
result = map_dataset_file_sync(
Path("compounds.tsv"),
name_column="name",
provided_id_columns=["hmdb_id"],
progress=True, # tqdm bar
total_hint=1000, # optional; enables % progress
)
result.raise_for_error() # opt-in: raise BioMapperError if the stream truncated
print(f"resolved {sum(1 for r in result.results if r.resolved)} of {len(result.results)}")
name_column 和 provided_id_columns 为必填项——服务会用它们将文件中的列映射到实体名称和标识符提示。
如果要将每条结果流式传输到 UI 或用于自定义处理,请使用异步
BioMapperClient.map_dataset_file_iter 方法(参见 notebooks/ 中的教程笔记本)。
了解 API 支持的功能
from biomapper import list_annotators, list_vocabularies, list_entity_types
for a in list_annotators():
print(f"{a.slug:30s} {a.name}")
# 300+ supported vocabularies (CHEBI, HMDB, PubChem, …)
vocabs = list_vocabularies()
print(f"{len(vocabs)} vocabularies supported")
# Biolink entity types with aliases and default vocabulary prefixes
for et in list_entity_types():
print(f"{et.type}: {', '.join(et.aliases)}")
if et.default_prefixes:
print(f" prefixes: {', '.join(et.default_prefixes)}")
调整解析设置
映射调用接受 API 的解析选项作为关键字参数。未传入的选项会从请求中省略,因此会采用服务端自己的默认值;不使用这些选项的调用方,其请求内容不会改变。
各调用对这些选项的支持并不统一,因此使用前请先查看下表。向不接受某个选项的调用传入该选项,会在本地引发 TypeError,不会发送请求:
vocab | prefer_human | prefer_canonical | candidate_limit | kestrel_top_n | array_delimiters | |
|---|---|---|---|---|---|---|
map_entity、map_entities(同步和异步) | 是 | 是 | 是 | 是 | 是 | 是 |
BioMapperClient.map_dataset_file_iter(异步) | 是 | 是 | 是 | 是 | 是 | 否 |
map_dataset_file_sync | 是 | 否 | 否 | 否 | 否 | 否 |
数据集路由不支持 array_delimiters,因为 API 不接受此选项。map_dataset_file_sync 不支持的另外四个选项,是该封装器的缺口,而非 API 的限制:其底层的异步 map_dataset_file_iter 支持这些选项,因此,如果文件处理需要这些选项,请直接使用该方法。
from biomapper import map_entity # map_entity / map_entities accept all six
result = map_entity(
"PC 34:1",
vocab="refmet", # restrict to one vocabulary (or a list)
prefer_human=False, # gene/protein: allow a non-human ortholog to win
prefer_canonical=False, # non-gene: allow a non-canonical-namespace node to win
candidate_limit=20, # candidates each Kestrel search annotator retrieves (1..100)
array_delimiters=["|"], # how delimited ID strings are split
kestrel_top_n=5, # opt in to raw Kestrel passthrough rows (1..100)
)
| 选项 | 适用范围 | 默认值 | 说明 |
|---|---|---|---|
vocab | 全部 | 服务端 | str 或 list[str],例如 "refmet" |
prefer_human | 基因/蛋白质 | True(服务端) | 优先选择属于人类且带有 HGNC 标识的候选项,而非物种错误的直系同源项 |
prefer_canonical | 非基因 | True(服务端) | 优先选择规范命名空间中的节点(CHEBI/HMDB/RefMet),而非来自 UMLS/ICD/KEGG 的同名节点 |
candidate_limit | 全部 | 服务端 | 1..100。由客户端验证,因此超出范围的值会在发送请求前引发 ValueError |
kestrel_top_n | 全部 | 关闭 | 1..100。仅透传:不会改变 chosen_kg_id、assigned_ids 或证书 |
array_delimiters | map_entity、map_entities | [",", ";"] | 数据集路由不接受此选项 |
对于管线使用的每个搜索端点,kestrel_top_n 都会将 Kestrel 返回的原始行填入 result.kestrel_results,并保持原样。此类行属于不可信的外部数据:应将每个字段都视为未经转义、未经验证。
解析证书与拒绝
映射结果包含 API 针对 chosen_kg_id 计算出的结构性证书,可据此区分“无法核查”和“核查后不一致”。
result = map_entity("cortisone")
cert = result.certificate
if cert is not None:
print(cert.state) # corroborated | uncorroborated | contradicted |
# unavailable | not_applicable
print(cert.independent_source) # registry consulted, e.g. "pubchem"
print(cert.independent_of_selection) # False => corroboration would be circular
print(cert.refmet_availability) # voted | no_match | unavailable | not_queried
# Why the resolver declined, when it did. Distinct from `error`:
# an error means the call failed; a refusal means the pipeline ran and declined to assert.
print(result.refusal_reason)
state="contradicted" 表示应由人工查看,并不代表解析器有误:外部注册表中的名称查询本身也可能返回相关但不同的化合物。state="unavailable" 表示没有可供比对的信息,即结果无法验证,而非错误。
异步用法
import asyncio
from biomapper import BioMapperClient
async def main() -> None:
async with BioMapperClient() as client:
# Verify connectivity
health = await client.health_check()
print(health) # {'status': 'healthy', ...}
# Single
result = await client.map_entity(
"L-Histidine",
identifiers={"HMDB": "HMDB00177"},
)
# Batch — auto-chunked at 1000 entities per request
results = await client.map_entities(
[{"name": "L-Histidine"}, {"name": "Glucose"}],
progress=True,
)
# Stream from a file — per-result as they arrive
from pathlib import Path
async for r in client.map_dataset_file_iter(
Path("compounds.tsv"),
name_column="name",
provided_id_columns=["hmdb_id"],
):
print(r.query_name, r.primary_curie)
asyncio.run(main())
map_dataset_file_iter 是面向 UI 和自定义处理的基础方法,适用于需要逐条结果响应的场景。需要阻塞式、完整收集结果的调用方应改用 map_dataset_file_sync(见上文)。
Jupyter 笔记本
在运行中的事件循环内使用同步辅助方法前,请先应用 nest_asyncio:
import nest_asyncio
nest_asyncio.apply() # required in Jupyter
from biomapper import map_entities
results = map_entities([{"name": "L-Histidine"}], progress=True)
已完成的示例笔记本列于笔记本下。两者都连接到无需密钥的托管部署,因此无需 API 密钥,并且都会打印响应请求的确切 KRAKEN 构建版本。
预处理函数
from biomapper.extras.metabolon import clean_compound_name, extract_hmdb_id
# Strip quotes and collision-energy suffixes
clean_compound_name('"1,3-Diphenylguanidine_CE45"') # '1,3-Diphenylguanidine'
clean_compound_name('"4,6-DIOXOHEPTANOIC ACID"') # '4,6-DIOXOHEPTANOIC ACID'
clean_compound_name('L-Histidine') # 'L-Histidine' (unchanged)
# Extract HMDB accessions from ms1_compound_name format
extract_hmdb_id('HMDB:HMDB03349-2257 L-Dihydroorotic acid') # 'HMDB03349'
extract_hmdb_id('HMDB00177') # 'HMDB00177'
extract_hmdb_id(None) # None
协调(跨数据集等价性)
biomapper.harmonize 在本地关联两个已解析的数据集。它完全在客户端运行:不发送额外请求,也不访问知识图谱,因此可离线使用,且无需网络即可全面测试。如果满足以下任一条件,两个实体(每个队列各一个)就会关联;每条关联都会记录其依据(basis),并按强度从高到低排列:
| 依据 | 规则 |
|---|---|
node | 两者仅含标识符的 CURIE 集合有交集,且都解析到同一个选定节点 |
identifier | 两者仅含标识符的 CURIE 集合有交集,但解析到不同节点 |
name_exact | 空白规范化后,两者名称相同 |
name_casefold | 仅在进行大小写折叠后,两者名称才相同(参见下文的短名称规则) |
名称关联(自 1.5.5 起提供,需通过 link_by_name=True 选择启用)可捕获解析到不同节点的实体,例如 acetylcarnitine (c2) 和 acetylcarnitine (C2)。目前,此功能面向小分子/代谢物面板;其他实体类型仍待审查其大小写敏感的命名惯例(例如基因和蛋白质符号)。规则如下:
- 只有两侧都成功解析的实体才会按名称关联;未解析的实体仍会作为拒绝候选项。即使传入自定义的
key=,也会根据query_name比较名称;关联结果会以键的形式报告。 - 不进行模糊匹配,也不去除标点,只规范化空白。
- 如果仅在进行大小写折叠后才匹配,且任一名称的长度不超过
NAME_CASEFOLD_MIN_LENGTH_EXCLUSIVE(4)个字符,则不建立关联,而是列入report.name_match_withheld供审查:Co(钴)和CO(一氧化碳)代表不同事物。 - 每次调用
harmonize()只传入一种实体类型的结果。结果中不含可供检查的类型,因此这由调用方负责;跨类型冲突不在范围内,例如 cAMP(代谢物)与 CAMP(基因)。 - 默认关闭:
harmonize(...)仅按node和identifier建立关联,与 1.5.5 之前完全相同。
report.summary() 会按依据统计关联数(links_by_basis),并报告 n_name_only_links(没有标识符证据的关联)和 n_name_match_withheld,因此报告可以显示“X 个通过标识符关联,Y 个仅通过名称关联”。每条关联还包含 bases,即适用依据的完整集合。
歧义关联(自 1.5.6 起提供)。每条关联都会记录 a_partners 和 b_partners,表示两侧各有多少个实体与之关联。如果任一值大于 1,则 link.ambiguous 为 true:多个不同实体关联到同一条目,因此该配对是待审查候选项,而非可信匹配。report.one_to_one_links 和 report.ambiguous_links 会分别列出这两类关联,summary() 还会添加 n_one_to_one_links 和 n_ambiguous_links。所有关联仍会返回,不会丢弃任何关联。在 NECS x Xu et al. 2022 对照 Metabolon 化合物 ID 的评分中,398 个一对一关联有 397 个正确(99.7%);而全部关联中,575 个有 439 个正确(76.3%)。
from biomapper import map_entities
from biomapper.harmonize import harmonize
ukbb = map_entities([{"name": "Glucose"}, {"name": "Urea"}])
arivale = map_entities([{"name": "D-glucose"}, {"name": "X-12345"}])
report = harmonize(ukbb, arivale, a_label="ukbb", b_label="arivale")
report.n_links # 1
report.links[0].basis # 'node'
report.links[0].shared # frozenset({'CHEBI:17234', 'KEGG:C00031'}): the identifiers shared
report.b_unresolved # ('X-12345',) — a refusal candidate, never silently dropped
report.summary()
关联器遵循两项规则:
- 不使用结构标识符。 排除
INCHIKEY、INCHI和SMILES。基于结构哈希进行关联会使任何下游结构证书陷入循环论证,并在设计上导致精确率达到 100%。 - 规范化前缀同义词。
KEGG.COMPOUND:C00031等同于KEGG:C00031;而KEGG.GLYCAN等真正不同的标识符空间则保持区分。
未解析出任何结果的实体是拒绝候选项,而非关联项。它会列在 a_unresolved / b_unresolved 中,并计入 summary(),但不会纳入关联率的分母,因此不会将未解析误计为不等价。映射调用出错的实体则会单独记录在 a_errors / b_errors 中。
使用 from biomapper.harmonize import harmonize 导入。此名称不会绑定在包根目录上,以免与同名子模块冲突。
在一次调用中协调两个队列:harmonize_cohorts()
harmonize_cohorts() 会运行完整流程:读取两个队列表,将它们映射后,通过 harmonize() 进行关联,并写入一份固定报告。之所以提供这个函数,是因为看似直接的手动流程可能会悄然降低结果质量。当只有一个队列提供某类标识符时,传入该标识符会使该队列使用另一队列无法通过名称找到的代码专属条目:在 UK Biobank x Arivale 临床检验数据中,传入 Arivale 的 LOINC 代码后,匹配对从 31 个降至 2 个。
from biomapper import harmonize_cohorts
report = harmonize_cohorts(
"ukbb_labs.tsv", # a DataFrame, a list of dicts, or a TSV/CSV path
"arivale_labs.tsv", # ('#' comment lines are skipped)
entity="labs", # -> biolink:ClinicalMeasurement
a_name_column="field_name",
b_name_column="Display Name",
b_vocabularies={"LOINC": ["Labcorp LOINC ID", "Quest LOINC ID"]},
a_label="ukbb",
b_label="arivale",
)
# UserWarning: LOINC is declared only for 'arivale' ... not supplied as mapping input
report.summary()["arms"]["names_only"] # pairs, one-to-one/ambiguous, link bases, ...
report.review_queue # codes whose entry disagrees with the name's entry
# harmonize_cohorts: wrote results to .../biomapper_runs/harmonize_cohorts_20261008T190000Z
功能:
- 仅名称分支。 根据解析后的类别和名称映射两个队列,不使用标识符。
entity可取metabolites(SmallMolecule)、proteins(Protein)、genes(Gene)、labs(ClinicalMeasurement,Biolink 中的实验室检验项目)或任意原始biolink:类别;category=可覆盖别名。与harmonize()一样,仅对 SmallMolecule 启用名称关联。 - 标识符分支,仅使用共享词表。 按词表和队列声明标识符列(
{"LOINC": [...]});名称会经过规范化,因此KEGG.COMPOUND等同于KEGG。只有两个队列都声明的词表才会作为映射输入,且只有包含此类标识符的行会重新映射;其余行沿用仅名称分支的结果。如果没有共享词表,则跳过该分支并在报告中说明原因;如果没有标识符列,则只运行仅名称分支。 - 单边代码的审核队列。 对于只有一个队列声明的词表中的每个代码,单独解析该代码(
annotation_mode="none",每行每个代码各发起一个请求),并通过标识符集合的交集与该行的仅名称条目进行比较。每个代码都会获得一个状态(agree、disagree、code_unresolved、name_unresolved_code_resolved、errored);report.review_queue会列出除agree以外的所有项目及两侧条目。在实验室检验数据中,这里会列出 Arivale 的“Glucose”:其名称对应一个条目,而 LOINC 代码 2345-7 指向另一个条目。 - 报告。 两个
HarmonizationResult(report.names_only、report.identifier)、它们的diff(仅名称找到的匹配对、仅标识符找到的匹配对、两者都找到的匹配对)、每个分支的一对一和歧义关联数(n_one_to_one_links/n_ambiguous_links,与harmonize()中相同)、关联依据、警告、排除的行(名称为空)和固定信息。每个分支的关联表都包含a_partners、b_partners和one_to_one标志,便于审核歧义关联。
默认输出。 结果会写入当前目录下的 biomapper_runs/harmonize_cohorts_<UTC stamp>/(可通过 output_dir= 指定其他位置;设置 save=False 可跳过保存;也可随时调用 report.write(path)):每个分支及队列的映射结果会在该分支完成时写入,因此即使发生故障,也能保留已完成的工作;此外还会写入每个分支的关联表、diff.tsv、review_queue.tsv、settings.json 和 summary.json。不会写入超出你传入内容范围的数据;输入文件仅记录文件名和 SHA-256,不记录绝对路径。
固定信息。 包版本;API 的 /health 状态和自报版本(标注为“self-reported, known stale”:API 不会公开其引擎版本,因此该版本记录为 unavailable);Kestrel 的 /health 中的 kestrel_version 和 kg_build,以及所用的 Kestrel URL(kestrel_url=);还有 UTC 时间戳。设置 probe_pins=False 可跳过两次读取。
请求。 默认映射器每批发送 10 条,超时为 300 s(可通过 batch_size=、timeout= 设置;设置 progress=True 可查看请求);失败的批次会被记为错误行并计入统计,不会抛出异常。传入 mapper=(任何符合 (records, *, entity_type, annotation_mode) -> list[MappingResult] 的可调用对象)即可离线重放已记录的结果;测试通过此方式重放了 UK Biobank x Arivale 实验室检验数据(tests/fixtures/cohorts_labs_cm/,KRAKEN kg 2.3.0 / 3dd08a5b:37 个匹配对,其中 21 个为名称一对一匹配)。
在 Agent 中使用(MCP)
biomapper 随附一个本地 stdio MCP 服务(命令为 biomapper,别名为 biomapper-mcp),因此 Agent 可以通过与 Python 客户端相同的公开、无需密钥的 API 解析实体。它在你的机器上运行,不会托管在任何地方。只需一条命令即可启动(需要
uv):
uvx biomapper
Claude Code(服务可通过 MCP roots 看到你的项目文件夹):
claude mcp add --scope user biomapper -- uvx biomapper
Claude Desktop(claude_desktop_config.json)。Desktop 不会继承你的 shell PATH,因此请使用 which uvx 输出的绝对路径,并列出 map_file 可能使用的文件夹,因为 Desktop 不共享任何项目 roots:
{
"mcpServers": {
"biomapper": {
"command": "/absolute/path/to/uvx",
"args": ["biomapper"],
"env": { "BIOMAPPER_MCP_ROOTS": "/Users/you/data" }
}
}
}
工具
| 工具 | 功能 |
|---|---|
list_entity_types、list_vocabularies、list_annotators | 发现;先调用 list_entity_types 以选择 entity_type |
map_entity | 将一个名称(以及可选的标识符提示)映射为 KG 标识符 |
map_batch | 在一个请求中处理最多 5 个实体;超过此数量会被拒绝,并提示使用 map_file |
map_file | 将任意长度的 TSV/CSV 作为可恢复的后台任务处理;会立即返回 job_id 和预计完成时间 |
job_status、resume_job、cancel_job | 跟踪、继续或停止文件任务 |
server_info | 版本、KG 来源信息、限制,以及 map_file 可使用的文件夹 |
每个结果都会标明 resolved、unresolved、refused 或 error。error 表示调用失败,并非已确认无匹配项。结果包含简明的来源信息块(客户端版本、API URL、Kestrel /health 中的 KG 构建版本,标记为假定值,未经验证,以及 kg_verified)。
吞吐量,以及设置这些限制的原因
托管部署是一个共享实例,处理每个实体约需 4-5 s,并且在并发负载下速度会大幅下降,因此服务会谨慎控制请求:
- 每个服务进程最多有一个正在处理的请求。 交互式调用和文件任务分块共用一个闸门;如果约 10 s 内无法获得闸门,调用会返回“繁忙,请稍后重试”。
- 每次工具调用都在 60 s 内返回(Claude Desktop 会在约 60 s 后取消调用),因此
map_batch最多处理 5 个实体,耗时较长的工作则作为任务运行。 - 循环保护: 5 分钟内调用超过 20 次
map_entity/map_batch会被拒绝,并提示使用map_file。发现和状态工具不计入。
文件任务
map_file(path, name_column, entity_type, identifier_columns?, output_path?) 会验证文件(是否可读、列是否存在、行数是否已统计、输出文件是否尚不存在、/health 是否有响应),然后将其加入队列。identifier_columns 用于将列映射到其词表,例如 {"hmdb_id": "HMDB"}。
- 输出: 在输入文件旁生成
<input>.biomapper.tsv和<input>.biomapper.provenance.json(包含完整固定信息:API、Kestrel、KG 构建版本)。绝不会覆盖文件。任务完成前,进度会写入<output>.partial。 - 可恢复: 行会以每块 5 行的方式映射,并在完成时缓存。如果 Agent 会话结束,任务会进入
paused状态;同一文件夹中的下一次会话会自动恢复任务,不会重新映射已缓存的行。空闲超过 7 天的任务会变为expired,只能通过resume_job恢复。 - 如实报告失败: 连续三次整块失败,或某一块耗时超过 240 s,都会使任务进入
stalled状态并停止发送请求;resume_job会在健康检查后重试。某行错误三次后会标记为error。如果输入文件已更改,或 KG 构建版本与缓存行所用版本不同,任务会失败;rerun=true会从头开始。 - 文件夹:
map_file只能在客户端的 MCP roots 和BIOMAPPER_MCP_ROOTS中读取和写入文件,并会解析符号链接。如果两者都未设置,它会拒绝操作并说明如何设置;交互式工具仍可使用。
环境
| 变量 | 默认值 | 用途 |
|---|---|---|
BIOMAPPER_BASE_URL | 托管 API | API 根地址,例如暂存环境或本地引擎 |
BIOMAPPER_KESTREL_URL | https://kestrel.krakenkg.com/api | 从何处读取 KG 构建版本以追溯来源 |
BIOMAPPER_API_KEY | 未设置(无需密钥) | 设置后通过 X-API-Key 发送;绝不会写入作业文件、结果或日志 |
BIOMAPPER_MCP_ROOTS | 未设置 | map_file 可使用的额外文件夹(以 : 分隔;Windows 上使用 ;) |
BIOMAPPER_MCP_HOME | ~/.cache/biomapper/mcp | 作业状态(仅所有者可访问) |
在主目录位于 NFS/SMB 上的 HPC 或共享主机上,请将 BIOMAPPER_MCP_HOME 设置为本地磁盘路径:
作业所有权使用操作系统文件锁,而网络文件系统可能无法在不同机器间正确执行这些锁。
API 参考
MappingResult
| 属性 | 类型 | 说明 |
|---|---|---|
query_name | str | 提交给 API 的名称 |
resolved | bool | 是否返回了任何标识符 |
primary_curie | str | None | 响应中的第一个 CURIE |
chosen_kg_id | str | None | 解析器选定的知识图谱 ID |
chosen_kg_id_review | str | None | 针对按来源加权的小分子 ChEBI 冲突的审核标记:"divergent_refmet"、"conflict_no_structure" 或 None |
confidence_score | float | None | 所有标注器中的最高分 |
confidence_tier | str | "high"(≥2.0)/ "medium"(1–2)/ "low"(<1)/ "unknown" |
identifiers | dict[str, list[str]] | 词汇表 → ID,例如 {"CHEBI": ["15971"]} |
kg_equivalent_ids | dict[str, list[str]] | 已解析 KG 节点的所有等价 ID,按 CURIE 前缀分类 |
certificate | ResolutionCertificate | None | chosen_kg_id 的结构化证书(状态、独立来源、RefMet 来源信息) |
refusal_reason | str | None | 解析器拒绝的原因,取自证书。没有证书时为 None |
lipid_resolution | LipidResolution | None | 脂质层级详情(goslin 解析、mapping_relation);非脂质行时为 None |
refmet_availability | str | "voted" / "no_match" / "unavailable" / "not_queried" |
refmet_source | str | "local_snapshot" / "not_in_snapshot" / "live_api" / "unavailable" / "not_queried" |
refmet_snapshot_version | str | None | 为该行提供数据的固定 RefMet 版本 |
tier_b_snapshot_version | str | None | 生成固定独立结果的 Tier B 版本 |
kestrel_results | list[KestrelSearchResult] | None | 原始透传行;仅在设置了 kestrel_top_n 时提供 |
hmdb_hint | str | None | 请求中传递的 HMDB 提示 |
error | str | None | 映射失败时的错误消息 |
result.ids_for("CHEBI") # ['15971']
result.ids_for("refmet_id") # ['RM0129894']
result.ids_for("PUBCHEM.COMPOUND") # []
# KG equivalent IDs — all identifiers from the resolved knowledge graph node
result.equivalent_ids_for("HMDB") # ['HMDB0000177']
result.equivalent_ids_for("LM") # ['ST01010001', 'ST01010093']
DatasetMappingResult
map_dataset_file_sync 的返回类型。包含逐行结果,以及一个可选启用的错误信号,用于标记未完整运行。
| 属性 | 类型 | 说明 |
|---|---|---|
results | list[MappingResult] | 按服务端输出顺序排列的逐行映射结果 |
stats | dict[str, Any] | 服务端提供的摘要。除非流中输出终止摘要行,否则为空 |
metadata | ApiMetadata | 请求元数据;如果数据流在完成前截断,则保持默认值 |
error | str | None | 数据流中途发生传输故障时的文本。正常运行时为 None |
result.raise_for_error() # raises BioMapperError if .error is set; else no-op
raise_for_error 与 httpx.Response.raise_for_status 的行为一致,并将部分结果契约变为调用方显式选择的行为——静默使用已截断的运行结果(使用 .results 却不检查 .error)正是此模型旨在防止的易错做法。
**注意:**数据集流结果中的
confidence_score始终为None—/map/dataset/stream端点输出的逐行负载比/map/batch更精简,不包含标注器的assigned_ids块。 如果需要置信度等级,请使用map_entity/map_entities。
置信度等级
| 分数 | 等级 | 建议操作 |
|---|---|---|
| ≥ 2.0 | high | 无需审核,直接接受 |
| 1.0–2.0 | medium | 快速检查是否合理 |
| < 1.0 | low | 建议人工审核 |
None | unknown | 未返回分数(例如通过 HMDB-hint 解析) |
错误处理
from biomapper import (
BioMapperError, # base class
BioMapperAuthError, # 401/403: a key is required, or the key was rejected
BioMapperRateLimitError, # 429 — throttled
BioMapperServerError, # 5xx
BioMapperTimeoutError, # request timeout
BioMapperConfigError, # invalid config, e.g. api_key= together with anonymous=True
)
try:
result = map_entity("Glucose")
except BioMapperAuthError as e:
# Only for a deployment that requires a key; the message says whether one was
# missing or rejected.
print(e)
else:
if result.error:
print(f"mapping failed: {result.error}")
无论从同步还是异步入口调用,身份验证失败(401/403)都会引发 BioMapperAuthError,因为这是系统性故障:之后的每个请求都会以相同方式失败。同步的 map_entity 和 map_entities 会通过批处理端点执行,因此临时故障(429、5xx、超时、响应格式错误)和单个实体的问题不会引发异常:每条受影响的记录都会作为 MappingResult(error=...) 返回,而不会中止整个批次。请检查每个结果的 .error。异步客户端的单实体调用 await client.map_entity(...) 则会直接引发相应的类型化异常(BioMapperRateLimitError、BioMapperServerError、BioMapperTimeoutError)。
数据集流式处理(map_dataset_file_sync)采用两级约定:
- 初始请求错误(401、422、500、连接超时)会引发类型化异常——这些错误发生在处理任何行之前,因此没有需要保留的部分结果。
- 流处理过程中的传输故障会记录在
DatasetMappingResult.error中,同时在.results中保留部分结果。调用.raise_for_error()可获取异常语义;对于“接受部分结果,其余内容记入日志”的工作流,也可直接检查.error。
on_result 中引发的回调异常会原样传播,并会取代返回值——截至该时刻已收集的部分结果也会丢失。对于回调可能失败的 UI 使用场景,如果希望保留部分数据,请在自己的回调函数体中使用 try/except。
外部基准测试套件
这是一个仅使用 API 的复现工具,用于复现 BioMapper 预印本报告的基准测试。它针对部署实例运行,而非本地引擎检出目录,这有两个重要原因:在检出目录中进程内运行测量的是库,而不是已部署的服务;而指定部署实例,则可将来源信息绑定到实际提供答案的后端。
pip install 'biomapper[benchmarks]'
python -m biomapper.benchmarks list # the 11 arms and the 2 deliberate skips
python -m biomapper.benchmarks all # all arms, production endpoint
python -m biomapper.benchmarks arm hajjar # a single arm
python -m biomapper.benchmarks --endpoint dev all # dev, for testing
公开的 KRAKEN 端点无需密钥,而未配置密钥的 BioMapper2 部署是开放的,因此该套件默认无需身份验证即可运行。如果你的部署需要密钥,请设置 BIOMAPPER_API_KEY;密钥不接受通过命令行传入,因为其他进程可以看到 argv,且密钥会被记录在 shell 历史中。
各测试组
| 测试组 | 输入 | 指标 | 可报告为 |
|---|---|---|---|
hajjar | 代谢物名称 | InChIKey 结构基准,严格匹配 + KG 等价集合 | 准确率候选 |
necs | 代谢物名称 | 结构基准,严格匹配 + 电荷归一化 | 准确率,需注意金标准的局限 |
srm1950 | 代谢物名称 | 结构基准(金标准源自经认证的 SMILES) | 准确率候选 |
metlinkr | 代谢物名称 | 策展者交叉链接一致性 + 结构一致性 | 准确率候选 |
metabench | ID→ID 和名称→ID 混合 | 1,000 个 grounding 对的 CURIE 相等性 | 部分循环验证 |
metaboliteannotator | 代谢物名称 | 名称命中率,按离子模式统计 | 按构建方式计为覆盖率 |
refmet | 代谢物名称 | 结构基准 | 覆盖率 |
lmsd | 脂质名称 | 简写可解析性,设有最低门槛 | 覆盖率(能力回归) |
hgnc | 基因符号 | 按目标命名空间统计的 CURIE 相等性 | 覆盖率 |
nlmgene | 基因提及 | 准确率(无歧义)+ 标记率(有歧义) | 准确率候选 |
swisslipids | 脂质名称 | — | 当前无法获取来源,报告为跳过 |
引用任何结果前,请先阅读“可报告为”列。 图谱收录的四个数据源(lipidmaps、refmet、loinc、ncbigene)是上述测试组的金标准来源,因此这些测试组衡量的是覆盖率,而非独立准确率:金标准标识符和 BioMapper 的答案来自同一处。每次运行都会根据构建自身的来源列表为每个测试组标注,而非使用静态说明,因此标注会随图谱变化。
测试套件还会强制执行另外两条报告规则,而不只是提供说明:
- 基因测试组按目标命名空间报告准确率。 任意命名空间的汇总结果会标记为
quotable: false,因为不同命名空间的表现差异很大,而且该汇总曾被引用得仿佛能代表所有命名空间。 - 跳过的测试组既不是零分,也不算通过。 它会在清单中附带跳过原因。
溯源信息
每次运行都会记录实际为其提供服务的版本信息,从 Kestrel /health 读取(无需密钥),而非硬编码:kestrel_version、kg_version、biolink_version、build_timestamp、git_commit、完整的 source_versions 映射、包版本、每个数据集的来源 SHA,以及运行 ID。测试组开始前读取一次构建信息,结束后再读取一次;如果运行期间发生变化,清单会明确说明,因为此时固定的版本信息已无法描述所有结果。
默认情况下,结果会保存到带时间戳的目录中(可用 --out 覆盖)。没有用于丢弃结果的标志:运行中最耗费资源的是实时 API 流量。
保留在引擎仓库中的内容
CI 回归门禁(gate.py、conflation_gate.py、test_regression_gate.py、kg-regression.yml)用于保护合并,需要访问引擎内部实现。--resolver-mode {weighted,vote} A/B 开关会切换解析器构造函数参数,该参数有意未列入 API。
开发
git clone https://github.com/Phenome-Health/biomapper
cd biomapper
poetry install --with dev --extras all
make check # format → lint → type-check → test
make test # tests only
make coverage # HTML coverage report
docs/solutions/ 存放过去问题的解决方案文档,包括错误、最佳实践和工作流模式,并按类别整理,附有 YAML 前置元数据(module、tags、problem_type)。在实现或调试已有相关文档的领域时可供参考。
许可证
MIT — 参见 LICENSE。
相关链接
- BioMapper2 API:
https://biomapper.expertintheloop.io
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。