Community编程与开发github.com

UNC-RENCI-KGAI/croissant-semantics

为已有的生物医学知识图谱 Croissant 元数据文件添加语义信息,将列分组为实体(基因、疾病等)、行类型化为 Biolink 关联,并标识标识符前缀、单位和代码值。

croissant-semantics 是什么?

该 AI 技能旨在增强现有的 Croissant 元数据文件,通过添加语义层来明确数据含义。它支持将数据列分组为有类型的实体(如基因、疾病),将数据行定义为 Biolink 标准下的关联关系,并标注标识符前缀、单位和代码值,所有操作均基于 Croissant 1.1 规范。技能通过一系列脚本实现工作流:`inventory.py` 用于枚举布局,`sample.py` 用于采样真实数据值,`vocab.py` 用于查询 Biolink 词汇和标识符前缀,`apply_plan.py` 将语义计划写入新的 Croissant 文件,`check.py` 则针对真实数据验证结果。主要适用于生物医学知识图谱(如 Reactome、HGNC 等)的维护者和数据工程师。关键特性包括:生成可复现的 JSON 计划、自动利用之前的维护人员答案、支持多种文件格式(VCF、GAF、MITAB、CSV 等)、以及对大型数据集的温和采样策略(限制并发请求、缓存下载)。此技能显著减少了手动编辑 Croissant 文件时引入不一致或错误的风险,并确保生成的语义元数据与底层数据一致。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/UNC-RENCI-KGAI/KGB-CIA/tree/HEAD/.agents/skills/metadata/croissant-semantics

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

为 Croissant 添加语义

RoboCroissant 文件说明了知识图谱包含哪些文件以及它们的列内容。此技能则为数据添加含义:哪些列共同描述一个基因或疾病、一行数据断言了什么、列的 ID 使用了哪个标识符前缀、代码代表什么。它使用 Croissant 1.1 结构将这些写入一个新的 croissant 文件,并记录每条声明的做出原因。

你将生成一个计划(JSON 格式,按布局组织),脚本将应用并检查该计划。你无需手动编辑 croissant 文件。

输入与输出

  • 输入:一个 croissant 文件(croissant.json 或 croissant.json.gz)和一个输出目录,以及 croissant 文件旁边的维护人员文件 semantics_answers.json(如果存在)。
  • 输出(在输出目录中):
    • semantics_plan.json — 计划(格式:reference/plan-format.md)
    • croissant.semantic.json(或 .json.gz,如果输入是 gzip 压缩的)— 结果文件
    • check_report.md — check.py 的输出(以及 check_report.load_errors.txt,当记录加载失败时包含完整的 mlcroissant 错误)
    • notes.md — 决策、未包括的布局及其原因、以及给知识图谱维护人员的问题

输入的 croissant 文件永远不会被修改。请将下载、辅助脚本和其他临时工作文件放在 OUT/work/ 目录下,而非其他位置。

脚本

所有脚本都位于 scripts/ 目录下,可直接运行(它们是 uv run --script 文件,会自动安装自身依赖)。在任何脚本上使用 --help 参数可查看帮助。

脚本用途
inventory.py CROISSANT [--layout ID] [--json F] [--common-columns]列出所有布局(不同的列集合),从大到小排列;描述某个布局的列、记录集和文件;列出大多数记录集共享的列
sample.py CROISSANT --layout ID从该布局的三个文件中读取真实行;显示每列的示例值及其形状(CURIE 及其前缀、裸 ID、列表、代码)
dialects.py list/show/detect/read已知文件格式(VCF、GAF、MITAB、CTD 等)作为可计算方言;检测某个布局的文件由哪种格式读取;仅使用 croissant 对文件的描述来读取记录
vocab.py class/slot/search/associations/prefix/identify/term/ols/infores查询 Biolink 类和槽位(包含近似匹配建议)、主语/宾语对的关联类、标识符前缀(Biolink + Bioregistry)、适合裸 ID 的前缀、本体术语(通过 ID 或文本)、以及资源名称的 infores ID
apply_plan.py CROISSANT PLAN OUT将计划写入一个新的 croissant 文件
check.py CROISSANT PLAN OUT --report R --load-records先执行 --plan-only:在数秒内检查术语、前缀、方言和单位。然后执行完整检查:对照 Biolink 和采样数据检查术语、前缀、代码和方言,运行 MLCommons 验证器,通过 mlcroissant 读取少量记录(从每个文件开头读取,而非完整下载),并报告覆盖率

工作流程

  1. 调查阶段。 如果 croissant 文件旁边存在 semantics_answers.json,先读取它:其中包含了知识图谱维护人员对先前问题的回答(见下文“维护人员回答”)。不要再问这些相同的问题;apply_plan.py 和 check.py 会自动将这些答案应用到你的计划中。然后运行 inventory.py CROISSANT。记录知识图谱的信息(croissant 中的名称、描述、URL)以及记录集如何在布局中分布。大型知识图谱可能有数百个布局;从列表顶部开始处理。

    现在查找知识图谱自身的 infores ID(使用 vocab.py infores NAME;尝试其全名、缩写和 URL)并将其设置为计划的 infores。它命名了这些文件所属的资源,图构建者将其作为从文件中读取的所有内容的来源引用:没有它,转换阶段将根本无法构建知识图谱。当多个条目匹配时,选择发布这些文件的资源的 infores 值,而不是重新提供这些资源的服务(例如使用 infores:reactome,而不是 infores:automat-reactome)。check.py 会将其与计划其余部分的内容进行比较:单一的聚合器或 provided_by 常量也会命名知识图谱(HCOP 的直系同源由 infores:hgnc 聚合),不匹配则是一个需要解决的警告。

    如果没有匹配的条目,则提议一个新 ID:格式为 infores: 后跟知识图谱短名称的小写单词,以短横线连接(例如 infores:bioplex、infores:expression-atlas),并在计划中设置 "infores_proposed": true。然后使用 vocab.py infores-entry CROISSANT --id infores:NAME 编写其目录条目,如果文档清晰,则添加 --knowledge-level 和 --agent-type 参数,并将结果放在 notes.md 中,标题为 要注册的 Infores ID(靠近顶部)。在该处说明用户应通过向 infores 注册表提交拉取请求来注册该 ID(命令会打印注册位置),并且该 ID 可能在审核过程中更改。check.py 会对提议的 ID 保留警告,直到它被注册为止;不要解释性地忽略该警告。

  2. 选择要处理的布局。 目标是覆盖大多数记录集和核心内容(关联和主要实体表)的布局——通常是前 5 到 15 个布局,或者直到剩余的布局变得次要(类似自述文件、日志、每个版本的计数)。如果存在许多小布局(inventory.py 会提示这一点),则记录集可能共享核心列:使用 inventory.py --common-columns 并计划这些列一次,通过 match.has_columns 机制。你放弃的所有内容都放在计划的 skipped 列表中,并附上原因。少处理几个布局,但做得好,比处理很多布局但做得差更好。

  3. 对于每个布局,在决定任何内容之前先查看数据。

    • 使用 inventory.py CROISSANT --layout ID 查看列、描述和文件名。标记为 MIXED 的列在不同记录集中具有不同的原子类型(管道按文件推断);根据数据决定其类型并设置 atomic。
    • 对于表格,dialects.py detect CROISSANT --layout ID 查找文件在已知格式中的编写方式(注释行、是否有表头、分隔符)。众所周知的历史格式(VCF、GAF、MITAB)有公开的规范;依赖它们而不是重新发现格式。如果没有匹配的格式,则内联描述方言(reference/dialects.md)。然后使用 --dialect NAME 进行采样,以便按照格式规定的方式读取行,而不是猜测。
    • 使用 sample.py CROISSANT --layout ID 获取真实值。它读取该布局的三个文件(名称看起来最新的、最大的、最小的),因为单个文件——通常是旧的快照或筛选后的子集——可能隐藏某些值(如 N/A 占位符、额外的代码值、其他 ID 类型)。--files N 可以采样更多文件;--record-set ID 可以采样特定文件。如果采样失败(文件过大、压缩包、文件集),请在计划的 basis 中说明并降低置信度。
    • 对于代码列(类型、证据、关系、来源),采样可能会遗漏稀有值。使用 sample.py CROISSANT --record-set ID --profile COL1,COL2 读取整个文件并计算每个不同值的计数;重复 --record-set 可以添加多个文件。根据分析结果映射,而不是样本。
    • 对知识图谱的服务器保持温和。 每次针对一个知识图谱只运行一个采样或检查命令,切勿并行运行多个:主机会通过机器人挑战来阻止突发流量,然后后续所有请求都会失败。脚本会自我调节请求并缓存下载(位于 ~/.cache/croissant-semantics/downloads 中;--refresh 则重新下载),因此重新运行成本很低(在更大的 --max-mb 下缓存的一份副本可以服务于更小的副本)。如果脚本报告机器人挑战或 HTTP 403 错误,则停止对该主机进行采样,不要尝试绕过,并在 notes.md 中说明哪些检查无法运行。此后脚本会拒绝该主机一小时(跨运行),并从缓存文件中工作。
    • 电子表格(xlsx 和旧版 xls)、SQLite 数据库和 Parquet 文件也可以被采样和分析:工作表或表是记录集名称结尾所指示的那个(例如 "file.xlsx — Sheet1"、"file.xlsx: Sheet1"),采样在无法确定时会失败而不会猜测。这些文件会被完整读取,因此如果需要,请为 check.py 也增加 --max-mb。mlcroissant 无法读取电子表格或数据库,因此不会加载它们的记录。
    • XML、RDF(Turtle、RDF/XML、OWL)、FASTA 及其他非表格文件无法被采样:脚本会提示这一情况。如果某个布局很重要,请使用 OUT/work/ 中的一个小脚本检查其 ID(对于 RDF 使用 uv run --with rdflib;使用 xml.etree.ElementTree.iterparse 流式处理 XML),并在 notes.md 中说明检查方法。它们的字段通常没有 extract,因此没有工具可以读取它们:这是一个需要报告的发包方问题。
    • --profile 配合 --layout 用于分析该布局的 --files 个记录集(默认为 3,或使用 all)而不是使用 --record-set 逐一命名。--prefixes 计算每个值的前缀或标签,适用于所有分析列或仅列出的列(--prefixes COL1,COL2);--by COL 针对另一列进行交叉表分析(每个代码与哪些对象类型一起出现);--split SEP 统计列表单元格的项目数;--per-file 对每个记录集独立分析(以检查 ID 在每个文件中是否唯一);--stop-mb N 在 N MB 后停止处理每个文件,适用于数 GB 的大文件(计数因此仅覆盖文件开头;在以物种或 ID 排序的文件中,这可能仅是一个组,因此需要说明这一点)。
    • 在信任主要布局的 ID 列之前,先对其进行分析(使用 --profile COL --shapes):数据检查会读取几个文件的前几行,因此某个列在后面的行中可能缺少 ID 或包含另一类 ID,但仍然能通过检查。多个知识图谱在数百行拥有全部 ID 的行之后,发现有 20–30% 的行缺少 ID。
    • 一个覆盖多个布局的 match.has_columns 条目,其 check.py 仅会在少数几个文件上采样。在信任它之前,先对其涵盖的不同布局进行采样(使用 --record-set-name、--files)。
    • 脚本使用操作系统的证书存储。如果下载仍然因证书错误而失败,请连同输出一起报告;不要关闭验证。
    • 如果文档受到机器人检查的保护(如“验证你是人类”、Cloudflare 或 ALTCHA 挑战),不要尝试绕过;根据数据和名称进行计划,并对仅凭文档才能确认的含义将置信度上限设为 medium。Croissant 的出处信息可能引用了后来被置于检查之后的页面:仅引用你能读取到的内容。
    • 在大文件中,前几行可能不具有代表性(CTD 的 3 GB genes_diseases 文件以数千条推断行开头)。请分析同一布局中较小的文件(精选子集),而不是流式处理整个大文件。
    • 要按名称选择记录集,请使用 --record-set-name REGEX(代替 --layout),而不是在 shell 中构建 --record-set 参数列表(zsh 不会将变量拆分为单词)。--per-file 分别显示每个采样文件,适用于文件间存在差异的布局(每个文件一种 ID 类型)。
    • 数据检查读取几个文件的前几行。列的后面行可能不同(200 个 IRI 之后出现空白节点、稀有的代码):使用 --profile(读取整个文件)确认 ID 形式和代码。
    • inventory.py 在布局之后列出随数据一起提供的文档文件(zip 内的 README.pdf、数据字典)。阅读相关的文件:sample.py CROISSANT --dump FILE 将文件打印为文本,--member NAME 打印归档文件中的成员(zip 会被完整读取,因此对于大文件请增加 --max-mb)(当名称错误时,它会列出 zip 的成员),--sheet NAME 打印电子表格的工作表。
    • sample.py 会标记声明类型与值不匹配的列(例如 sc:Integer 列中存放着 27152464|29518214)以及行数比表头更宽或更窄的文件。两者通常是流水线问题:使用 atomic 修复类型,并进行报告。
    • 当脚本无法读取来源时,请自行获取文件(一次一个,放入 OUT/work/),并使用 --url-map OLD=file:///abs/path/ 将它们指向脚本,以便其检查仍能运行,而不是自己编写分析器。下载会被缓存,~/.cache/croissant-semantics/downloads/index.tsv 将每个缓存文件映射到其 URL。
    • 如果某个布局的“列名”实际上是数据(没有表头行,因此流水线将第一行数据当作列名,并且每个文件都成为自己的布局),则跳过它并在 notes.md 中将其报告为流水线问题。
    • 如果数据 URL 已失效(HTTP 404),知识图谱可能已迁移到更新的版本。从其下载页面找到当前的 URL,并将 --url-map OLD=NEW 传递给 sample.py 和 check.py(例如 --url-map 202607=202610)。当更改的内容不仅仅是版本号时(如路径或文件名也有变化),请映射整个 URL,每个文件一个 --url-map OLD_URL=NEW_URL。当 URL 本身包含 =(查询字符串)时,请使用 OLD=>NEW 的格式。在 notes.md 中说明这一点;这也是一个流水线问题。返回 JSON 的 SPARQL 端点 URL(而 croissant 描述为表格)通常需要映射 &format=csv(或 text/csv)参数。
    • 归档文件:zip 和 tar 归档文件中的成员可以被采样。Zip 文件会被完整下载(最大 --max-mb);tar 文件会流式处理,直到找到成员,因此位于巨大 tar 文件深处的成员可能会超过 --max-mb。曾经失败的归档文件不会再次尝试,采样在多次失败后停止。如果有必要,请自行将某个成员提取到 OUT/work/ 中,并在 notes.md 中记录你检查了什么以及如何检查的。
    • 如果数据需要登录或 API 密钥(HTTP 401/403,或 croissant 的 conditionsOfAccess 声明了此要求),请不要寻找凭据。仅根据文档和列名进行计划:source 为 documentation 或 agent,confidence 最多为 medium,并且 notes.md 中说明未对数据做任何检查。
    • 查找随附的数据字典...

相关技能