Ray API 策略权威指南:曝光级别、文档规范与弃用生命周期管理
【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址: https://gitcode.com/gh_mirrors/ra/ray
导读
Ray 是一个 AI 计算引擎,由核心分布式运行时与一组加速机器学习负载的 AI 库组成。对于这样一个被大量应用依赖的框架,公开 API 的任何变更都会直接冲击下游用户。本文基于仓库内 api-policy.md 与 stability.md 两份策略文档,系统梳理 Ray 的 API 曝光级别(Stable / Beta / Alpha / Deprecated / Developer)、文档编写强制规范、以及 API 在各级别之间升降级的生命周期管理规则(含"六个月或 +25 个 minor 版本"等具体期限),并结合 python/ray/util/annotations.py 的装饰器实现与 ci/lint/check_api_annotations.py 的自动化检查,讲清"何时声明、如何标注、怎样安全移除一个 Ray API"的完整流程。
一、什么是 Ray API 策略:一份对社区的承诺
Ray API 指类、类方法或函数。当 Ray 团队"声明"一个 API 时,实质上是向用户承诺:在后续 Ray 版本之间,这些接口不会随意变动,用户可以放心基于它开发应用。相应地,声明或弃用一个 API 都会对社区产生显著影响,因此仓库通过 api-policy.md 制定简单明确的策略,来约束贡献者兑现这些承诺、并管理用户的预期。
理解这份策略的前提是先搞清楚曝光级别(Exposure Level),即 stability.md 中定义的 API 稳定性分级体系(对应源码中的api-stability锚点):
| 级别 | 含义 | 稳定性承诺 |
|---|---|---|
| PublicAPI (stable) | 暴露给终端用户的公开 API | 在 major 版本生命周期内完全受支持,major 版本内不得有破坏性变更(极端情况除外) |
| PublicAPI (beta) | 公开但处于测试期 | 应尽量稳定,允许最小化变更,可含向后不兼容变更,但必须经过合理弃用期 |
| PublicAPI (alpha) | 面向少量已知用户的快速迭代组件 | 破坏性变更必须被允许且被预期,用户不得期望任何稳定性 |
| Deprecated | 已弃用 | 可能在未来的 Ray 版本中被移除 |
| DeveloperAPI | 显式暴露给高级用户和库开发者的低级接口 | 可能跨 minor 版本变更,无标注即默认为此级别 |
Ray 的 PublicAPI 稳定性定义参考了 Google 的稳定性分级指南(Google AIP-181),并根据自身发布节奏做了微调。
源码中的标注实现
在 python/ray/util/annotations.py 中,三种标注以装饰器形式实现,并统一维护一个AnnotationType枚举:
class AnnotationType(Enum): PUBLIC_API = "PublicAPI" DEVELOPER_API = "DeveloperAPI" DEPRECATED = "Deprecated" UNKNOWN = "Unknown"PublicAPI:支持stability("stable"/"beta"/"alpha",默认"stable")与api_group(仅用于文档渲染分组)两个关键字参数。对 alpha/beta 级别会向 docstring 自动追加 "PublicAPI (alpha/beta):This API is in alpha/beta and may change before becoming stable." 提示;可裸用(@PublicAPI)也可带参使用(@PublicAPI(stability="beta"))。DeveloperAPI:自动追加 "DeveloperAPI:This API may change across minor Ray releases.",接口可能跨 minor 版本变更。Deprecated:支持message(弃用原因与迁移路径说明)与warning(是否在运行时额外发出RayDeprecationWarning,默认False)两个参数。开启warning=True时,会通过包装函数在调用时发出warnings.warn(..., RayDeprecationWarning);对类则替换其__init__实现告警。文档字符串中会以.. warning::指令渲染弃用提示。
这些装饰器通过_mark_annotated在被标注对象上写入_annotated/_annotated_type/_annotated_api_group三个"魔法标记"(obj._annotated = obj.__name__),供后续自动化检查工具识别。
仓库内的真实使用示例
在 python/ray/_private/object_ref_generator.py 第 15 行、python/ray/_private/runtime_env/context.py 第 17 行等处可直接看到@DeveloperAPI的标注;python/ray/_private/ray_logging/logging_config.py 第 66 行则有@PublicAPI(stability="alpha")的实例。此外 python/ray/_common/deprecation.py 展示了社区自定义@Deprecated(new=..., error=False)风格的替代方案。
二、API 文档策略:每个曝光级别必须满足的文档义务
文档是 Ray 将 API 呈现给用户的主要渠道之一。信息一旦有误,会直接影响用户应用的可靠性与可维护性。基于曝光级别,api-policy.md 给出了如下强制规范:
| 策略 / 曝光级别 | Stable Public API | Beta Public API | Alpha Public API | Deprecated | Developer API |
|---|---|---|---|---|---|
| 该 API 是否必须编写文档? | 是 | 是 | 是 | 是 | 由开发者自行决定 |
| 方法是否必须标注一种 API 注解(PublicAPI / DeveloperAPI / Deprecated)? | 是 | 是 | 是 | 是 | 否。无注解默认即视为 Developer API 级别 |
该 API 是否可以设为私有(位于_internal模块内或带下划线前缀)? | 否 | 否 | 否 | 否 | 否 |
要点解读:
- 凡公开即须有文档:只要 API 属于公开级别(无论 stable/beta/alpha),甚至已弃用的 API,都必须有文档;只有 Developer API 允许"由开发者自行决定"。
- 标注是强制的:公开 API 必须且只能使用三种注解之一来声明身份。反向来看,没有注解的 API 默认就是 Developer API——这是很多贡献者容易忽略的隐含规则。
- 公开 API 不允许"假装私有":不能用
_internal模块、下划线前缀等私有化手段来规避公开 API 的稳定性承诺,各公开级别一律禁止。
自动化检查:check_api_annotations
策略并非纸面约束,仓库在 CI 中落地了自动化校验。 ci/lint/lint.sh 第 107-112 行显式调用:
./ci/lint/check_api_annotations.pyci/lint/check_api_annotations.py 会导入ray模块,递归扫描所有公开符号,对未标注的类/函数输出到异常列表,其逻辑核心是:
- 通过
_fullname(attr)计算全限定名,只检查名称包含"ray."的符号; - 跳过私有符号(
"._"前缀)以及IGNORE_PATHS中列出的路径(如.impl.、.backend.、.experimental.、.internal.、.generated.、.test_utils.、.annotations.、.deprecation.、.protobuf.、.cloudpickle.等); - 用 python/ray/util/annotations.py 中的
_is_annotated(attr)判断对象是否携带_annotated魔法标记且标记值等于自身__name__(避免子类继承父类标记造成误判)。
也就是说,一个公开的类或函数只要没有标注,CI 就会把它挑出来要求补标,从机制上保证"无标注 = Developer API"的策略不被破坏。
三、API 生命周期策略:级别升降级与参数变更的规则
用户对不同曝光级别抱有不同预期,因此在级别之间迁移 API 必须格外谨慎。api-policy.md 定义了完整的生命周期管理策略:
| 策略 / 曝光级别 | Stable Public API | Beta Public API | Alpha Public API | Deprecated API | Developer API |
|---|---|---|---|---|---|
| 能否在无任何警告或通知的情况下升级到更高级别? | 是 | 是 | 是 | 否 | 是 |
| 能否降级到更低级别?如果可以,方式是什么? | 只能降级为 Deprecated。API 应发出警告消息,弃用截止期限为六个月或 +25 个 Ray minor 版本,以先到者为准 | 只能降级为 Deprecated。API 应发出警告消息,弃用截止期限为三个月或 +12 个 Ray minor 版本,以先到者为准 | 用户必须允许并预期 alpha 组件的破坏性变更,不得期望任何稳定性 | 可以 | 无注解即默认为 Developer API |
| 能否移除或更改该 API 的参数? | 可以。API 应发出警告消息,并须为原版本的终结(end-of-life)设定截止期限,为六个月或 +25 个 Ray minor 版本,以先到者为准。过渡期内必须同时支持新旧参数 | 可以。API 应发出警告消息,变更截止期限为三个月或 +12 个 Ray minor 版本,以先到者为准。过渡期内必须同时支持新旧参数 | 用户必须允许并预期 alpha 组件的破坏性变更,不得期望任何稳定性 | 否 | 可以 |
策略核心解读
1. 升级(Promotion)是自由的:Stable、Beta、Alpha、Developer 都可以直接升级到更高级别,无需预先警告。唯一例外是 Deprecated——已弃用的 API 不能直接"复活"升级,必须走正常流程。
2. 降级(Demotion)有硬性时限:
- Stable → Deprecated:警告 + 弃用截止期限 =六个月或 +25 个 Ray minor 版本,以先到者为准。这是为了让 stable 用户有充分时间迁移。
- Beta → Deprecated:警告 + 截止期限 =三个月或 +12 个 Ray minor 版本,以先到者为准。时限显著短于 stable。
- Alpha 无降级概念:alpha 组件本身允许破坏性变更,用户被要求"不要期望稳定性",因此不需要冗长的弃用过渡期。
3. 参数变更与移除同样受时限约束:
- Stable 与 Beta 的参数移除/变更,分别遵循上述六个月/+25 与三个月/+12 的截止期限,且过渡期内必须同时支持新旧参数(双轨兼容),给用户迁移窗口;
- Alpha 不受此约束;
- Deprecated 的参数不可再变更(冻结)。
4. 时限的"双条件"逻辑:"六个月或 +25 个 minor 版本,以先到者为准"意味着无论时间先到还是版本号先到,弃用流程都必须在该节点完成——这同时保证了日历时间与发布节奏两个维度上的确定性,防止项目发版缓慢导致弃用遥遥无期,也防止发版过快导致迁移时间不足。
四、运行时弃用告警:Deprecated 注解的实战效果
策略要求"API 应发出警告消息",这一要求在源码层面由Deprecated装饰器的warning参数实现(见 python/ray/util/annotations.py 第 157-249 行):
@Deprecated(message="g() is deprecated because the API is error prone. " "Please call h() instead.", warning=True) def g(y): return y运行时会发出RayDeprecationWarning(继承自DeprecationWarning,便于细粒度过滤控制)。模块在导入时自动执行:
if not sys.warnoptions: warnings.filterwarnings("module", category=RayDeprecationWarning)即默认按"模块"维度打印每个模块首次出现的告警(与行号无关),避免刷屏。用户也可通过环境变量PYTHONWARNINGS="ignore::DeprecationWarning"抑制该警告。
针对类与函数/方法,告警包装策略不同:
- 类:替换
__init__,在实例化时告警; - 函数/方法:包装调用点告警,并通过
functools.wraps保留签名(对 property 等描述符不套@wraps,避免inspect.unwrap()破坏签名推导)。
另外,python/ray/_common/deprecation.py 还提供了带old/new/error参数的社区自定义弃用机制,测试见 python/ray/_common/tests/test_deprecation.py,可作为Deprecated注解的补充工具。
五、文档构建行为:写 API 前必须知道的渲染机制
策略文档特别提醒:API reference 是从源码自动生成的,因此公开 API 的写法会直接决定文档构建的成败。相关细节在 docs.md 的 "How the docs build renders your API signatures"(api-ref-build-behavior锚点)一节,有两个关键行为:
1. 重依赖被 mock,导入必须安全。文档构建只安装轻量依赖集,不安装 Ray 完整运行时。torch、tensorflow、pandas等重型/可选库会被替换为 mock 对象(清单见doc/source/conf.py中的autodoc_mock_imports),autodoc 才能在不导入这些库的情况下读取模块。注意:构建期间 Sphinx autodoc 会把typing.TYPE_CHECKING置为True,所以if TYPE_CHECKING:保护的导入依然会被执行,未 mock 就会导致构建失败。正确做法是把重依赖延迟到函数/方法内部导入;若新公开 API 的签名引入了新的重依赖,需把它加入autodoc_mock_imports。
2. 类型注解通过 intersphinx 链接外部文档。公开签名中出现numpy.ndarray、torch.Tensor等外部库类型时,构建会根据doc/source/conf.py的intersphinx_mapping将其转为指向该库文档的链接;只有库在映射中链接才可解析。新增引用外部库的公开 API 时,需同步更新intersphinx_mapping(通常也要更新autodoc_mock_imports)。解析不成功的注解只会以纯文本渲染,不会导致构建失败。
结合这两点可以理解:新增公开 API 不只是加个装饰器,还要考虑文档构建链路——导入安全性、mock 清单、intersphinx 映射都需要同步维护,这正是"API 文档策略"落地到工程实践的具体体现。
六、贡献者实操清单:新增、变更、移除一个 Ray API
综合 api-policy.md、stability.md 与源码实现,贡献者面对一个 Ray API 时应遵循以下流程:
新增 API
- 判断曝光级别:面向终端用户用
@PublicAPI(stable/beta/alpha),面向高级用户与库开发者用@DeveloperAPI; - 必须编写 docstring 文档(Developer API 可选),内容应自包含、可直接复制运行;
- 确保公开 API 不会被 CI 的
check_api_annotations.py检查挑出(即正确标注); - 若签名涉及重型依赖,延迟导入并更新
autodoc_mock_imports;若引用新外部库类型,更新intersphinx_mapping; - 不能放在
_internal模块或用下划线前缀"伪装私有"。
变更 API(参数增删/行为变化)
- Stable/Beta:发出警告消息,设定弃用截止期限(六个月/+25 或三个月/+12,先到者为准),过渡期内新旧参数并存;
- Alpha:允许破坏性变更,但需明确告知用户其不稳定性;
- Deprecated:参数冻结,不可再变更。
移除/弃用 API
- 用
@Deprecated(可带message说明迁移路径、warning=True触发运行时告警)标注; - 按曝光级别执行对应弃用时限(stable 六个月/+25,beta 三个月/+12);
- 期限到达后,才能安排移除。
验证与发布
- 运行 ci/lint/lint.sh 中的
./ci/lint/check_api_annotations.py确认标注合规; - 涉及文档变更时,在
doc/目录执行make rtd-build复现 Read the Docs 的完整构建(含fail_on_warning),或先用make local/make develop增量迭代(详见 docs.md)。
七、常见问题(FAQ)
Q1:一个 API 不标任何注解会怎样?默认视为 Developer API。它不受公开 API 的稳定性承诺约束,但会被check_api_annotations.py忽略(因为检查器只要求公开 API 标注),因此在文档中不应被当作公开接口宣传。
Q2:为什么弃用期限是"六个月或 +25 个 minor 版本"这种双条件?双条件保证无论项目发版快慢,弃用流程都有明确的完成节点:时间维度(六个月)防止发版缓慢时无限拖延,版本维度(+25 个 minor)防止发版频繁时迁移窗口过短。两个条件先到者触发。
Q3:可以把 stable API 直接降级为 Developer API 吗?不可以。策略规定 Stable/Beta 只能降级为Deprecated,不能直接降为 Developer API。Developer API 的"无注解默认级别"机制只适用于从未声明为公开 API 的符号。
Q4:alpha API 的破坏性变更需要弃用期吗?不需要。alpha 组件的定义就是"用户必须允许并预期破坏性变更,且不得期望稳定性",因此变更无需警告或过渡期——但应在文档与 docstring 中明确其 alpha 状态(装饰器会自动追加提示语)。
Q5:在哪里看到告警抑制方式?RayDeprecationWarning默认按模块过滤打印;设置环境变量PYTHONWARNINGS="ignore::DeprecationWarning"可整体抑制(该提示已内置在Deprecated装饰器的警告文案中,见 python/ray/util/annotations.py 第 203-207 行)。
八、总结
Ray 的 API 策略围绕"声明即承诺"展开:用PublicAPI(stable/beta/alpha)、DeveloperAPI、Deprecated三类注解明确每个公开接口的身份与稳定性预期,用文档策略保证每个公开 API 都有准确文档、都经过标注、都不允许私有化规避,用生命周期策略为级别迁移设定明确时限(stable 六个月/+25、beta 三个月/+12,先到者为准),并通过 ci/lint/check_api_annotations.py 的 CI 检查与 python/ray/util/annotations.py 的运行时告警将策略落为工程事实。这份策略既是贡献者的行为准则,也是用户评估"能否放心使用某个 Ray API"的依据。
【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址: https://gitcode.com/gh_mirrors/ra/ray
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考