news 2026/9/18 8:43:50

为 ZenML 实现自定义集成(Custom Integration)完整指南:从自定义 Flavor 到核心代码库贡献

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
为 ZenML 实现自定义集成(Custom Integration)完整指南:从自定义 Flavor 到核心代码库贡献

为 ZenML 实现自定义集成(Custom Integration)完整指南:从自定义 Flavor 到核心代码库贡献

【免费下载链接】zenmlZenML 🙏: One AI Platform from Pipelines to Agents. https://zenml.io.项目地址: https://gitcode.com/GitHub_Trending/ze/zenml

ZenML 将不断膨胀的 MLOps 工具生态抽象为统一的栈(Stack)与组件(Component)体系,而集成(Integration)机制则是这套体系对外开放的"插槽":它允许你把任意 MLOps 工具打包成一组可复用的栈组件 Flavor,并随 ZenML 主仓库分发给所有人。本文以 implement-a-custom-integration.md 为骨架,结合src/zenml/integrations/下的真实源码,完整讲解从规划集成、注册自定义 Flavor,到编写Integration子类、提交 Pull Request 的每一步,读完后你将具备为 ZenML 贡献一个生产级工具集成的全部实战能力。

一、前置知识:理解 ZenML 的集成体系

在动手之前,先明确三个概念之间的关系,这是本指南的前提:

  • Stack Component Type(组件类型):一个宽泛的功能类别,如orchestratorartifact_storeexperiment_tracker。ZenML 的完整类别列表可在 component-guide 中查看,包括 alerter、annotator、artifact store、container registry、data validator、deployer、experiment tracker、feature store、image builder、log store、model deployer、model registry、orchestrator、service connector、step operator 等。
  • Flavor(口味/实现变体):某一组件类型下的具体实现,例如artifact_store类型下有locals3等 Flavor。
  • Integration(集成):将一组相关 Flavor(以及 materializer、service connector、steps 等配套模块)打包的集合,是 ZenML 主代码库中的一等公民。

一个集成可以横跨多个组件类别。例如云厂商集成(AWS/GCP/Azure)同时包含 container registry、artifact store 等 Flavor;再如仓库中的 MLflow 集成 一次声明了实验追踪器(experiment tracker)、模型部署器(model deployer)与模型注册表(model registry)三个类别的 Flavor。因此规划阶段的第一步,就是先确定你的集成属于哪些类别。

从源码层面看,所有集成最终都汇聚在一个全局注册表中。IntegrationMeta元类在Integration子类创建时自动将其注册进integration_registry(见 integration.py),而注册表会遍历zenml.integrations包下所有含__init__.py的子目录并逐个导入(见 registry.py)。这意味着:只要你的集成目录结构正确、类定义完整,ZenML 就能在启动时自动发现它,无需额外注册中心。

二、Step 1:规划你的集成

这是成本最低、但最容易出错的步骤。请回答两个问题:

  1. 你的集成属于哪些类别?回到上文提到的组件类别清单,勾选与你的工具能力匹配的类别。例如要接入一个实验追踪工具,就对应experiment_tracker;要接入云端对象存储,就对应artifact_store;两者都要,就同时规划两个类别。
  2. 每个类别下要实现哪些 Flavor?一个类别下通常只需一个 Flavor,但也可以像 MLflow 那样为一个类别提供不同语义的多个 Flavor(MLFlowModelDeployerFlavorMLFlowExperimentTrackerFlavorMLFlowModelRegistryFlavor)。

建议同时研读 如何编写自定义栈组件,它会详细讲解StackComponentStackComponentConfigFlavor三个核心抽象——它们是后续所有实现的基础。

三、Step 2:先以"自定义 Flavor"形态开发并验证

不要急着打包成集成。先用 ZenML 的自定义 Flavor 机制把每个组件开发、测试到可用状态,再进入打包阶段,可以大幅降低集成开发的调试成本。

3.1 注册自定义 Flavor

假设你正在开发一个自定义 orchestrator,Flavor 类MyOrchestratorFlavor定义在flavors/my_flavor.py中,注册命令为:

zenml orchestrator flavor register flavors.my_flavor.MyOrchestratorFlavor

该命令的底层实现见 stack_components.py:它通过client.create_flavor(source=source, component_type=component_type)解析点分路径并创建 Flavor 模型,命令名由组件类型自动生成(artifact_storezenml artifact-store flavor register ...,orchestrator →zenml orchestrator flavor register ...)。

注册成功后,可用如下命令确认新 Flavor 已出现在列表中:

zenml orchestrator flavor list

list命令会调用client.get_flavors_by_type()拉取该类型下的全部 Flavor(内置与自定义的都会列出)。

3.2 关于解析路径的重要警告

⚠️ZenML 解析 Flavor 类的起点是zenml init初始化的仓库根目录,而不是当前所在目录。因此务必遵循最佳实践:在仓库根目录执行zenml init

如果 ZenML 在任何父目录中都找不到已初始化的仓库,它会退而使用当前工作目录作为解析起点——这种机制可以工作,但通常不应依赖它。

这一点在 CLI 源码中有直接体现:当client.root为空时,命令会打印警告"你的当前工作目录将被用作 source 参数的解析根目录,请在你的源码根目录运行zenml init以消除此警告"(见 stack_components.py);若加载失败,错误信息也会明确提示"请确保你已在仓库根目录运行过zenml init"。

四、Step 3:将组件打包成 Integration

当所有组件以自定义 Flavor 形态验证通过后,就可以开始打包,并最终并入 ZenML 主包。以下是完整的 checklist。

4.1 Clone 主仓库并搭建开发环境

参考仓库根目录的 CONTRIBUTING.md 完成本地开发环境配置。注意:集成开发是面向 ZenML 主代码库的贡献,因此需要在 ZenML 源码(而非你自己的独立仓库)中进行。

4.2 创建集成目录

所有集成都位于src/zenml/integrations/下的独立子目录中。一个典型的集成目录结构如下:

src/zenml/integrations/ <- ZenML 集成目录 <example-integration> <- 集成根目录 | ├── artifact-stores <- 按组件类型分目录存放 | ├── __init__.py | └── <example-artifact-store> <- artifact store 的实现类 ├── flavors | ├── __init__.py | └── <example-artifact-store-flavor> <- Config 类与 Flavor 类 | └── __init__.py <- Integration 类

以仓库中真实的 mlflow 集成目录 为参照,可以看到它按experiment_trackers/model_deployers/model_registries/flavors/services/steps/组织,与上述规范完全一致。实际项目中还常出现materializers/(自定义物化器)与utils/(工具函数)等子目录。

4.3 在 constants 中定义集成名称

在 src/zenml/integrations/constants.py 中新增一行常量:

EXAMPLE_INTEGRATION = "<name-of-integration>"

该常量名即zenml integration install <name-of-integration>命令中的集成名。从现有文件可以看出,仓库中每个集成都对应一个字符串常量,例如MLFLOW = "mlflow"AWS = "aws"WANDB = "wandb"等,共约 80 个。命名遵循"全大写 + 下划线"的 Python 常量惯例,值则使用小写连字符风格。

4.4 创建 Integration 类(init.py)

src/zenml/integrations/<YOUR_INTEGRATION>/__init__.py中创建Integration的子类,设置NAMEREQUIREMENTS属性,并覆写flavors类方法:

from typing import List, Type from zenml.integrations.constants import EXAMPLE_INTEGRATION from zenml.integrations.integration import Integration from zenml.stack import Flavor # 该 Flavor 名称将用于注册栈组件: # zenml <type-of-stack-component> register ... -f example-orchestrator-flavor EXAMPLE_ORCHESTRATOR_FLAVOR = "example-orchestrator-flavor" # 创建 Integration 类的子类 class ExampleIntegration(Integration): """Definition of Example Integration for ZenML.""" NAME = EXAMPLE_INTEGRATION REQUIREMENTS = ["<INSERT PYTHON REQUIREMENTS HERE>"] @classmethod def flavors(cls) -> List[Type[Flavor]]: """Declare the stack component flavors for the <EXAMPLE> integration.""" from zenml.integrations.example_flavor import ExampleFlavor return [ExampleFlavor] ExampleIntegration.check_installation() # 检查依赖是否已安装

对照基类源码(integration.py),Integration还提供了以下可扩展点:

成员类型/默认值说明
NAME类属性,默认"base_integration"集成唯一名称,必须与 constants 中的常量一致;IntegrationMeta用它做注册键
REQUIREMENTSList[str],默认[]集成的 Python 依赖列表(PEP 508 格式),由get_requirements()返回
APT_PACKAGESList[str],默认[]需要以系统包形式安装的依赖(如某些原生库)
REQUIREMENTS_IGNORED_ON_UNINSTALLList[str],默认[]卸载集成时不应移除的依赖前缀(防止误删公共依赖,参见 MLflow 集成中的用法)
check_installation()类方法逐个解析并校验依赖是否已安装(含传递依赖),供注册表与 CLI 使用
get_requirements()类方法返回依赖列表,可按目标 OS / Python 版本动态调整(MLflow 集成即在此追加 numpy、pandas 依赖)
activate()类方法激活钩子,用于注册 materializer、service connector 等运行时模块
flavors()类方法,默认返回[]声明本集成提供的全部 Flavor 类

4.5 在正确的位置导入

集成必须被导入到 src/zenml/integrations/init.py 中,以保证IntegrationMeta的自动注册机制生效。实际上,registry.py 会在首次访问时扫描zenml.integrations包下所有子目录并逐个importlib.import_module,因此__init__.py中的显式导入与注册表的自动发现共同构成了完整的加载链路。

五、源码级原理:注册表、依赖校验与激活机制

理解以下三个运行机制,能帮你写出符合 ZenML 内部约定的集成。

5.1 自动注册:IntegrationMeta元类

任何Integration子类(类名非Integration本身)在定义时都会被IntegrationMeta.__new__捕获,并以cls.NAME为键注册进全局单例integration_registry(integration.py)。注册表对外暴露list_integration_namesis_installed()get_installed_integrations()select_integration_requirements()等能力(registry.py)。

5.2 依赖校验:check_installation()

check_installation()遍历get_requirements()返回的每个依赖,用packaging.requirements.Requirement解析后调用requirement_installed()校验版本,还会递归校验每个依赖自身的传递依赖(integration.py)。因此你的REQUIREMENTS中每个条目都应是合法的 PEP 508 规范字符串,例如"mlflow>=2.1.1,<4"(见 MLflow 集成)。

5.3 激活钩子:activate()

activate_integrations()会对所有通过依赖校验的集成逐个调用activate(),用于"急切地"注册 materializer、service connector 等运行时模块;单个集成激活失败(如第三方库导入错误)不会阻断其他集成(registry.py)。MLflow 集成即在activate()中导入services模块来完成部署服务的注册。如果你的集成需要注册 materializer 或 service connector,覆写此方法即可。

六、实战参考:解剖 MLflow 集成

MLflow 集成是官方文档点名的范例,也是仓库中最完整的实现之一(src/zenml/integrations/mlflow/init.py)。它的设计值得照抄:

  • 多 Flavor 声明flavors()返回三个 Flavor——MLFlowModelDeployerFlavorMLFlowExperimentTrackerFlavorMLFlowModelRegistryFlavor,分别对应三个组件类别,Flavor 常量统一为"mlflow"
  • 动态依赖get_requirements()在基础依赖之外追加 numpy、pandas 的依赖,实现跨集成复用。
  • 卸载保护:通过REQUIREMENTS_IGNORED_ON_UNINSTALL声明python-rapidjsonpydanticnumpypandas为卸载时忽略的公共依赖。
  • 激活钩子activate()导入services子模块完成部署服务注册。

再看单个 Flavor 的构成(以 mlflow_experiment_tracker_flavor.py 为例),它清晰展示了 Flavor 类的三件套:

  • name属性返回 Flavor 名称("mlflow");
  • config_class返回 Pydantic 配置类MLFlowExperimentTrackerConfig(含tracking_uritracking_username/passwordtracking_token、Databricks 相关字段等,并使用SecretField标记敏感字段、用model_validator做凭据配对校验);
  • implementation_class返回真正实现组件逻辑的类MLFlowExperimentTracker

这与 Flavor 基类 定义的抽象接口(nametypeimplementation_classconfig_class)一一对应,你的集成 Flavor 也应遵循同样的模式。

七、Step 4:提交 Pull Request 并庆祝

完成以上所有步骤后,即可向 ZenML 仓库发起 Pull Request,等待核心维护者 review。提交前请自检:

  • 集成的每个 Flavor 都已作为自定义 Flavor 验证可用;
  • 目录结构符合src/zenml/integrations/<name>/规范,并按组件类型分子目录;
  • constants 中已添加集成名常量;
  • Integration子类设置了NAMEREQUIREMENTSflavors()返回完整列表;
  • 集成已在src/zenml/integrations/__init__.py中导入;
  • zenml integration install <name>zenml integration list行为符合预期。

完成这些,你就把一个新的 MLOps 工具真正融入了 ZenML 的集成生态,让所有 ZenML 用户都能通过一行zenml integration install使用它。

附:完整文件速查

  • 本文档: implement-a-custom-integration.md
  • 自定义栈组件指南:custom-stack-component.md
  • 集成常量定义:constants.py
  • Integration 基类与元类:integration.py
  • 集成注册表实现:registry.py
  • MLflow 集成范例:mlflow/init.py
  • Flavor 基类抽象:flavor.py
  • flavor register/flavor listCLI 实现:stack_components.py

【免费下载链接】zenmlZenML 🙏: One AI Platform from Pipelines to Agents. https://zenml.io.项目地址: https://gitcode.com/GitHub_Trending/ze/zenml

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 8:43:35

uniapp多端项目H5接口404原因与本地代理配置完全指南

如果你在uniapp项目里同时开发小程序、App和H5&#xff0c;大概率会碰到这个经典场景&#xff1a;代码在小程序端跑得好好的&#xff0c;接口数据正常返回&#xff0c;一切岁月静好&#xff1b;一切到H5&#xff0c;在浏览器里一打开&#xff0c;接口直接给你一个红色的404。第…

作者头像 李华
网站建设 2026/9/18 8:42:53

给 OpenAI 评估脚本的 API 入口交给 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 8:41:49

时序差分学习:从TD(0)到DQN的核心原理与实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 8:39:49

编译原理第八章:语义分析、属性文法与中间代码全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 8:37:41

HarmonyOS适配Steam Guard的TOTP算法实践

1. 项目背景与核心价值Steam平台作为全球最大的数字游戏分发平台之一&#xff0c;其账号安全机制一直备受关注。Steam Guard作为平台的两步验证系统&#xff0c;通过TOTP&#xff08;基于时间的一次性密码&#xff09;算法为账号提供额外的安全层。传统的Steam Guard验证通常需…

作者头像 李华
网站建设 2026/9/18 8:37:39

C++策略模式详解:原理、实现与应用场景

1. 策略模式基础概念解析策略模式(Strategy Pattern)是GoF设计模式中行为型模式的经典代表&#xff0c;它定义了算法家族并分别封装起来&#xff0c;让它们之间可以互相替换。这种模式的核心在于将算法的使用与实现分离&#xff0c;使得算法可以独立于使用它的客户端变化。在C中…

作者头像 李华