为 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(组件类型):一个宽泛的功能类别,如
orchestrator、artifact_store、experiment_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类型下有local、s3等 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:规划你的集成
这是成本最低、但最容易出错的步骤。请回答两个问题:
- 你的集成属于哪些类别?回到上文提到的组件类别清单,勾选与你的工具能力匹配的类别。例如要接入一个实验追踪工具,就对应
experiment_tracker;要接入云端对象存储,就对应artifact_store;两者都要,就同时规划两个类别。 - 每个类别下要实现哪些 Flavor?一个类别下通常只需一个 Flavor,但也可以像 MLflow 那样为一个类别提供不同语义的多个 Flavor(
MLFlowModelDeployerFlavor、MLFlowExperimentTrackerFlavor、MLFlowModelRegistryFlavor)。
建议同时研读 如何编写自定义栈组件,它会详细讲解StackComponent、StackComponentConfig、Flavor三个核心抽象——它们是后续所有实现的基础。
三、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_store→zenml artifact-store flavor register ...,orchestrator →zenml orchestrator flavor register ...)。
注册成功后,可用如下命令确认新 Flavor 已出现在列表中:
zenml orchestrator flavor listlist命令会调用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的子类,设置NAME与REQUIREMENTS属性,并覆写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用它做注册键 |
REQUIREMENTS | List[str],默认[] | 集成的 Python 依赖列表(PEP 508 格式),由get_requirements()返回 |
APT_PACKAGES | List[str],默认[] | 需要以系统包形式安装的依赖(如某些原生库) |
REQUIREMENTS_IGNORED_ON_UNINSTALL | List[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_names、is_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——MLFlowModelDeployerFlavor、MLFlowExperimentTrackerFlavor、MLFlowModelRegistryFlavor,分别对应三个组件类别,Flavor 常量统一为"mlflow"。 - 动态依赖:
get_requirements()在基础依赖之外追加 numpy、pandas 的依赖,实现跨集成复用。 - 卸载保护:通过
REQUIREMENTS_IGNORED_ON_UNINSTALL声明python-rapidjson、pydantic、numpy、pandas为卸载时忽略的公共依赖。 - 激活钩子:
activate()导入services子模块完成部署服务注册。
再看单个 Flavor 的构成(以 mlflow_experiment_tracker_flavor.py 为例),它清晰展示了 Flavor 类的三件套:
name属性返回 Flavor 名称("mlflow");config_class返回 Pydantic 配置类MLFlowExperimentTrackerConfig(含tracking_uri、tracking_username/password、tracking_token、Databricks 相关字段等,并使用SecretField标记敏感字段、用model_validator做凭据配对校验);implementation_class返回真正实现组件逻辑的类MLFlowExperimentTracker。
这与 Flavor 基类 定义的抽象接口(name、type、implementation_class、config_class)一一对应,你的集成 Flavor 也应遵循同样的模式。
七、Step 4:提交 Pull Request 并庆祝
完成以上所有步骤后,即可向 ZenML 仓库发起 Pull Request,等待核心维护者 review。提交前请自检:
- 集成的每个 Flavor 都已作为自定义 Flavor 验证可用;
- 目录结构符合
src/zenml/integrations/<name>/规范,并按组件类型分子目录; - constants 中已添加集成名常量;
Integration子类设置了NAME与REQUIREMENTS,flavors()返回完整列表;- 集成已在
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),仅供参考