From c3046684def584aba24c6fcf011c9e9594ea7ac9 Mon Sep 17 00:00:00 2001 From: zhouwei25 Date: Sat, 9 May 2026 13:00:16 +0000 Subject: [PATCH] [Code Agent] Update API compatibility skills documentation - Refactor api-change-decider skill description and documentation structure - Normalize allowed-tools formatting (remove invisible characters) - Update api-compatibility, api-docs-updater, cpp-sink, create-pr, python-decorator, and pytorch-alignment-validator skills with improved descriptions and content organization - Enhance documentation clarity and consistency across all API compatibility skills Co-Authored-By: Claude Opus 4.6 --- .../skills/api-change-decider/SKILL.md | 398 ++++++++++++------ .../.claude/skills/api-compatibility/SKILL.md | 261 +++++++----- .../.claude/skills/api-docs-updater/SKILL.md | 51 +-- .../.claude/skills/cpp-sink/SKILL.md | 154 +++---- .../.claude/skills/create-pr/SKILL.md | 102 ++++- .../.claude/skills/python-decorator/SKILL.md | 162 +++---- .../pytorch-alignment-validator/SKILL.md | 111 +++-- 7 files changed, 766 insertions(+), 473 deletions(-) diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-change-decider/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-change-decider/SKILL.md index 51250e43d43..ab7a6ac339f 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-change-decider/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-change-decider/SKILL.md @@ -1,7 +1,6 @@ --- name: api-change-decider -description: 仅用于《Paddle API 对齐 PyTorch 项目》,负责 Step1:方案决策,分析 PyTorch API 与 Paddle API 之间的差异,制定合适的 API 改动方案 -allowed-tools: Read Grep‌ Glob‌ WebSearch +description: 负责《Paddle API 对齐 PyTorch 项目》中 Step1:方案决策,分析 PyTorch API 与 Paddle API 之间的差异,制定合适的 API 改动方案 disable-model-invocation: false --- @@ -11,115 +10,176 @@ disable-model-invocation: false 需要对齐的 PyTorch API 列表(如 `torch.atan`、`torch.asinh`) ## 1.2 输出 -方案类型、对应 Paddle API、差异分类、决策依据(以表格形式展示) - -## 1.3 输出内容 -输出应包含如下内容,以表格式形式展示: -1. **方案类型**:从方案 1~6 中选择合适的方案(可组合多种方案,例如方案 3+方案 1) -2. **对应 Paddle API**:需改动的 Paddle API 完整路径(如 `paddle.nn.functional.dropout`) -3. **差异分类**:差异分类是什么 -4. **决策依据**:总结差异分析过程和选择理由 - - API 相对引用路径是否一致 - - 为什么选择该方案 - - 为什么不选择其他方案 - - 该方案是否会影响后向兼容 - -## 1.4 输出格式示例 -```markdown -# 决策结果 -|Pytorch API|方案类型|Paddle API|差异分类|决策依据| +以表格形式展示,列说明如下: + +| Pytorch API | 方案类型 | Paddle API | 差异分类 | 决策依据 | |-|-|-|-|-| -|torch.atan|方案 2|paddle.atan|torch 参数更多|仅参数名不同(input→x)+仅多 out 参数,Python 实现仅有一次`_C_ops.atan(x)`调用,满足 C++下沉条件,性能最优| -|torch.frexp|方案 3+方案 1|paddle.frexp|torch 参数更多|API 相对引用路径一致,差异为:1)仅参数名不同(input→x);2)仅多 out 参数。当前 Python 实现包含多个 paddle 操作调用(abs、floor、log2 等),逻辑较复杂,不满足 C++下沉条件。选择方案 3 修改 API,在末尾添加 out 参数(带默认值 None),保持后向兼容。同时方案 1 支持参数名不同的重载情况。| -``` +| 需对齐的 PyTorch API | 从方案 1~6 中选择 | 需改动的 Paddle API 完整路径 | 差异分类 | 总结差异分析过程和选择理由 | + +以下为示例表格: + +| Pytorch API | 方案类型 | Paddle API | 差异分类 | 决策依据 | +|-|-|-|-|-| +| torch.atan | 方案 2 | paddle.atan | torch 参数更多 | 仅参数名不同(input→x)+仅多 out 参数,Python 实现仅有一次`_C_ops.atan(x)`调用,满足 C++下沉条件,性能最优 | +| torch.select_scatter | 方案 1 | paddle.select_scatter | 仅参数名不一致 | input→x, src→values, dim→axis 参数名不同。底层调用 `_C_ops.set_value_with_tensor`(非 `_C_ops.select_scatter`),不满足方案 2 条件 1,降级为方案 1(Python 装饰器) | +| torch.Tensor.select_scatter | 方案 1 | paddle.Tensor.select_scatter | 仅参数名不一致 | 与 paddle.select_scatter 共享实现(patch 机制),随主 API 一并修改 | +| torch.logspace | 方案 3 + 方案 1 | paddle.logspace | 参数名不一致 + torch 参数更多 | 全文有两类差异:①end→stop/steps→num 参数名不同;②torch 多 out/device/requires_grad 参数。方案 3 末尾新增 out=None/device=None/requires_grad=False(后向兼容);方案 1 装饰器添加 end/stop、steps/num 别名 | + # 二、候选方案 ## 方案 1:Python 装饰器 **适用场景**: -- 在 Python 层添加装饰器实现对齐 -- 可对输入 `(*args, **kwargs)` 进行操作 -- 支持多种重载情况:参数名不同、参数顺序不同、参数个数不同、参数类型不同 -- 同时支持 torch 和 paddle 两套参数签名 +- 支持多种参数重载情况:参数名不同、参数顺序不同、参数个数不同、参数类型不同 +- 重载条件:能通过输入参数特征(名称、类型、个数)区分两套签名 **工作原理**: -- 根据输入参数的名称、类型、个数的不同来判断是 torch 签名还是 paddle 签名 -- 分别针对两套签名进行不同的功能适配,从而既保留了原本的 paddle 功能,也新增了 torch 功能 -- 这是方案 3(修改 API)的升级版,在保持后向兼容性的前提下实现对齐 +根据输入参数的名称、类型、个数判断是 PyTorch 签名还是 Paddle 签名,针对两套签名分别适配功能,既保留原有 Paddle 功能也实现了 PyTorch 对齐 -**核心要求**: -- **必须能够区分**:能够根据输入的参数类型、名称的不同来区分 torch 签名还是 paddle 签名 -- **无法区分则不适用**:如果无法通过输入参数特征区分两套签名,则方案 1 不适用 +**核心限制**: +- **重载条件**:能通过输入参数特征(名称、类型、个数)区分两套签名 +- **无法重载则不适用**:如果无法通过输入参数特征区分两套签名,则不适用 **优点**:灵活性强,兼容性好 -**缺点**:性能低于 C++下沉实现 +**缺点**:性能低于 C++ 下沉实现 -## 方案 2:C++下沉 +## 方案 2:C++ 下沉 **适用场景**: -- 将 API 直接下沉到 C++层 -- Paddle 机制支持在 C++层配置参数映射 -- **支持仅参数名不同的重载情况**(不涉及参数顺序或个数差异) -- **支持仅多 out 参数的情况** -- 方案 2 需要判断 API 的 Python 实现,需满足以下两个条件: - - 只有一次 `_C_ops.xxx` 调用 - - `_C_ops.xxx` 前面没有**前处理逻辑**,或虽有**前处理逻辑**但逻辑简单且不涉及其他 API 调用(如 x.flatten 等),容易改写为 C++ - - 注:分析时忽略静态图部分(LayerHelper 分支代码),该分支不再维护 - -**方案 2 不适用场景(满足其一则不适用)**: -- ❌ API 差异涉及参数顺序或个数差异 -- ❌ Python 实现里调用了其他**Paddle API**,如 x.flatten、paddle.flatten(x)等 -- ❌ 包含多个 `_C_ops.xxx` 调用 -- ❌ `_C_ops.xxx` 前面的**前处理逻辑**较为复杂,不容易被改写为 C++ +- 仅涉及参数名不同或仅多 out 参数的情况 + +**适用条件**(必须全部满足): +1. API 名称和 `_C_ops.xxx` 的 OP 名称一致 + - ✅ 正确示例:`paddle.atan` 调用 `_C_ops.atan` + - ❌ 错误示例:`paddle.select_scatter` 调用 `_C_ops.set_value_with_tensor`(名称不一致) +2. API 差异**仅为参数名不同或仅多 out 参数**(不涉及参数顺序或个数差异;"仅多 out 参数"的精确含义见 2.1 关键概念) +3. Python 实现中**仅有一次** `_C_ops.xxx` 调用 +4. Python 实现中不涉及其他 Paddle API 调用 + - ❌ **禁止**:调用任何其他 paddle API(如 `paddle.where`、`paddle.abs`、`paddle.flatten` 等) + - ❌ **禁止**:调用 Tensor 方法(如 `x.flatten()`、`x.reshape()`、`x.unsqueeze()` 等,这些等同于调用 paddle API) + - ❌ **禁止**:使用 `paddle.full_like`、`paddle.zeros_like`、`paddle.cast` 等 + - ✅ **允许**:Python 内置函数(如 `len()`、`isinstance()`、`list()`、`range()` 等) + - ✅ **允许**:简单的属性访问(如 `x.shape`、`x.dtype`、`x.ndim` 等) + - ✅ **允许**:简单的算术运算(如 `index + 1`、`axis < 0` 等) +5. `_C_ops.xxx` 前面**无复杂前处理逻辑**,前处理逻辑(如存在)容易改写为 C++ + - ❌ **复杂前处理**(不满足条件): + - 涉及多个 paddle API 调用的逻辑(如 `fill_constant`、`paddle.where`、`paddle.cast` 等) + - 复杂的 shape 处理逻辑(如 `reshape`、`transpose`、`flatten` 等) + - 条件分支中的 paddle API 调用 + - 循环中的 paddle API 调用 + - ✅ **简单前处理**(满足条件): + - 仅做参数校验(如 `isinstance()`、类型检查、范围检查) + - 仅做参数类型转换(如 `convert_np_dtype_to_dtype_`) + - 仅做简单参数处理(如负索引转正索引、默认值设置) + - 仅做属性获取(如 `x.shape`、`x.dtype`) + +**注意**: +- 读取 Python 实现逻辑时,忽略静态图部分(LayerHelper 分支代码不再维护) **优点**:性能最优 -**缺点**:仅支持参数名不同的情况 +**缺点**:限制条件很多,需严格满足 ## 方案 3:修改 API **适用场景**: -- 直接修改现有 API 实现对齐 -- 新增参数或功能 -- 修改原有参数或功能 - -**以下修改不会导致后向兼容问题,可开展**: -- ✅ 在 API 参数末尾添加参数,且参数具有默认值 -- ✅ 对已有 API 参数扩展新功能,保留原有功能 - -**以下修改会导致后向兼容问题,需禁止**: -- ❌ 改变已有参数顺序 -- ❌ 改变已有参数名称 -- ❌ 修改返回值类型 - -**优点**:直接对齐,实现简单 -**缺点**:可能导致后向不兼容 +- API 相对引用路径一致,但存在可通过修改原有实现来对齐的差异 +- 包括以下情况: + 1. **新增参数**:向现有 API 添加新参数(如添加 out 参数) + 2. **参数默认值调整**:修改参数默认值以对齐 PyTorch + 3. **扩展参数功能**:对已有参数扩展新功能同时保留原有功能 + 4. **参数用法调整**:修改参数的处理逻辑以支持不同用法 + +**适用条件**(必须全部满足)**: +1. API 相对引用路径一致 +2. 修改必须保持后向兼容性,例如: + - 在 API 参数末尾添加有默认值的参数 + - 对已有参数保留原有功能时,扩展新功能 + +**不适用条件**(❌ 禁止)**: +- 改变已有参数顺序 +- 改变已有参数名称 +- 修改返回值类型 +- 删除现有参数 +- 修改现有参数的默认值 ## 方案 4:新增 API **适用场景**: -- API 相对引用路径不一致 -- 新增的 API 需要与 Pytorch 完全一致,包括 API 相对引用路径、输入参数与返回值(名称、个数、功能均一致) - -**优点**:完全对齐,无后向兼容问题 +- 无法通过修改现有 API 实现对齐,需要新增 API 来实现功能 +- 具体包括以下情况: + 1. **API 相对引用路径不一致**:API 调用方式、模块路径与 PyTorch 不同 + 2. **仅 API 调用方式不一致**:API 相对引用路径不一致,但参数完全相同 + 3. **组合替代实现**:PyTorch API 需多个 Paddle API 组合实现 + 4. **API 别名**:为 PyTorch 别名 API 新增对应的 Paddle 别名 API + 5. **功能缺失**:Paddle 暂无等效实现,需新增完整 API ## 方案 5:新增 compat 类型 API **适用场景**: -- 在 `paddle/compat/__init__.py` 下新增 API -- 既无法原地修改(后向兼容性问题严重) -- 也无法新增 API(API 相对引用路径已被占用) +- 无法通过其他方案实现对齐的退而求其次方案 +- 具体包括以下情况: + 1. **无法原地修改**:修改现有 API 会引入严重的后向兼容性问题 + 2. **无法新增 API**:PyTorch 对应的 API 路径在 Paddle 中已被占用 + 3. **返回值不一致**:修改返回值类型会破坏现有调用 + 4. **无法重载**:通过装饰器无法根据输入参数特征区分两套签名 -**优点**:无后向兼容问题 -**缺点**:多一级 compat 路径,无法真正实现与 Pytorch 完全一致,实现之后差异分类将成为『仅 API 调用方式不一致』,在无其他方案时可以退而求其次选择 +**注意**: +- 新增对标 PyTorch 的兼容 API(位于 `paddle.compat.*` 路径下),不影响原 Paddle API +- 新增 API 需与 PyTorch 完全一致(路径、参数、返回值、行为) -## 方案 6:无需改动 -**适用场景**: -- API 完全一致 # 三、标准工作流程 -## Step 1: 分析差异文档 - -### 1.1 获取差异文档 -务必查阅每个 PyTorch API 对应的 API 差异文档(`torch.{api_name}.md`,位于 docs/docs/guides/model_convert/convert_from_pytorch/api_difference/目录下),如果实在无法找到差异文档,则说明该 API 已经实现了对齐一致,差异分类直接视作『API 完全一致』,无需再查询其他内容。 - -### 1.2 差异分类定义 +## Step 1: 差异分析 + +### 1.1 获取差异信息 + +> **⚠️ 短路逻辑(必须严格遵守)**: +> - 按**优先级 1 → 2 → 3 的顺序**依次尝试 +> - **一旦从某个来源获取到完整差异信息,立即停止,不再查找其他来源** +> - 这是"三选一"而非"三者都要",严禁同时查找多个来源 + +#### 优先级 1:查阅 API 差异文档 ⭐ +- 查阅 PyTorch API 对应的 API 差异文档(`torch.{api_name}.md`,位于 `${ROOT_DIR}/docs/docs/guides/model_convert/convert_from_pytorch/api_difference/` 目录下) +- 如果文档存在且信息完整(包含对应 Paddle API、转写示例),则以此为准 ✅ **→ 停止查找,进入下一步** +- 如果文档不存在或信息不完整 → 继续优先级 2 + +> **⚠️ 注意:差异文档标题仅反映主要分类,须阅读全文** +> - 差异文档的标题头(如 `[ torch 参数更多 ]`、`[ 仅参数名不一致 ]`)只选取了**最显著的一类差异**作为标题 +> - 一个 API 往往同时涉及多种差异,例如既有参数名不同,又有 torch 多出 out 参数 +> - 必须通读差异文档的**完整参数映射表**,提取所有差异点,不能仅以文件标题作为差异分类的唯一依据 + +#### 优先级 2:查询转写配置 ⭐⭐ +- 查询 PyTorch API 对应的转写配置(位于 `${ROOT_DIR}/PaConvert/paconvert/api_mapping.json` 或 `${ROOT_DIR}/PaConvert/paconvert/attribute_mapping.json`) +- 根据 Matcher 类型和字段内容分析差异分类和对应的 Paddle API +- 如果能从中获取到差异信息 ✅ **→ 停止查找,进入下一步** +- 如果转写配置不存在或无法获取信息 → 继续优先级 3 +- **转写配置字段说明**: + +| 字段 | 说明 | 对应差异分类 | +|------|------|------------| +| `Matcher: "ChangePrefixMatcher"` | API 完全一致,仅框架前缀不同(torch→paddle),无需任何参数转换 | API 完全一致 | +| `Matcher: "ChangeAPIMatcher"` | API 调用方式不同,但功能一致,无需参数转换 | 仅 API 调用方式不一致 | +| `Matcher: "NumelMatcher"` | 特定 API(如 torch.numel)的专用转换器 | 仅 API 调用方式不一致 | +| `Matcher: "TensorFunc2PaddleFunc"` | Tensor 类方法转为 Paddle 函数,如 `x.func()` → `paddle.func(x)` | 仅 API 调用方式不一致(无其他差异时) | +| `Matcher: "Func2Attribute"` | 函数调用转为属性访问,如 `x.func()` → `x.attr` | 仅 API 调用方式不一致(无其他差异时) | +| `Matcher: "Attribute2Func"` | 属性访问转为函数调用,如 `x.attr` → `x.func()` | 仅 API 调用方式不一致(无其他差异时) | +| `Matcher: "GenericMatcher"` | 通用转换器,适用于可直接映射的 API | 仅参数名不一致 / 仅 paddle 参数更多 / 仅参数默认值不一致 / torch 参数更多| +| `paddle_api` | 对应的 Paddle API 完整路径,如 `"paddle.transpose"` | 表示 API 映射关系| +| `kwargs_change` | 参数名映射关系,如 `{"input": "x", "dims": "perm"}` | 仅参数名不一致 | +| `unsupport_args` | 不支持的参数列表,如 `["stride"]` | torch 参数更多(部分不支持) | +| `paddle_default_kwargs` | Paddle 需要设置的默认参数,如 `{"axis": -1}` | 参数默认值不一致 / paddle 参数更多 | +| 其他自定义 `Matcher` | 除上述 Matcher 外的其他自定义 Matcher 名称 | 参数用法/类型不一致 / 组合替代实现等复杂情况 | + +- **注意**: +- 当 `TensorFunc2PaddleFunc`、`Func2Attribute`、`Attribute2Func` 同时包含 `unsupport_args`、`kwargs_change` 或 `paddle_default_kwargs` 字段时,说明除了调用方式差异外,还存在其他差异,不能归类为"仅 API 调用方式不一致" +- 更多的分类映射关系则需要自行分析,可结合 `${ROOT_DIR}/PaConvert/paconvert/api_matcher.py` 中对应 Matcher 的实现逻辑进行差异分类 + + +#### 优先级 3:网络搜索 API 文档 ⭐⭐⭐ +- 从网络中分别搜索: + 1. PyTorch 官方 API 文档(https://pytorch.org/docs/stable/) + 2. Paddle 官方 API 文档(https://www.paddlepaddle.org.cn/documentation/docs/zh/api/) +- 对比两者的 API 文档,手动分析差异,获取 API 的签名、参数、返回值等信息 + + +### 1.2 确定差异分类 差异分类共 13 类,具体如下: | 序号 | 差异分类 | 说明 | @@ -140,17 +200,20 @@ disable-model-invocation: false ### 1.3 提取差异信息 -提取相关差异信息,提供给 Step2 进行方案决策: +总结相关差异信息,提供给 Step2 进行方案决策: | 项目 | 内容 | |------|------| +| 差异分类 | 具体差异分类 | | API 映射 | PyTorch API vs 对应的 Paddle API(可能为空)| | 参数映射 | 参数对应关系和差异说明 | | 转写示例 | 代码转换示例 | 注意以下参数直接忽略,不视作差异信息: 1. 忽略第 1 列的 generator、memory_format、layout 参数 -1. 忽略第 2 列的 name 参数 +2. 忽略第 2 列的 name 参数 + +> 只能忽略上述明确列出的参数,**其他参数不可忽略**。例如 **device、out、requires_grad、dtype** 等不可忽略,必须处理。 ## Step 2: 方案决策 @@ -161,6 +224,12 @@ disable-model-invocation: false - 示例:`paddle.nn.functional.dropout` 的 API 相对引用路径是 `nn.functional.dropout` - 示例:`torch.Tensor.tile` 的 API 相对引用路径是 `Tensor.tile` +**仅多 out 参数**:torch 比 paddle **恰好只多一个参数**,且该参数名为 `out`,其余所有参数完全一致 +- ✅ 符合:torch 签名比 paddle 签名仅多 `out` 一个参数,其余参数完全一致 +- ❌ 不符合:torch 比 paddle 多两个及以上参数(即使其中包含 `out`,如同时多了 `out` 和 `requires_grad`) +- ❌ 不符合:torch 多的参数不是 `out`(如仅多 `dtype`) +- ❌ 不符合:除参数个数差异外,还存在参数名不同等其他差异(此时差异分类应合并为"torch 参数更多 + 参数名不一致",不满足"仅多 out 参数") + ### 2.2 关键原则 > **⚠️ 严格遵循**:决策时必须严格遵守以下原则,不得主观臆断: @@ -185,70 +254,163 @@ disable-model-invocation: false ↓ ↓ 具体有哪些差异? 方案 4(新增 API)→结束 │ - ├──→ API 完全一致 → 方案 6(无需改动)→结束 + ├──→ 1. API 完全一致 → 方案 6(无需改动)→结束 + │ + ├──→ 2. 仅 API 调用方式不一致 → 方案 4(新增 API)→结束 + │ + ├──→ 3. 仅参数名不一致 → 方案 2(C++下沉)→ 不适用则方案 1→结束 + │ + ├──→ 4. paddle 参数更多 → 是否影响对齐?─┬→否→方案 6(无需改动)→结束 + │ └→是→方案 3(修改 API)→导致后向不兼容则方案 5→结束 + │ + ├──→ 5. 参数默认值不一致 → 是否影响对齐?─┬→否→方案 6(无需改动)→结束 + │ └→是→方案 3(修改 API)→导致后向不兼容则方案 5→结束 + │ + ├──→ 6. torch 参数更多 → 仅多 out 参数(见 2.1 定义)?─┬→是→方案 2(C++下沉)→不适用则方案 1→结束 + │ └→否→方案 3(修改 API)→导致后向不兼容则方案 1→无法重载则方案 5→结束 + │ + ├──→ 7. 输入参数用法不一致 → 方案 3(修改 API)→导致后向不兼容则方案 1→无法重载则方案 5→结束 │ - ├──→ 仅参数名不一致 → 方案 2(C++下沉)→ 不适用则方案 1→结束 + ├──→ 8. 输入参数类型不一致 → 方案 3(修改 API)→导致后向不兼容则方案 1→无法重载则方案 5→结束 │ - ├──→ paddle 参数更多 → 是否影响对齐?─┬→否→方案 6(无需改动)→结束 - │ └→是→方案 3(修改 API)→存在兼容性则方案 5→结束 + ├──→ 9. 返回参数类型不一致 → 方案 5(新增 compat 类型 API)→结束 │ - ├──→ 参数默认值不一致 → 方案 3(修改 API)→存在兼容性则方案 5→结束 + ├──→ 10. 组合替代实现 → 方案 4(新增 API)→结束 │ - ├──→ torch 参数更多 → 仅多 out 参数?─┬→是→方案 2(C++下沉)→不适用则方案 3→存在兼容性则方案 1→无法区分则方案 5→结束 - │ └→否→方案 3(修改 API)→存在兼容性则方案 1→无法区分则方案 5→结束 + ├──→ 11. 可删除 → 方案 6(无需改动)→结束 │ - ├──→ 输入参数用法/类型不一致 → 方案 3(修改 API)→存在兼容性则方案 1→无法区分则方案 5→结束 + ├──→ 12. API 别名 → 方案 4(新增 API)→结束 │ - └──→ 返回参数类型不一致 → 方案 5(新增 compat 类型 API)→结束 + └──→ 13. 功能缺失 → 方案 4(新增 API)→结束 ``` ### 2.4 详细决策规则 -**前置判断**:以下规则均基于**API 相对引用路径一致**的前提。只要 API 相对引用路径不一致,直接选择**方案 4(新增 API)**,无需进入后续判断。 +**前置判断**:分类 3~10 判定规则均基于**API 相对引用路径一致**的前提。只要 API 相对引用路径不一致,直接选择**方案 4(新增 API)**,无需进行如下判断。 #### 1. API 完全一致 - **决策**:方案 6(无需改动) -#### 2. 仅参数名不一致 +#### 2. 仅 API 调用方式不一致 +- **决策**:方案 4(新增 API) +- **说明**:API 相对引用路径不一致,但参数完全相同,需要新增 API 来实现路径对齐 + +#### 3. 仅参数名不一致 - **优先级 1**:方案 2(C++下沉) - - **适用条件**:满足方案 2 适用条件(见第三部分定义) - - **优势**:性能最优 + - **前置检查**:确认满足方案 2 的全部适用条件 + - **任一不满足** → **优先级 2** - **优先级 2**:方案 1(Python 装饰器) - - **适用条件**:不满足方案 2 适用条件 + - 当方案 2 不满足时,使用方案 1 -#### 3. paddle 参数更多 +#### 4. paddle 参数更多 - **判断**:额外参数是否影响对齐 - - **否**(如默认参数,Paddle 保持默认即可)→ 方案 6(无需改动) + - **否**(例如默认参数,Paddle 保持默认即可)→ 方案 6(无需改动) - **是** → 方案 3(修改 API) - - **存在兼容性** → 方案 5(新增 compat 类型 API) + - **检查兼容性**:修改是否会引入后向不兼容问题 + - **会导致后向不兼容** → 方案 5(新增 compat 类型 API) -#### 4. 参数默认值不一致 +#### 5. 参数默认值不一致 +- **判断**:不一致的默认值是否影响对齐 + - **否**(例如不影响结果的参数)→ 方案 6(无需改动) + - **是** → 方案 3(修改 API) + - **检查兼容性**:修改是否会引入后向不兼容问题 + - **会导致后向不兼容** → 方案 5(新增 compat 类型 API) + +#### 6. torch 参数更多 +- **判断**:是否仅多 out 参数(详见 2.1 定义,必须满足"恰好只多一个参数且该参数名为 out") + - **是**: + - **优先级 1**:方案 2(C++下沉) + - **前置检查**:确认满足方案 2 的全部 5 个适用条件 + - **任一不满足** → **优先级 2** + - **优先级 2**:方案 1(Python 装饰器) + - **否**: + - **优先级 1**:方案 3(修改 API) + - **检查兼容性**:修改是否会引入后向不兼容问题 + - **会导致后向不兼容** → **优先级 2** + - **优先级 2**:方案 1(Python 装饰器) + - **检查能否区分**:能否根据输入参数特征区分两套签名 + - **无法重载** → **优先级 3** + - **优先级 3**:方案 5(新增 compat 类型 API) + +#### 7. 输入参数用法不一致 - **优先级 1**:方案 3(修改 API) -- **回退**:存在兼容性 → 方案 5(新增 compat 类型 API) - -#### 5. torch 参数更多 -- **子判断**:是否仅多 out 参数 - - **是** → 方案 2(C++下沉) - - **不适用** → 方案 3(修改 API)→ 存在兼容性则方案 1→ 无法区分则方案 5 - - **否** → 方案 3(修改 API)→ 存在兼容性则方案 1→ 无法区分则方案 5 + - **检查兼容性**:修改是否会引入后向不兼容问题 + - **会导致后向不兼容** → **优先级 2** +- **优先级 2**:方案 1(Python 装饰器) + - **检查能否区分**:能否根据输入参数特征区分两套签名 + - **无法重载** → **优先级 3** +- **优先级 3**:方案 5(新增 compat 类型 API) -#### 6. 输入参数用法/类型不一致 +#### 8. 输入参数类型不一致 - **优先级 1**:方案 3(修改 API) - - **存在兼容性** → 方案 1(Python 装饰器) - - **无法区分两套签名** → 方案 5(新增 compat 类型 API) + - **检查兼容性**:修改是否会引入后向不兼容问题 + - **会导致后向不兼容** → **优先级 2** +- **优先级 2**:方案 1(Python 装饰器) + - **检查能否区分**:能否根据输入参数特征区分两套签名 + - **无法重载** → **优先级 3** +- **优先级 3**:方案 5(新增 compat 类型 API) -#### 7. 返回参数类型不一致 +#### 9. 返回参数类型不一致 - **唯一决策**:方案 5(新增 compat 类型 API) - **原因**: - - ❌ 方案 3:修改返回值必然不兼容 - - ❌ 方案 1:装饰器只能根据输入区分,无法区分返回值差异 + - ❌ 方案 3:修改返回值必然存在兼容性问题 + - ❌ 方案 1:只能根据输入参数特征来实现重载,返回值不一致不满足重载条件 - ✅ 方案 5:在 compat 路径下新增,不影响原 API +#### 10. 组合替代实现 +- **决策**:方案 4(新增 API) +- **说明**:PyTorch API 需要多个 Paddle API 组合实现,通过新增 API 实现组合计算逻辑 + +#### 11. 可删除 +- **决策**:方案 6(无需改动) +- **说明**:PyTorch API 在 Paddle 中可直接删除,无需开发 + +#### 12. API 别名 +- **决策**:方案 4(新增 API) +- **说明**:为 PyTorch 别名 API 新增对应的 Paddle 别名 API + +#### 13. 功能缺失 +- **决策**:方案 4(新增 API) +- **说明**:Paddle 暂无等效实现,需要新增 API 来实现该功能 + ### 2.5 方案组合说明 > **重要提醒**:一个 API 可能涉及多种差异分类,需要综合分析所有差异点,可以组合多种方案来消除所有差异点。 -**示例**:`torch.frexp` 存在"仅参数名不同"和"仅多 out 参数"两个差异点 +**示例 1**:`torch.logspace` 差异文档标题为 `[ torch 参数更多 ]`,但全文实际涉及两类差异: +- 参数名不一致:`end→stop`、`steps→num` +- torch 参数更多:额外 `out`、`device`、`requires_grad` 参数 - **组合方案**:方案 3 + 方案 1 - - 方案 3:在末尾添加 out 参数(带默认值 None),消除"仅多 out 参数"差异 - - 方案 1:支持参数名不同的重载,消除"仅参数名不同"差异 + - 方案 3:在 `paddle.logspace` 末尾新增 `out=None`、`device=None`、`requires_grad=False` 参数(后向兼容),处理"torch 参数更多"差异 + - 方案 1:Python 装饰器添加参数别名 `end/stop`、`steps/num`,处理"参数名不一致"差异 + +**示例 2**:`torch.slice_scatter` 差异文档标题为 `[ 输入参数用法不一致 ]`,但全文实际涉及两类差异: +- 参数名不一致:`input→x`、`src→value`、`dim→axes`、`start→starts`、`end→ends`、`step→strides` +- 输入参数类型不一致:torch 各参数为 `int`,Paddle 对应参数为 `list of int` +- **组合方案**:方案 3 + 方案 1 + - 方案 3:扩展 `paddle.slice_scatter` 的 `axes`/`starts`/`ends`/`strides` 参数,使其同时支持 `int` 和 `list of int`(后向兼容),处理"输入参数类型不一致"差异 + - 方案 1:Python 装饰器添加参数别名 `input/x`、`src/value`、`dim/axes`、`start/starts`、`end/ends`、`step/strides`,处理"参数名不一致"差异 + + +# 四、常见问题处理 + +### Q1:如何判断方案 3 是否会导致后向不兼容? + +此问题仅适用于**流程图中标注"导致后向不兼容则方案 1/5"的分支**(如差异分类 6/7/8)。 + +**判断方法**:严格按照方案 3 的"不适用条件"判断: +- ❌ 改变已有参数顺序 → 后向不兼容 +- ❌ 改变已有参数名称(旧名不可用)→ 后向不兼容 +- ❌ 修改返回值类型 → 后向不兼容 +- ❌ 删除现有参数 → 后向不兼容 +- ❌ 修改现有参数的默认行为 → 后向不兼容 + +**示例**: +- `torch.tril_indices` 多 `device` 参数 → 在末尾添加 `device=None` → 不违反上述条件 → **后向兼容** → **方案 3** +- `torch.slice_scatter` 扩展参数类型(int → int|list)→ 不违反上述条件 → **后向兼容** → **方案 3** + +# 五、注意事项 + +1. 严格按标准工作流程执行,杜绝自行臆断和跳过步骤 +2. 所有路径使用 `${ROOT_DIR}` 变量表示根目录,需自行替换为实际路径 +3. 决策前检查 Paddle 代码的实际状态,差异文档可能滞后,代码反映真实情况(有可能已经完成了 Paddle 代码修改但未更正映射文档) diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-compatibility/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-compatibility/SKILL.md index b77209e5933..a266c88d16e 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-compatibility/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-compatibility/SKILL.md @@ -1,6 +1,7 @@ --- name: api-compatibility description: 开展《Paddle API 对齐 PyTorch 项目》,负责项目整体统筹规划,调用多个 skill,完成输入的 API 对齐 +allowed-tools: Read Write Edit Bash Glob Grep Agent Skill WebFetch WebSearch disable-model-invocation: true --- @@ -45,26 +46,34 @@ torch.logsumexp # 三、技术背景知识 -### 3.1 根目录说明 +### 3.1 工作目录说明 -| 目录名称 | 内容说明 | 对应步骤 | -|---------|---------|---------------| -| Paddle | 包含所有 Paddle API 的实现 | Step2:代码修改 | -| PaConvert | 包含所有 Pytorch 单元测试 | Step3:对齐验证 | -| docs | 包含所有 Paddle API 中文文档 | Step4:文档更新 | -| Paddle、PaConvert、docs | 代码提交对象 | Step5:代码提交 | +**ROOT_DIR 变量定义**: +- `${ROOT_DIR}` 是项目的根工作目录变量,例如 `/workspace`、`/home/user/projects` 等 +- 本项目涉及的三个仓库位于 `${ROOT_DIR}` 下: + - `${ROOT_DIR}/Paddle`:Paddle 框架源码仓库 + - `${ROOT_DIR}/PaConvert`:PyTorch 转换工具仓库 + - `${ROOT_DIR}/docs`:Paddle 文档仓库 +- 在实际执行时,需自行分析环境并将 `${ROOT_DIR}` 替换为实际路径 + +| 工作目录 | 完整路径 | 内容说明 | 对应步骤 | +|---------|---------|---------|---------------| +| Paddle | `${ROOT_DIR}/Paddle` | 包含所有 Paddle API 的实现 | Step2:代码修改 | +| PaConvert | `${ROOT_DIR}/PaConvert` | 包含所有 Pytorch 单元测试 | Step3:对齐验证 | +| docs | `${ROOT_DIR}/docs` | 包含所有 Paddle API 中文文档 | Step4:文档更新 | +| Paddle、PaConvert、docs | - | 代码修改 Diff | Step5:代码提交 | ### 3.2 相关文件位置 |**功能模块**|**检索关键字**|**文件路径**|**举例**|**注意**| |-|-|-|-|-| -|API 中文文档|`{api_name}_cn.rst`|docs/docs/api/paddle/|tan_cn.rst|| -|API 差异文档|`torch.{api_name}.md`|docs/docs/guides/model_convert/convert_from_pytorch/api_difference/|torch.tan.md|| -|C++下沉使用|`python_api_info.yaml`、`ops.yaml`|Paddle/paddle/phi/ops/yaml/|python_api_info.yamlops.yaml|| -|C++下沉使用|`_paddle_docs.py`|Paddle/python/paddle/|_paddle_docs.py|| -|Paddle API 实现位置|`def {api_name}` 或 `class {api_name}`|Paddle/python/paddle/|Paddle/python/paddle/tensor/ops.py|不要误检索到 sparse 目录下(稀疏 API 位置),本项目与稀疏无关,所有 sparse 相关文件直接忽略| -|Paddle API 兼容性单测位置|`test_api_compatibility.py`|Paddle/test/legacy_test/test_api_compatibility.py|| -|Pytorch API 单测位置|`test_{api_name}.py`|PaConvert/tests/|PaConvert/tests/test_tan.py|| +|API 中文文档|`{api_name}_cn.rst`|`${ROOT_DIR}/docs/docs/api/paddle/`|tan_cn.rst|| +|API 差异文档|`torch.{api_name}.md`|`${ROOT_DIR}/docs/docs/guides/model_convert/convert_from_pytorch/api_difference/`下一级目录|torch.tan.md|| +|C++下沉使用|`python_api_info.yaml`、`ops.yaml`|`${ROOT_DIR}/Paddle/paddle/phi/ops/yaml/`|python_api_info.yaml、ops.yaml|| +|C++下沉使用|`_paddle_docs.py`|`${ROOT_DIR}/Paddle/python/paddle/`|_paddle_docs.py|| +|Paddle API 实现位置|`def {api_name}` 或 `class {api_name}`|`${ROOT_DIR}/Paddle/python/paddle/*/`|`${ROOT_DIR}/Paddle/python/paddle/tensor/math.py`|不要误检索到 sparse 目录下(稀疏 API 位置),本项目与稀疏无关,所有 sparse 相关文件直接忽略| +|Paddle API 兼容性单测位置|`test_api_compatibility_part[1-9]\.py`|`${ROOT_DIR}/Paddle/test/legacy_test/`|test_api_compatibility_part3.py|| +|Pytorch API 单测位置|`test_{api_name}.py`|`${ROOT_DIR}/PaConvert/tests/`|test_tan.py|| ### 3.3 Paddle API 架构(5 层调用栈) @@ -73,10 +82,10 @@ Paddle API 从上到下由 5 层组成(本项目直接修改第 1、5 层, | 层级 | 名称 | 语言 | 文件位置 | 功能说明 | 是否修改 | |------|------|------|----------|----------|----------| | 1 | Python 层 | Python | `*.py` | API 的 Python 接口定义 | ✅ **修改** | -| 2 | Pybind 层 | C++ | 根据`*.yaml`自动生成(`paddle/fluid/pybind/eager_op_function.cc`)| Python 与 C++的绑定层 | ✅ **修改 yaml 配置来实现修改** | -| 3 | Dygraph 层 | C++ | 根据`*.yaml`自动生成(`paddle/fluid/eager/.../dygraph_functions.cc`)| 前反向传播组合 | ❌ 通常不改 | -| 4 | C++ API 层 | C++ | 根据`*.yaml`自动生成(`paddle/phi/api/lib/api.cc`) | Kernel 选择调度 | ❌ 通常不改 | -| 5 | Kernel 层 | C++ | `paddle/phi/kernels/` | 实际计算逻辑实现 | ✅ **修改** | +| 2 | Pybind 层 | C++ | 根据`*.yaml`自动生成(`${ROOT_DIR}/Paddle/paddle/fluid/pybind/eager_op_function.cc`)| Python 与 C++的绑定层 | ✅ **修改 yaml 配置来实现修改** | +| 3 | Dygraph 层 | C++ | 根据`*.yaml`自动生成(`${ROOT_DIR}/Paddle/paddle/fluid/eager/.../dygraph_functions.cc`)| 前反向传播组合 | ❌ 通常不改 | +| 4 | C++ API 层 | C++ | 根据`*.yaml`自动生成(`${ROOT_DIR}/Paddle/paddle/phi/api/lib/api.cc`) | Kernel 选择调度 | ❌ 通常不改 | +| 5 | Kernel 层 | C++ | `${ROOT_DIR}/Paddle/paddle/phi/kernels/` | 实际计算逻辑实现 | ✅ **修改** | **示例 API 层级**: ```python @@ -108,8 +117,8 @@ void AtanKernel(const Context& dev_ctx, const DenseTensor& x, DenseTensor* out) | PyTorch API | `torch.*` 系列接口 | 约 2000+个 API,是本项目的**对齐标准**| | Paddle API | `paddle.*` 系列接口 | 约 2000+个 API,是本项目的**修改对象** | | API 对齐 | 使两个 API 的行为完全对齐一致 | 对齐包括 API 相对引用路径、输入参数、返回值、计算逻辑等| -| API 中文文档 | 中文描述了该 API 的功能与行为 | 位于 docs/docs/api/paddle/目录,命名类似 tan_cn.rst | -| API 差异文档 | 中文描述了 Pytorch API 与 Paddle API 两者的行为差异 | 位于 docs/docs/guides/model_convert/convert_from_pytorch/api_difference/下的一级子目录,命名类似 torch.tan.md | +| API 中文文档 | 中文描述了该 API 的功能与行为 | 位于 `${ROOT_DIR}/docs/docs/api/paddle/` 目录,命名类似 tan_cn.rst | +| API 差异文档 | 中文描述了 Pytorch API 与 Paddle API 两者的行为差异 | 位于 `${ROOT_DIR}/docs/docs/guides/model_convert/convert_from_pytorch/api_difference/` 下一级子目录,命名类似 torch.tan.md | | compat 类型 API | 兼容性 API | 为保持后向兼容而添加的 API,能实现除 API 相对引用路径之外的完全对齐,实现之后差异分类将成为『仅 API 调用方式不一致』| ### 3.5 类方法 API 实现原理 @@ -119,9 +128,9 @@ void AtanKernel(const Context& dev_ctx, const DenseTensor& x, DenseTensor* out) - **类方法 API**(如`torch.Tensor.abs`):`torch.Tensor`类方法 - **普通 API**(如`torch.abs`):普通方法 -Paddle 的 Tensor 类方法通过**patch 机制**实现,即将普通方法动态添加到`paddle.Tensor`(即`core.eager.Tensor`)类上成为类方法。 +Paddle 的 Tensor 类方法通过**patch 机制**实现,即将普通方法动态添加到`paddle.Tensor`(即`core.eager.Tensor`)类上成为类方法,因此两者虽然是不同 API,但实现一致,合并处理即可。 -**实现机制**(参考`Paddle/python/paddle/base/dygraph/math_op_patch.py`): +**实现机制**(参考`${ROOT_DIR}/Paddle/python/paddle/base/dygraph/math_op_patch.py`): ```python # 从 paddle.tensor 模块获取方法定义 @@ -177,9 +186,34 @@ Paddle 支持自动生成 inplace API,无需在`ops.yaml`中单独配置。当 use_default_mapping : True ``` -# 四、标准工作流程 +# 四、整体工作流程 + +## 执行逻辑 +1. 接收用户输入的待对齐 API 列表(如 `torch.argmax`, `torch.log2`, `torch.logsumexp`) +2. **批量处理模式**:依次执行,每个 Step 结束后才进入下一个 Step + - Step1:对**所有 API**进行方案决策,记录每个 API 的方案类型 + - Step2:对**所有 API**进行代码修改 + - Step3:对**所有 API**进行对齐验证 + - Step4:对**所有 API**更新文档 + - Step5:对**所有 API**进行代码提交 +3. **流程推进的豁免与放弃条件**: + - **豁免条件**: + * 每一个执行步骤均需调用相应的 skill 来执行 + * 当前仅支持方案 1、方案 2,若为其他方案,由于无对应 skill,无需处理,直接跳过该 API + - **放弃条件**(合理分配精力,最大化成功率): + * **放弃判断标准**: + - 当某个 API 在 Step2 或 Step3 经过多次尝试(建议 3 次)仍无法通过验证 + * **放弃执行要求**: + - ⚠️ 必须完整回退该 API 在 Step2 和 Step3 中的所有代码修改 + - ⚠️ 确保项目处于干净状态,不得保留任何"修改了但没改对"的中间状态 + - 在最终的对齐结果统计表中标记该 API 为"未对齐",并简要说明放弃原因 + * **整体策略原则**: + - 目标是最大化 API 列表的整体对齐成功率,而非执着于单个 API + - 优先处理更可能成功的 API,避免在困难 API 上消耗过多时间 + - 放弃是为了提高整体效率的理性决策,不是逃避问题 +4. 所有 API 都完成 5 个步骤(除被豁免或放弃外)后,任务结束 -## 4.1 流程概览 +## 流程概览 ``` 输入 API 列表 → Step1:所有 API 方案决策 → Step2:所有 API 代码修改 → Step3:所有 API 对齐验证 → Step4:所有 API 文档更新 → Step5:代码提交 → 全部完成(流程全自动推进,不用询问) @@ -192,135 +226,87 @@ Paddle 支持自动生成 inplace API,无需在`ops.yaml`中单独配置。当 ### Step 2:代码修改 #### 方案 1:Python 装饰器(调用 `/python-decorator` skill) - Step 2.1: 差异分析与选择装饰器 - Step 2.2: 应用或开发装饰器 - Step 2.3: 添加 out 参数支持 - Step 2.4: 更新函数文档字符串 - Step 2.5: 添加测试用例 - Step 2.6: 编译并运行 + Step 1.1: 差异分析与选择装饰器 + Step 1.2: 应用或开发装饰器 + Step 1.3: 添加 out 参数支持 + Step 1.4: 更新函数文档字符串 + Step 1.5: 添加测试用例 + Step 1.6: 编译并运行 #### 方案 2:C++下沉(调用 `/cpp-sink` skill) Step 2.1: 配置 python_api_info.yaml Step 2.2: 迁移文档到_paddle_docs.py Step 2.3: 替换 Python 实现 Step 2.4: 添加测试用例 Step 2.5: 编译并运行 +#### 方案 3~5:无对应 skill,无需处理,直接跳过 ### Step 3:对齐验证(调用 `/pytorch-alignment-validator` skill) Step 3.1: 标记已对齐的 API - Step 3.2: 补充测试用例 + Step 3.2: 增加测试用例 Step 3.3: 运行单元测试 ### Step 4:文档更新(调用 `/api-docs-updater` skill) - Step 4.1: 获取代码变更信息 - Step 4.2: 更新 API 中文文档 ### Step 5:代码提交(调用 `/create-pr` skill) -**执行逻辑**: -1. 接收用户输入的待对齐 API 列表(如 `torch.argmax`, `torch.log2`, `torch.logsumexp`) -2. **批量处理模式**:按 Step 顺序依次执行,每个 Step 处理完所有 API 后才进入下一个 Step - - Step1:对**所有 API**进行方案决策,记录每个 API 的方案类型 - - Step2:对**所有 API**进行代码修改 - - Step3:对**所有 API**进行对齐验证 - - Step4:对**所有 API**更新文档 - - Step5:对**所有 API**进行代码提交 -3. **流程推进的豁免与放弃条件**: - - **豁免条件**: - * 每一个执行步骤均需调用相应的 skill 来执行 - * 当前仅支持方案 1/2,若决策为其他方案,则该 API 跳过,只需记录决策结果即可,不要自行处理 - - **放弃策略**(合理分配精力,最大化成功率): - * **放弃判断标准**: - - 当某个 API 在 Step2 或 Step3 经过多次尝试(建议 3 次)仍无法通过验证 - - 经分析判断短期内难以解决,继续投入时间成本过高 - * **放弃执行要求(必须严格遵守)**: - - ⚠️ 必须完整回退该 API 在 Step2 和 Step3 中的所有代码修改 - - ⚠️ 确保项目处于干净状态,不得保留任何"修改了但没改对"的中间状态 - - 在最终的对齐结果统计表中标记该 API 为"未对齐",并简要说明放弃原因 - * **整体策略原则**: - - 目标是最大化 API 列表的整体对齐成功率,而非执着于单个 API - - 优先处理更可能成功的 API,避免在困难 API 上消耗过多时间 - - 放弃是为了提高整体效率的理性决策,不是逃避问题 -4. 所有 API 都完成 5 个步骤(除被豁免或放弃外)后,任务结束 - - -## 4.2 详细步骤 +## 详细步骤 ### Step 1: 方案决策 ⚙️ -**目标**:确定每个 API 的改动方案 +**调用**:`/api-change-decider` skill -**执行步骤**: -1. 输入:需要对齐的 PyTorch API 列表(如 `torch.atan`、`torch.asinh`) -2. 调用 `/api-change-decider` skill -3. 输出:方案类型、对应 Paddle API、差异分类、决策依据 +**输入**:需要对齐的 PyTorch API 列表(如 `torch.atan`、`torch.asinh`) -**方案类型**: -- 无需改动 -- 方案 1:Python 装饰器 -- 方案 2:C++下沉 -- 方案 3:修改 API -- 方案 4:新增 API -- 方案 5:新增 compat 类型 API +**输出**: +- 方案类型(无需改动/方案 1~5) +- 对应 Paddle API +- 差异分类 +- 决策依据 ### Step 2: 代码修改 💻 -**目标**:根据方案修改 Paddle API 代码 +**根据方案类型调用对应 skill**: +- 方案 1 → `/python-decorator` +- 方案 2 → `/cpp-sink` +- 方案 3/4/5 → 无对应 skill,无需处理,直接跳过 +- 方案 6 → 无需处理,直接跳过 -**执行步骤**: -1. 输入:方案类型、对应 Paddle API(如 `paddle.atan`、`paddle.asinh`)、差异分类、决策依据 -2. 根据方案类型,调用对应的子智能体,每个子智能体批量处理其所负责的 API: - - 方案 1 → 调用 `/python-decorator` skill - - 方案 2 → 调用 `/cpp-sink` skill - - 方案 3 → `/python-decorator`和`/cpp-sink`skill 支持新增 out 参数,其他修改无对应 skill 支持,豁免 - - 方案 4 → 无对应 skill 支持,豁免 - - 方案 5 → 无对应 skill 支持,豁免 -3. 输出:是否代码修改无误(即单测运行通过) - -**异常处理**: -- 本步骤多次调试仍异常时,主控智能体根据报错信息评估,是否需要回退到前序步骤: - - 是否 Step1 中有 API 的方案决策错误? +**输出**:代码修改是否完成 +**异常处理**:如多次尝试仍失败,需回退到 Step1 重新决策 ### Step 3: 对齐验证 ✅ **(金标准)** -**目标**:验证修改后的 Paddle API 能与 PyTorch API 完全对齐 +**调用**:`/pytorch-alignment-validator` skill + +**输入**:PyTorch API 列表 -**执行步骤**: -1. 输入:PyTorch API 列表(如 `torch.atan`、`torch.asinh`) -2. 调用 `/pytorch-alignment-validator` skill -3. 输出:是否通过对齐验证(即单测运行通过) +**输出**:验证是否通过 -**异常处理**: -- 本步骤多次调试仍异常时,主控智能体根据报错信息评估,是否需要回退到前序步骤: - - 是否 Step1 中有 API 的方案决策错误? - - 是否 Step2 中有 API 的代码实现有误? +**异常处理**:如多次尝试仍失败,需回退到 Step2 调整实现或 Step1 重新决策 ### Step 4: 文档更新 📝 -**目标**:更新 Paddle API 中文文档 +**调用**:`/api-docs-updater` skill -**执行步骤**: -1. 调用 `/api-docs-updater` skill +**输入**:已修改的 API 信息 -**异常处理**: -- 文档更新必须与 Step2 中的代码修改保持同步 -- 确保文档准确反映代码的最新行为 +**输出**:文档是否更新完成 ### Step 5: 代码提交 📤 -**目标**:提交修改后的代码到 Paddle、PaConvert、Docs 仓库 +**调用**:`/create-pr` skill + +**输入**:已修改的代码 -**执行步骤**: -1. 调用 `/create-pr` skill -2. 在对应的三个仓库分别创建或更新 Pull Request -3. 包含代码修改、测试用例和文档更新 +**输出**:PR 是否创建成功 -## 4.3 重要约束 ⚠️ +## 重要约束 ⚠️ 1. **流程正向推进原则** - 正常情况下必须遵循 Step1 → Step2 → Step3 → Step4 → Step5 的顺序 - 每个步骤完成并验证通过后,才能进入下一步骤 - - 禁止跳过任何步骤(特别是 Step3 对齐验证步骤和 Step5 代码提交步骤) + - 禁止跳过任何步骤(特别是 Step3 对齐验证步骤) 2. **异常回溯调整原则** - 当 Step2(代码修改)或 Step3(对齐验证)多次尝试仍无法通过时 @@ -335,7 +321,7 @@ Paddle 支持自动生成 inplace API,无需在`ops.yaml`中单独配置。当 - 所有步骤的产出物(代码、测试、文档、PR)必须齐全 -## 4.4 工作示例 +## 工作示例 假设待对齐 API 为 `torch.argmax`: @@ -354,7 +340,7 @@ Paddle 支持自动生成 inplace API,无需在`ops.yaml`中单独配置。当 - ✅ 改动位置如果方便注释,可以注释`# Edit by AI Agent`,但只能注释 1 次 ## 5.2 代码质量规范 -- ✅ 保持代码风格与项目一致 +- ✅ 保持代码风格与原项目一致 - ✅ 不破坏现有功能 - ✅ 确保向后兼容性 @@ -369,7 +355,54 @@ Paddle 支持自动生成 inplace API,无需在`ops.yaml`中单独配置。当 - ✅ 文档格式符合 Paddle 规范 - ✅ 准确描述 API 功能和参数 -# 六、注意事项 +# 六、各 Skill 说明 -1. 复盘记忆中的历史易错点,避免重复犯错 -2. 严格按标准工作流程执行,杜绝自行臆断和跳过步骤 +| Skill | 对应步骤 | 功能说明 | +|-------|--------|---------| +| `/api-change-decider` | Step1:方案决策 | 分析 PyTorch 与 Paddle API 差异,制定改动方案 | +| `/python-decorator` | Step2:Python 装饰器方案 | 实施 Python 层面的兼容性转换,参数别名、参数顺序、参数类型和参数用法的兼容转换 | +| `/cpp-sink` | Step2:C++下沉方案 | 实施 C++ 层面的代码下沉,减少 Python 装饰器的性能开销,提升 API 调度效率 | +| `/pytorch-alignment-validator` | Step3:对齐验证 | 基于 PaConvert 工具验证 Paddle API 与 PyTorch API 是否用法完全对齐一致(金标准) | +| `/api-docs-updater` | Step4:文档更新 | 同步更新 API 中文文档,确保文档准确反映代码的最新行为 | +| `/create-pr` | Step5:代码提交 | 在 Paddle、PaConvert、Docs 三个仓库分别创建或更新 Pull Request | + + +# 七、自进化机制 + +**本项目涉及的所有 skill 均具备自进化能力**,通过持续学习和优化来提升工作质量。 + +**如何自进化**: +- 每次交互结束后,自动复盘分析工作过程中的问题、错误和成功经验 +- 结合用户反馈纠偏和运行日志,不断优化描述细节和边界条件 +- 识别重复出现的问题模式和最佳实践 + +**自进化需要修改哪里**: +1. **注意事项**章节:补充新发现的注意事项、工作要求 +2. **常见问题处理**章节:补充新发现的问题-解决方案、特殊情况处理方案 +3. 修正或补充 SKILL 中新发现的错误或遗漏内容 + +**跨会话学习**: +- 所有优化和改进都写入各 skill 的 SKILL.md 文档,确保知识持久化 +- 后续会话可以复用之前积累的经验和教训 + +# 八、注意事项 + +1. 严格按标准工作流程执行,杜绝自行臆断和跳过步骤 +2. 所有路径使用 `${ROOT_DIR}` 变量表示根目录,需自行替换为实际路径 + +# 九、常见问题处理 + +### Q1:为什么有些 API 对齐失败? + +**常见原因**: + +1. **差异分析阶段失败**:未查询到差异文档或转写配置 +2. **方案决策阶段失败**:选择的方案不适用或后向兼容性问题 +3. **代码修改阶段失败**:装饰器实现问题或 C++ 下沉编译错误 +4. **验证阶段失败**:Paddle API 实现与 PyTorch 计算结果不一致 + +**处理办法**: +- 查看具体错误信息,返回相应 Step 重新处理 +- 使用调试技巧逐步排查问题 + +--- diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-docs-updater/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-docs-updater/SKILL.md index 0a182208901..5c1a658f3d2 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-docs-updater/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-docs-updater/SKILL.md @@ -1,10 +1,7 @@ --- name: api-docs-updater -description: 仅用于《Paddle API 对齐 PyTorch 项目》,负责 Step4,在 API 代码修改完成后,同步更新中文 API 文档,确保文档准确反映 API 的最新行为 -allowed-tools: Read Grep Glob‌ Write‌ Edit -context: fork -background: true -verbose: true +description: 负责《Paddle API 对齐 PyTorch 项目》中 Step4:API 文档修改,在 API 代码修改完成后,同步更新中文 API 文档,确保文档准确反映 API 的最新行为 +allowed-tools: Read Grep Glob Write Edit disable-model-invocation: false --- @@ -14,22 +11,20 @@ disable-model-invocation: false | 文档类型 | 文件命名 | 改动点 | |----------|----------|----------| -| API 概览文档 | `docs/api/paddle/Overview_cn.rst` | API 索引目录,新增 API 时需要更新 | +| API 概览文档 | `${ROOT_DIR}/docs/api/paddle/Overview_cn.rst` | API 索引目录,新增 API 时需要更新 | | API 中文文档 | `{api_name}_cn.rst` | 针对 API 功能改动点,修改文档 | -# 二、工作流程概述 +# 二、标准工作流程 -## 基本流程 - -1. **查找 API 英文文档** - 在两个位置查找: +Step 1. **查找 API 英文文档** - 在两个位置查找: - 直接存储在 API 实现代码中的 `__doc__` 文档字符串 - - 集中存储在 `Paddle/python/paddle/_paddle_docs.py` 文件中 + - 集中存储在 `${ROOT_DIR}/Paddle/python/paddle/_paddle_docs.py` 文件中 -2. **对比英文和中文文档** - 识别不一致之处 +Step 2. **对比英文和中文文档** - 识别不一致之处 -3. **根据代码修改方案选择对应模式** - 见第三章 +Step 3. **根据代码修改方案选择对应模式** - 见第三章 -4. **按照格式规范更新中文文档** - 见第四章 +Step 4. **按照格式规范更新中文文档** - 见第四章 # 三、常见修改模式 @@ -50,7 +45,7 @@ disable-model-invocation: false **英文文档要求**(代码 docstring): - 格式:`Alias: ` + `` ``别名`` `` - 多个别名:`Alias: ` `` ``input`` ` or ` `` ``other`` `` -- 位置:参数描述末尾 +- 位置:参数描述末尾,**句号前** ```python Args: @@ -144,7 +139,7 @@ Args: keyword-only 形式: ```python Keyword Args: - out (Tensor|None, optional): The output tensor. Default: None. + out (Tensor|None, optional): The output Tensor. Default: None. ``` 位置参数形式: @@ -245,13 +240,11 @@ Inplace 版本的 :ref:`cn_api_paddle_floor_divide` API,对输入 `x` 采用 I ``` -# 四、格式规范与注意事项 - -## 格式规范 +# 四、格式规范 | 项目 | 规范 | 示例 | |------|------|------| -| **别名说明位置** | 参数描述末尾,句号前 | `- **x** (Tensor) - 输入的 Tensor。别名 ` ``input``` | +| **别名说明位置** | 参数描述末尾,**句号前** | `- **x** (Tensor) - 输入的 Tensor。别名 ` ``input``` | | **别名格式** | 2 个反单引号+别名+2 个反单引号 | `` ``input`` `` 或 `` ``dim`` `` | | **多个别名** | 用"或"连接 | `别名 ` ``input`` ` 或 ` ``other``` | | **参数类型** | 可选参数用管道符 | `(float\|None,可选)` 或 `(str\|None,可选)` | @@ -265,22 +258,24 @@ Inplace 版本的 :ref:`cn_api_paddle_floor_divide` API,对输入 `x` 采用 I - 参数类型用 `()` 包裹 - 别名用反引号包裹:`` ``input`` `` -## 注意事项 -1. **Tensor 类方法**(如 `paddle.Tensor.abs`) +# 五、注意事项 + +1. 严格按标准工作流程执行,杜绝自行臆断和跳过步骤 +2. 所有路径使用 `${ROOT_DIR}` 变量表示根目录,需自行替换为实际路径 +3. **Tensor 类方法**(如 `paddle.Tensor.abs`) - 没有独立文档,无需处理 - 勿与普通方法(如 `paddle.abs`)混淆 - -2. **Inplace 方法**(如 `paddle.abs_`) +4. **Inplace 方法**(如 `paddle.abs_`) - 仅更新代码签名,不需修改文档 - 参数别名支持与原方法一致 - -3. **文档内容保持** +5. **文档内容保持** - 保留原有的文档风格和格式 - 不要大面积删除文档原内容 - 示例代码采用 COPY-FROM: 格式,不要修改 - -4. **英文文档与中文文档必须对应** +6. **英文文档与中文文档必须对应** - 别名格式完全相同 - Overload 说明内容对应 - out 参数描述对齐 + +# 六、常见问题处理 diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/cpp-sink/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/cpp-sink/SKILL.md index 524d6cf16ee..1a337bd29a0 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/cpp-sink/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/cpp-sink/SKILL.md @@ -1,7 +1,9 @@ --- name: cpp-sink -description: 仅用于《Paddle API 对齐 PyTorch 项目》,负责 Step2:API 代码修改,实施 C++下沉的代码开发。通过将 Python API 下沉至 C++层,可以减少 Python 装饰器带来的性能开销,提升 API 调度效率。 -allowed-tools: Read Grep‌ Glob‌ Edit Bash +description: 负责《Paddle API 对齐 PyTorch 项目》中 Step2:API 代码修改,实施 C++下沉的代码开发。通过将 Python API 下沉至 C++层,可以减少 Python 装饰器带来的性能开销,提升 API 调度效率。 +context: fork +background: false +verbose: true disable-model-invocation: false --- @@ -55,7 +57,7 @@ disable-model-invocation: false ### Step 2:迁移文档到 `_paddle_docs.py` 注意要更新函数文档字符,在文档的 Args 部分为有别名的参数添加 Alias Support 说明,如下: -> 注:Alias 说明应放在该参数描述的末尾,格式为: Alias: ``alias_name`` ,多个 Alias 描述为: Alias: ``alias_name1`` or ``alias_name2`` +> 注:Alias 说明应放在该参数描述的末尾,**句号前**,格式为: Alias: ``alias_name`` ,多个 Alias 描述为: Alias: ``alias_name1`` or ``alias_name2`` ```python add_doc_and_signature( @@ -261,7 +263,7 @@ class TestAPI(unittest.TestCase): 3. 输出结果序号需要保持连贯,每一个输出结果均需要检验,尽可能循环检验减少行数。 3. 比对测试项,对于内容相同的测试项,不要重复添加。 -完整测试示例,请参考 `Paddle/test/legacy_test/test_api_compatibility[1-9]\.py` 中已有的测试类结构。 +完整测试示例,请参考 `${ROOT_DIR}/Paddle/test/legacy_test/test_api_compatibility[1-9]\.py` 中已有的测试类结构。 ### Step 5:编译并运行 @@ -269,7 +271,7 @@ class TestAPI(unittest.TestCase): 1. **重新编译项目**: ```bash - cd /workspace/Paddle/build + cd ${ROOT_DIR}/Paddle/build cmake .. make -j$(nproc) ``` @@ -282,8 +284,8 @@ class TestAPI(unittest.TestCase): 3. **问题排查**:根据报错信息调整代码或测试用例,确保所有测试用例通过。注意每次修改 Paddle 源码后,必须重新编译方可生效。 编译注意事项: -- 编译完成后不需要重新安装,无需执行 setup/install 等任何安装操作,直接可生效 -- 编译不要删除 build 目录,否则会导致增量编译失效,编译时间极长 +- 无需重装,直接生效(勿执行 setup/install 等安装操作) +- 勿删除 build 目录(否则增量编译失效,编译时间极长) ## 场景二: 具有前处理逻辑(中等复杂度) @@ -377,7 +379,21 @@ void LogsumexpPreProcess(pir::Value *x, std::vector *axis, bool *reduce_all - 函数通过指针修改参数值 - 直接翻译 Python 前处理逻辑到 C++ -### Step 3~6:参考 Step 1 的 Step 2~5 +### Step 3:迁移文档到 `_paddle_docs.py` + +参考场景一的 Step 2 执行相同操作。 + +### Step 4:替换 Python 实现 + +参考场景一的 Step 3 执行相同操作。 + +### Step 5:添加测试用例 + +参考场景一的 Step 4 执行相同操作。 + +### Step 6:编译并运行 + +参考场景一的 Step 5 执行相同操作。 ## 场景三: 复杂参数映射(最复杂) @@ -612,11 +628,21 @@ Returns: """ ``` -### Step 4~6:参考场景一的 Step 3~5 +参考场景一的 Step 2 执行文档迁移操作。 -## 不同场景对比 +### Step 4:替换 Python 实现 + +参考场景一的 Step 3 执行相同操作。 + +### Step 5:添加测试用例 -| 项目 | Step 1: 仅参数名不同 | Step 2: 有前处理逻辑 | Step 3: 复杂参数映射 | +参考场景一的 Step 4 执行相同操作。 + +### Step 6:编译并运行 + +参考场景一的 Step 5 执行相同操作。 + +## 不同场景对比 |------|---------------------|---------------------|---------------------| | **YAML 配置** | `args_alias` + `use_default_mapping` | `args_alias` + `pre_process` | `args_mapper` | | **C++实现** | 无需额外 C++代码 | `arg_pre_process.h/cc` | `args_mapper.h/cc` | @@ -626,65 +652,9 @@ Returns: | **示例 API** | log2 | logsumexp | argmax, argmin | -# 二、异常处理 - -## 2.1 处理流程 -当遇到错误时,建议按照以下步骤处理,确保代码能运行通过: -1. **定位错误**:仔细阅读错误信息,确定错误类型和位置 -2. **分析原因**:根据错误信息分析具体问题,例如参数错误、类型不匹配 -3. **修改代码**:根据错误信息与分析结果,调整代码 -4. **验证修复**:重新运行测试确认问题解决 - -## 2.2 常见错误及解决方案 - -### 静态图兼容性问题 -**错误现象**: -```python -TypeError: (InvalidType) all(): argument (position 1) must be Value, but got Variable -``` - -**问题原因**: -API 下沉后使用了新的 Value 类型系统,但测试代码仍在使用旧的 Variable 类型 - -**解决方法**: -1. 删除过时的测试文件: - ```bash - rm -rf test/deprecated/test_xxx.py - ``` -2. 删除`CMakeLists.txt`中涉及的单测配置: - ```cmake - # 删除相关单测配置 - # set_tests_properties(test_lbfgs_deprecated PROPERTIES TIMEOUT 100) - ``` -3. 检查并更新所有引用这些测试的代码 - -### 参数解析错误 -**错误现象**: -```python -TypeError: argmax() got an unexpected keyword argument 'invalid_param' -``` - -**解决方法**: -1. 检查参数名称拼写 -2. 确认是否支持该参数 - -### 类型转换错误 -**错误现象**: -```python -TypeError: expected Tensor as argument, got numpy.ndarray -``` - -**解决方法**: -1. 确保输入数据是 Tensor 类型: - ```python - tensor_input = paddle.to_tensor(numpy_input) - ``` -2. 检查数据类型是否匹配 - - -# 三、技术背景知识 +# 二、技术背景知识 -## 3.1 工具函数速查 +## 2.1 工具函数速查 ```cpp // 获取 Tensor 参数(支持别名) @@ -712,16 +682,50 @@ void CheckParamsCount(int nargs, int remaining_kwargs, int max_args); void CheckRemainingParamsValidity(PyObject* args, PyObject* kwargs, int remaining_kwargs, int nargs); ``` -# 四、注意事项 +# 三、注意事项 -1. 若 Python API 参数顺序与`_C_ops` API 不同,属于特殊情况,Cpp 下沉方案无法实现,需要使用 Python 装饰器方案。 -2. 代码中不允许提交中文,代码注释采用英文 -3. 若 API 需支持`out`参数,必须修改`add_doc_and_signature`中的字符串,增加 out 参数 -4. 不要修改`generated_tensor_methods_patch.py`,该文件是自动生成的,修改没有意义,如无法对齐可考虑放弃 C++下沉方案而不是改动该文件 -5. 示例代码若涉及多种数据类型,可能触发类型检查误报,添加注释忽略: +1. 严格按标准工作流程执行,杜绝自行臆断和跳过步骤 +2. 所有路径使用 `${ROOT_DIR}` 变量表示根目录,需自行替换为实际路径 +3. 若 Python API 参数顺序与`_C_ops` API 不同,属于特殊情况,Cpp 下沉方案无法实现,需要使用 Python 装饰器方案 +4. 代码中不允许提交中文,代码注释采用英文 +5. 若 API 需支持`out`参数,必须修改`add_doc_and_signature`中的字符串,增加 out 参数 +6. 不要修改`generated_tensor_methods_patch.py`,该文件是自动生成的,修改没有意义,如无法对齐可考虑放弃 C++下沉方案而不是改动该文件 +7. 示例代码若涉及多种数据类型,可能触发类型检查误报,添加注释忽略: ```python .. code-block:: pycon >>> # type: ignore >>> import paddle >>> x = paddle.to_tensor([1.0, 2.0]) ``` + +# 四、常见问题处理 + +## Q1:静态图报错"must be Value, but got Variable" + +**错误现象**: +```python +TypeError: (InvalidType) all(): argument (position 1) must be Value, but got Variable +``` + +**解决方法**: +1. 删除过时的测试文件: + ```bash + rm -rf test/deprecated/test_xxx.py + ``` +2. 删除`CMakeLists.txt`中涉及的单测配置 +3. 检查并更新所有引用这些测试的代码 + +--- + +## Q2:参数解析报错"got an unexpected keyword argument" + +**错误现象**: +```python +TypeError: argmax() got an unexpected keyword argument 'invalid_param' +``` + +**解决方法**: +1. 检查参数名称拼写 +2. 确认是否支持该参数 + +--- diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/create-pr/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/create-pr/SKILL.md index a76b6f4ab7e..83a336b3ed2 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/create-pr/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/create-pr/SKILL.md @@ -1,6 +1,6 @@ --- name: create-pr -description: 仅用于《Paddle API 对齐 PyTorch 项目》,负责 Step5:代码提交,负责在前序步骤都完成后,分别对 Paddle、PaConvert、Docs 三个仓库创建或更新 Pull Request +description: 负责《Paddle API 对齐 PyTorch 项目》中 Step5:代码提交,分别对 Paddle、PaConvert、Docs 三个仓库创建或更新 Pull Request allowed-tools: Bash(git *) disable-model-invocation: false --- @@ -8,48 +8,104 @@ disable-model-invocation: false # 一、标准工作流程 该 skill 负责将前序步骤的成果提交到三个代码库: -1. **PaddlePaddle/Paddle** - API 代码实现(base: develop) -2. **PaddlePaddle/PaConvert** - PyTorch 兼容性测试(base: master) -3. **PaddlePaddle/docs** - 中文 API 文档(base: develop) + +| 仓库 | 说明 | Base 分支 | +|------|------|---------| +| **PaddlePaddle/Paddle** | API 代码实现 | develop | +| **PaddlePaddle/PaConvert** | PyTorch 兼容性测试 | master | +| **PaddlePaddle/docs** | 中文 API 文档 | develop | ## Step 1:检查三个仓库的改动状态 -验证三个仓库都已有需要提交的改动: +三个仓库的本地目录名称分别为 Paddle、PaConvert、docs,自行找到对应本地路径,检查三个仓库是否有未提交的改动,**只对有代码改动的仓库进行后续提交**(排除未跟踪文件): + +```bash +cd /path/to/Paddle && git status --untracked-files=no +cd /path/to/PaConvert && git status --untracked-files=no +cd /path/to/docs && git status --untracked-files=no +``` + +判断标准: +- 若仓库中有 `M`、`A`、`D` 等标记的**已跟踪文件**,则该仓库**需要提交** +- 若仓库中只有 `??` 标记的**未跟踪文件**,则该仓库**无需提交** +- 若仓库无任何改动,则该仓库**无需提交** + +## Step 2:获取 PyTorch API 名单 + +根据各仓库的改动状态,自行从多个渠道获取 PyTorch API 名单,**最后需要取并集**: + +### 渠道 1:从上下文获取 + +```bash +# 从 api-change-decider、python-decorator、cpp-sink 等前序步骤的上下文中自动提取 API 名单 +``` + +### 渠道 2:从用户输入获取 + +```bash +# 用户直接提供 PyTorch API 名单,例如:torch.relu、torch.sigmoid、torch.tanh 等 +``` + +### 渠道 3:从 Paddle 仓库分析获取 + +若 Paddle 仓库有改动,分析以下位置: + +```bash +cd /path/to/Paddle +# 1. 分析任意 Python 文件的改动 +git diff origin/develop -- '*.py' | grep -E "^\+.*def|^\+.*class" + +# 2. 分析 python_api_info.yaml 的改动 +git diff origin/develop -- python_api_info.yaml +``` + +### 渠道 4:从 PaConvert 仓库分析获取 + +若 PaConvert 仓库有改动,从 `api_mapping.json` 提取标记为 `ChangePrefixMatcher` 的 API: ```bash -cd /path/to/Paddle && git status -cd /path/to/PaConvert && git status -cd /path/to/docs && git status +cd /path/to/PaConvert +# 分析 api_mapping.json 中标记为 ChangePrefixMatcher 的 API +git diff origin/master -- api_mapping.json | grep -E "ChangePrefixMatcher|torch\." +``` + +**API 名单合并** + +```bash +# 将从各渠道获取的 API 名单取并集,确保不重复,生成最终的统一 API 名单 +# 例如:torch.relu, torch.sigmoid, torch.tanh, ... ``` -## Step 2:添加改动并提交 +## Step 3:添加改动并提交 -对每个仓库执行以下操作(顺序:Paddle → Docs → PaConvert): +仅对**有代码改动的仓库**执行以下操作(顺序:Paddle → Docs → PaConvert): ```bash # Paddle 仓库 cd /path/to/Paddle -git add -A +git add -u git commit -m "[API Compatibility] api_name_1/api_name_2/api_name_3/... Edit By AI Agent" # 等待 pre-commit hook 完成 # 如果 pre-commit 失败,修复问题后重新 git add 和 commit # docs 仓库 cd /path/to/docs -git add -A +git add -u git commit -m "[API Compatibility] api_name_1/api_name_2/api_name_3/... Edit By AI Agent" # 等待 pre-commit hook 完成 # 如果 pre-commit 失败,修复问题后重新 git add 和 commit # PaConvert 仓库 cd /path/to/PaConvert -git add -A +git add -u git commit -m "[API Compatibility] api_name_1/api_name_2/api_name_3/... Edit By AI Agent" # 等待 pre-commit hook 完成 # 如果 pre-commit 失败,修复问题后重新 git add 和 commit ``` -## Step 3:推送代码到 upstream claude 分支 +## Step 4:推送代码到 upstream claude 分支 + +仅对**有代码改动的仓库**执行推送操作: ```bash # Paddle 仓库 @@ -65,9 +121,9 @@ cd /path/to/PaConvert git push upstream HEAD:claude -f ``` -## Step 4:创建 PR +## Step 5:创建 PR -根据自动获取的 PyTorch API 名单生成 PR,执行以下命令创建 PR(顺序:Paddle → Docs → PaConvert): +根据自动获取的 PyTorch API 名单生成 PR,**仅对有代码改动的仓库**执行以下命令创建 PR(顺序:Paddle → Docs → PaConvert): ```bash # Paddle PR @@ -135,11 +191,21 @@ EOF - 将 `api_name_1/api_name_2/...` 替换为实际的 API 名单 - 将 `{paddle_pr_number}` 和 `{docs_pr_number}` 替换为实际创建的 PR 号 - # 二、注意事项 -- 从前序步骤的上下文中自动获取 PyTorch API 名单,无需用户输入 +- 所有路径使用 `${ROOT_DIR}` 变量表示根目录 +- **PyTorch API 名单获取策略**: + - 先检查三个仓库的改动状态(Step 1) + - 根据各仓库的改动情况,灵活选择获取渠道 + - 从多个渠道获取的 API 名单需要**取并集**,确保完整性和准确性 + - Paddle 仓库改动分析:任意 Python 文件修改、python_api_info.yaml 修改 + - PaConvert 仓库改动分析:api_mapping.json 中标记为 `ChangePrefixMatcher` 的 API +- **仅对有代码改动的仓库进行提交和 PR 创建**,如果某个仓库无代码改动,则跳过该仓库的提交、推送和 PR 创建步骤 - 三个 PR 的 API 名单必须完全一致 - 如果 pre-commit hook 失败,修复问题后重新提交 - 所有改动必须推送到 upstream 的 claude 分支 - 确保 PR 创建成功,如果失败需要继续修正直到成功 +- 复盘记忆中的历史易错点,避免重复犯错 +- 严格按标准工作流程执行,杜绝自行臆断和跳过步骤 + +# 三、常见问题处理 diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/python-decorator/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/python-decorator/SKILL.md index 2fdce2a457a..f86804a1054 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/python-decorator/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/python-decorator/SKILL.md @@ -1,13 +1,15 @@ --- name: python-decorator -description: 仅用于《Paddle API 对齐 PyTorch 项目》,负责 Step2:API 代码修改,实施 Python 装饰器的代码开发。通过 Python 装饰器,在 Python 层为 Paddle API 提供参数别名、参数顺序、参数类型和参数用法的兼容转换,实现 PyTorch 风格的 API 调用,并保持 Paddle API 的向后兼容性。 -allowed-tools: Read Grep‌ Glob‌ Edit Bash +description: 负责《Paddle API 对齐 PyTorch 项目》中 Step2:API 代码修改,实施 Python 装饰器的代码开发。通过 Python 装饰器,在 Python 层为 Paddle API 提供参数别名、参数顺序、参数类型和参数用法的兼容转换,实现 PyTorch 风格的 API 调用,并保持 Paddle API 的向后兼容性。 +context: fork +background: false +verbose: true disable-model-invocation: false --- # 一、现有装饰器体系 -Paddle 现有装饰器统一位于 `Paddle/python/paddle/utils/decorator_utils.py`,按功能分为两类: +Paddle 现有装饰器统一位于 `${ROOT_DIR}/Paddle/python/paddle/utils/decorator_utils.py`,按功能分为两类: ## 1.1 通用别名装饰器 @@ -34,9 +36,25 @@ Paddle 现有装饰器统一位于 `Paddle/python/paddle/utils/decorator_utils.p # 二、标准工作流程 +**整体流程**:Step 1 差异分析与选择装饰器 → Step 2 应用或开发装饰器 → Step 3 添加 out 参数支持 → Step 4 更新函数文档 → Step 5 添加测试用例 → Step 6 编译并运行 + ## Step 1: 差异分析与选择装饰器 -根据 PyTorch API 与 Paddle API 的**差异分析**来区分不同场景: +根据 PyTorch API 与 Paddle API 的**差异分析**来区分不同场景,选择合适的装饰器方案。 + +### 场景决策表 + +| 差异类型 | 参数顺序 | 参数个数 | 参数用法 | 推荐方案 | +|---------|--------|--------|--------|--------| +| 仅参数名不同 | 相同 | 相同 | 相同 | ✅ 方式一(通用别名装饰器) | +| 参数名+参数顺序不同 | 不同 | 相同 | 相同 | ❌ 需要使用方式二(专用装饰器) | +| 参数名+参数个数不同 | 相同 | 不同 | 相同 | ❌ 需要使用方式二(专用装饰器) | +| 参数名+参数用法不同 | 相同 | 相同 | 不同 | ❌ 需要使用方式二(专用装饰器) | +| 其他复杂情况 | 其他 | 其他 | 其他 | ❌ 需要使用方式二(专用装饰器) | + +**判断方法**:若上表中任何一列出现"不同",则需使用方式二开发专用装饰器。 + +--- ### 1. 仅参数名不同(参数顺序相同) @@ -136,7 +154,7 @@ def cumsum(x, axis=None, dtype=None, name=None): ### 方式二:开发新的专用装饰器 -1. 在`Paddle/python/paddle/utils/decorator_utils.py`中定义新装饰器 +1. 在`${ROOT_DIR}/Paddle/python/paddle/utils/decorator_utils.py`中定义新装饰器 2. 按照以下模板和要点实现 3. 在 API 函数上使用新装饰器 @@ -231,10 +249,10 @@ def index_select_decorator(): ``` **注意事项**: -1. 尽可能参考 `Paddle/python/paddle/utils/decorator_utils.py` 中已有的专用装饰器来实现,在风格和逻辑上保持尽可能一致 +1. 尽可能参考 `${ROOT_DIR}/Paddle/python/paddle/utils/decorator_utils.py` 中已有的专用装饰器来实现,在风格和逻辑上保持尽可能一致 2. 如果两者 API 对应参数的顺序不同,则装饰器需要通过位置参数(args)类型检测来区分两者,并分别匹配不同的参数顺序 -3. 专用装饰器应该尽可能逻辑简单,只假定存在 Paddle 签名+Pytorch 签名两种用法,其他情况无需判断,提升性能 -4. overload 注解:专有装饰器需添加 overload 注解(通用别名装饰器无需注解),需针对 Paddle 签名、Pytorch 签名分别添加 overload 注解(Paddle 在前,Pytorch 在后) +3. 专用装饰器应该尽可能逻辑简单(单个函数控制在 30 行以内),只假定存在 Paddle 签名+PyTorch 签名两种用法,其他情况无需判断,提升性能 +4. overload 注解:专用装饰器需添加 overload 注解(通用别名装饰器无需注解),需针对 Paddle 签名、PyTorch 签名分别添加 overload 注解(Paddle 在前,PyTorch 在后)。导入方式:`from typing import overload` ```python @overload def gather( @@ -527,7 +545,7 @@ class TestAPI(unittest.TestCase): 3. 输出结果序号需要保持连贯,每一个输出结果均需要检验,尽可能循环检验减少行数。 3. 比对测试项,对于内容相同的测试项,不要重复添加。 -完整测试示例,请参考 `Paddle/test/legacy_test/test_api_compatibility[1-9]\.py` 中已有的测试类结构。 +完整测试示例,请参考 `${ROOT_DIR}/Paddle/test/legacy_test/test_api_compatibility[1-9]\.py` 中已有的测试类结构。 ## Step 6: 编译与运行 @@ -535,7 +553,7 @@ class TestAPI(unittest.TestCase): 1. **重新编译项目**: ```bash - cd /workspace/Paddle/build + cd ${ROOT_DIR}/Paddle/build cmake .. make -j$(nproc) ``` @@ -548,56 +566,12 @@ class TestAPI(unittest.TestCase): 3. **问题排查**:根据报错信息调整代码或测试用例,确保所有测试用例通过。注意每次修改 Paddle 源码后,必须重新编译方可生效。 编译注意事项: -- 编译完成后不需要重新安装,无需执行 setup/install 等任何安装操作,直接可生效 -- 编译不要删除 build 目录,否则会导致增量编译失效,编译时间极长 - -# 三、异常处理 - -## 3.1 标准处理流程 -1. **定位错误**:仔细阅读错误信息,确定错误类型和位置 -2. **分析原因**:根据错误信息分析具体问题(装饰器实现错误、使用错误等) -3. **修改代码**:根据分析结果调整代码 -4. **验证修复**:重新运行测试确认问题解决 - -## 3.2 常见错误及解决方案 - -### 类型转换错误 - -**错误现象**: -```python -TypeError: expected Tensor as argument, got numpy.ndarray -``` - -**解决方法**: -```python -# 确保输入是 Tensor 类型 -tensor_input = paddle.to_tensor(numpy_input) -paddle.api(tensor_input, ...) -``` - -## 3.3 调试技巧 - -```python -# 添加调试日志 -import logging -logging.basicConfig(level=logging.DEBUG) - -# 在装饰器中添加日志 -def wrapper(*args, **kwargs): - logging.debug(f"Before: args={args}, kwargs={kwargs}") - # 处理逻辑... - logging.debug(f"After: args={args}, kwargs={kwargs}") - return func(*args, **kwargs) - -# 或使用打印调试 -def wrapper(*args, **kwargs): - print(f"[DEBUG] args={args}, kwargs={kwargs}") - # ... -``` +- 无需重装,直接生效(勿执行 setup/install 等安装操作) +- 勿删除 build 目录(否则增量编译失效,编译时间极长) -# 四、技术背景知识 +# 三、技术背景知识 -## 4.1 Paddle API 分层结构 +## 3.1 Paddle API 分层结构 **Paddle API 架构(5 层)**: 1. **Python 层**:Python 函数定义(本方案修改层) @@ -611,7 +585,7 @@ def wrapper(*args, **kwargs): - ❌ 第 2~4 层通过 yaml 配置自动生成,无需手动修改 - ❌ 第 5 层涉及 C++实现,不在本方案范围内 -## 4.2 Python 装饰器原理 +## 3.2 Python 装饰器原理 ### 装饰器基本结构 @@ -650,36 +624,68 @@ if len(args) >= 2 and isinstance(args[1], int): args = () ``` -## 4.3 装饰器特点与注意事项 +## 3.3 装饰器特点与注意事项 ### 装饰器特点 - **零侵入性**:无需修改 API 的实现代码 - **适用面广**:支持灵活处理各种 API 签名重载情况,如参数名不同、参数顺序不同、参数个数不同、参数类型不同、参数用法不同等 - **向后兼容**:保持 Paddle 原有 API 调用方式 - **开发效率**:相比 C++下沉方案,修改更快速直接 -- **性能开销**:Python 装饰器层会引入轻微性能开销 -### 性能开销 +# 四、注意事项 -- 装饰器会引入额外的函数调用层级 -- 对于高频调用的 API,装饰器开销可能不可忽略 -- 考虑对性能敏感的 API 使用 C++下沉方案 +1. 严格按标准工作流程执行,杜绝自行臆断和跳过步骤 +2. 所有路径使用 `${ROOT_DIR}` 变量表示根目录,需自行替换为实际路径 +3. 不要修改 sparse 目录下的 API +4. 确保不破坏现有功能,保持向后兼容性 +5. 开发专用装饰器时参考现有实现 +6. 代码中不允许提交中文,代码注释采用英文 +7. 复盘记忆中的历史易错点,避免重复犯错 -### 调试复杂性 +# 五、常见问题处理 -- 装饰器增加了调用栈深度 -- 错误追踪时可能需要多跳一层 -- 使用日志辅助调试 +## Q1:类型转换错误 -### 与其他装饰器共存 +**错误现象**: +```python +TypeError: expected Tensor as argument, got numpy.ndarray +``` -- 需要注意装饰器的应用顺序 -- 确保装饰器之间不产生冲突 -- 不同装饰器的参数处理逻辑应该兼容 +**解决方法**: +```python +# 确保输入是 Tensor 类型 +tensor_input = paddle.to_tensor(numpy_input) +paddle.api(tensor_input, ...) +``` + +--- + +## Q2:装饰器参数处理错误 + +**错误现象**:装饰器内参数转换失败或逻辑异常 + +**解决方法**: +1. 检查位置参数(args)与关键字参数(kwargs)的转换逻辑是否正确 +2. 确保参数别名映射完整(包括所有别名情况) +3. 使用调试技巧进行追踪: -# 五、注意事项 +在装饰器中添加日志进行调试: -1. 不要修改 sparse 目录下的 API -2. 确保不破坏现有功能,保持向后兼容性 -3. 开发专用装饰器时参考现有实现 -4. 代码中不允许提交中文,代码注释采用英文 +```python +import logging +logging.basicConfig(level=logging.DEBUG) + +# 在装饰器中添加日志 +def wrapper(*args, **kwargs): + logging.debug(f"Before: args={args}, kwargs={kwargs}") + # 处理逻辑... + logging.debug(f"After: args={args}, kwargs={kwargs}") + return func(*args, **kwargs) + +# 或使用打印调试 +def wrapper(*args, **kwargs): + print(f"[DEBUG] args={args}, kwargs={kwargs}") + # ... +``` + +--- diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/pytorch-alignment-validator/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/pytorch-alignment-validator/SKILL.md index ff14844b7bd..293adea0836 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/pytorch-alignment-validator/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/pytorch-alignment-validator/SKILL.md @@ -1,18 +1,15 @@ --- name: pytorch-alignment-validator -description: 仅用于《Paddle API 对齐 PyTorch 项目》,负责 Step3:Pytorch 对齐验证,基于 PaConvert 工具验证 Paddle API 与 PyTorch API 是否用法完全对齐一致 -allowed-tools: Read Grep‌ Glob‌ Write‌ Edit Bash(python *) +description: 负责《Paddle API 对齐 PyTorch 项目》中 Step3:Pytorch 对齐验证,基于 PaConvert 工具验证 Paddle API 与 PyTorch API 是否用法完全对齐一致 disable-model-invocation: false --- # 一、标准工作流程 -> **PaConvert 介绍**:Pytorch->Paddle 代码转换工具,可以搭建起 Pytorch-Paddle API 之间的桥梁。 - 请严格按以下 Step 依次执行,不要自行修改或跳过 Step: ## Step 1: 标记已对齐的 API -1. 定位文件:`PaConvert/paconvert/api_mapping.json` +1. 定位文件:`${ROOT_DIR}/PaConvert/paconvert/api_mapping.json` 2. 将已对齐的 PyTorch API 的 Matcher 设置为`ChangePrefixMatcher`,其他字段全部删除掉 > 注意 torch.abs、torch.abs_、torch.Tensor.abs、torch.Tensor.abs_是四个不同的 API @@ -21,14 +18,13 @@ disable-model-invocation: false **目的:** 判断是否满足如下测试规范,如不满足,则需增加测试用例使之符合规范 **修改位置:** -- Pytorch 单测路径: `PaConvert/tests/` +- Pytorch 单测路径: `${ROOT_DIR}/PaConvert/tests/` - Pytorch 单测文件名: `test_.py` -- **测试文件命名规范**:API 名称转换为下划线命名法,并在文件名中体现完整的模块路径层级: +- **测试文件命名规范**:将 API 路径中的 `.` 替换为 `_`,Tensor 类保留大写 `T`,最终加上 `test_` 前缀和 `.py` 后缀 - `torch.argmax` → `test_argmax.py`(顶层函数) - - `torch.Tensor.argmax` → `test_Tensor_argmax.py`(类方法,用大写 T 表示类名) - - `torch.linalg.inv` → `test_linalg_inv.py`(子模块函数,用下划线连接模块名) - - 从左到右依次将 API 路径中的`.`替换为`_`,类名保留首字母大写,最终加上`test_`前缀和`.py`后缀 -- 注意新增的测试 case 需要放到之前测试 case 的后面,不要删除之前的测试 case + - `torch.Tensor.argmax` → `test_Tensor_argmax.py`(类方法) + - `torch.linalg.inv` → `test_linalg_inv.py`(子模块) +- **新增测试 case 策略**:若现有测试不满足规范,应**新增测试 case**(追加到后面),而非修改或删除已有测试 **测试规范:** 1. **参数覆盖要全面** @@ -160,7 +156,7 @@ class CustomAPIBase(APIBase): 1. 本地执行以下命令: ```bash - cd /workspace/PaConvert/ + cd ${ROOT_DIR}/PaConvert/ python -m pytest tests/test_.py ``` @@ -172,42 +168,73 @@ make -j$(nproc) ``` 编译注意事项: -- 编译完成后不需要重新安装,无需执行 setup/install 等任何安装操作,直接可生效 -- 编译不要删除 build 目录,否则会导致增量编译失效,编译时间极长 +- 无需重装,直接生效(勿执行 setup/install 等安装操作) +- 勿删除 build 目录(否则增量编译失效,编译时间极长) + + + +# 二、注意事项 + +1. 严格按标准工作流程执行,杜绝自行臆断和跳过步骤 +2. 所有路径使用 `${ROOT_DIR}` 变量表示根目录,需自行替换为实际路径 +3. 确保测试用例覆盖所有参数组合和边界情况 +4. 验证通过是对齐的金标准,不可跳过 +5. 复盘记忆中的历史易错点,避免重复犯错 +6. **PaConvert 说明**:Pytorch->Paddle 代码转换工具,可以搭建起 Pytorch-Paddle API 之间的桥梁。 + +# 三、常见问题处理 + +## Q1:PyTorch 代码执行失败 + +**错误标识**:Failed to execute pytorch code + +**根本原因**:PyTorch 单元测试代码存在问题,无法正常执行 + +**处理策略**:修改 PyTorch 单元测试代码,确保能正确执行 Pytorch 代码 + +**验证标准**:测试代码应该能够在标准的 PyTorch 环境中正常运行 + +--- + +## Q2:Paddle 代码执行失败 -# 二、异常处理 +**错误标识**:Failed to execute paddle code -## 2.1 异常处理策略 +**根本原因**:Pytorch 单测正确,但修改后的 Paddle API 实现存在问题,导致代码无法执行 -在 PyTorch 对齐验证过程中,需要对不同异常情况进行分类处理。以下是异常处理策略: +**处理策略**:需要返回到前序 Step 修改,因此结束本 Step,将报错信息返回给主控智能体分析 -### a. PyTorch 代码执行失败 -- **错误标识**:`Failed to execute pytorch code` -- **根本原因**:PyTorch 单元测试代码存在问题,无法正常执行 -- **处理策略**:修改 PyTorch 单元测试代码,确保能正确执行 Pytorch 代码 -- **验证标准**:测试代码应该能够在标准的 PyTorch 环境中正常运行 +**关联任务**:Paddle API 需要进一步修改以兼容 PyTorch 接口 -### b. Paddle 代码执行失败 -- **错误标识**:`Failed to execute paddle code` -- **根本原因**:Pytorch 单测正确,但修改后的 Paddle API 实现存在问题,导致代码无法执行 -- **处理策略**:需要返回到前序 Step 修改,因此结束本 Step,将报错信息返回给主控智能体分析 -- **关联任务**:Paddle API 需要进一步修改以兼容 PyTorch 接口 +--- + +## Q3:计算结果不一致 + +**错误标识**:Unable to align results + +**根本原因**:Pytorch 单测正确,但 Paddle API 与 PyTorch API 计算结果存在差异 + +**处理策略**:需要返回到前序 Step 修改,因此结束本 Step,将报错信息返回给主控智能体分析 + +**验证要求**:Paddle API 需要进一步修改以兼容 PyTorch 接口,确保数值精度、数据类型、形状等完全一致 + +**禁止通过配置 api_mapping.json 为非 ChangePrefixMatcher 来使单测通过**,本步骤的通过标准为:Matcher 配置为 ChangePrefixMatcher + 单测运行通过。 -### c. 计算结果不一致 -- **错误标识**:`Unable to align results` -- **根本原因**:Pytorch 单测正确,但 Paddle API 与 PyTorch API 计算结果存在差异 -- **处理策略**:需要返回到前序 Step 修改,因此结束本 Step,将报错信息返回给主控智能体分析 -- **验证要求**:Paddle API 需要进一步修改以兼容 PyTorch 接口,确保数值精度、数据类型、形状等完全一致 +--- -> 禁止通过配置 api_mapping.json 为非`ChangePrefixMatcher`来使单测通过,本步骤的通过标准为:Matcher 配置为`ChangePrefixMatcher` + 单测运行通过。 +## Q4:如何禁用不支持的测试用例 -## 2.2 常见错误及解决方案 +**错误现象**: +Paddle 因为暂不支持某些功能(如类型提升、标量输入等)而报错 -### Paddle 不支持类型提升 -- 如果报错是因为 Paddle 不支持类型提升或标量输入(已知问题),可以禁用对应测试用例,其他情况不允许禁用单测: - ```python - # 将 def test_case_x(): 改为 def _test_case_x(): - # 并添加注释说明原因 - def _test_case_2(): # Paddle does not support scalar input - ... - ``` +**解决方法**: +```python +# 将 def test_case_x(): 改为 def _test_case_x(): +# 并添加注释说明原因 +def _test_case_2(): # Paddle does not support scalar input + ... +``` + +**注意**:仅允许禁用因已知 Paddle 限制导致的失败用例,其他情况不允许禁用 + +---