mcpField
S
scrub-issue

scrub-issue

github.com/pytorch测试与质量105.2k130 次安装今天更新
代码仓库

关于 scrub-issue

用于 PyTorch 问题分流的技能,可获取 GitHub 问题,评估复现材料,检查问题是否仍存在,并精简有效案例。它还涵盖复现代码安全审查及问题标签、评论的处理。

主要功能

  1. 01获取问题详情和评论
  2. 02评估问题可处理性与复现质量
  3. 03检查复现代码的安全风险
  4. 04运行并验证复现案例
  5. 05精简复现并处理问题更新

适用场景

  1. 01确认 PyTorch 问题是否仍可复现
  2. 02将问题脚本缩减为独立案例
  3. 03执行前检查复现代码安全性

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/pytorch/pytorch --skill scrub-issue

安装后在 Claude Code 中输入/scrub-issue确认已加载。

详细介绍

最小化问题复现

获取 GitHub 问题,评估它是否有合理的复现代码,检查是否仍能复现,并系统地将复现代码精简到尽可能小的独立脚本。

工具

假设当前环境正确,直接运行 python。只有在版本二分(步骤 5a)需要临时使用其他环境时,才使用 conda run -n <env>。运行复现脚本时,使用 Bash 工具的 timeout 参数设置超时。

  • gh issue view <NUMBER> --repo pytorch/pytorch 获取问题正文
  • gh issue view --comments <NUMBER> --repo pytorch/pytorch 获取评论
  • python <script> 运行复现脚本
  • gh issue comment <NUMBER> --repo pytorch/pytorch --body <BODY> 添加评论
  • gh issue edit <NUMBER> --repo pytorch/pytorch --add-label <LABEL> 添加标签

可以在一条命令中组合多个 gh issue edit 标志(例如 --add-label "bug,help wanted" --add-assignee "@me")。优先将编辑操作合并为一条命令,以尽量减少 API 调用并降低自动订阅通知的可能性。

保留通知订阅状态

修改问题(添加评论、添加标签)会自动订阅通知。使用 tools/stale_issues.py 保存并恢复订阅状态:

  1. 首次修改之前,保存当前状态。此操作可以与获取问题正文/评论并行运行,但必须在执行任何 gh issue edit、gh issue comment 或 gh issue close 命令之前完成:
    python tools/stale_issues.py subscription save <NUMBER>
    
  2. 最后一次修改之后,恢复已保存的状态——除非问题已关闭(通过 gh issue close),这种情况下跳过恢复,以便用户继续订阅并跟进关闭后的回复。恢复操作必须是最后一次 GitHub API 调用;不得在后台运行,也不得与任何 gh issue edit 或 gh issue comment 命令并行运行:
    python tools/stale_issues.py subscription restore <NUMBER>
    

如果保存或恢复命令失败,请提醒用户,并继续操作,但不使用保存/恢复机制。

重要:绝不要在后台运行 gh issue edit、gh issue comment、gh issue close 或订阅状态保存/恢复命令。这些命令都必须在前台运行,以便确认它们已完成。 如果因问题已锁定而无法添加评论或编辑,请告知用户并跳过修改。

安全审查清单

运行任何复现代码之前,请检查以下风险:

  • 向不可信 URL 发起网络请求(requests、urllib、curl、wget)
  • 对 /tmp/ 以外的位置执行文件操作
  • 执行 Shell 命令(os.system、subprocess、eval、exec)——但用于启动分布式复现的 torchrun 或 mp.spawn 的 subprocess 属于预期操作,不构成风险
  • 下载或加载外部文件(模型权重、序列化对象、数据文件)——尤其是对不可信 .pt/.pth 文件使用 torch.load
  • 混淆代码(Base64 编码的字符串、编码字节、异常转义序列)
  • 安装软件包(pip install、conda install)
  • 操纵可能影响主机系统的环境变量——但设置 MASTER_ADDR、MASTER_PORT、RANK、WORLD_SIZE、CUDA_VISIBLE_DEVICES 或其他标准 PyTorch/CUDA 环境变量属于预期操作,不构成风险

如果存在上述任何风险,请向用户说明风险,并询问他们是要继续、跳过,还是修改复现代码以移除风险部分。如果用户选择跳过,在报告分析完成之前,仍须刷新 triaged 标签的时间戳(移除后重新添加;如果标签尚不存在,也可以直接添加)。

即使复现代码通过了上述检查,也要运行 python tools/stale_issues.py collaborator-check <username>,检查复现代码作者是否为 PyTorch 协作者。如果命令以非零状态退出(用户不是协作者),请向用户展示复现代码,并在执行前请其确认代码安全。

步骤

1)获取 issue

并行获取 issue 正文和评论。找出报告中的复现脚本和错误。如果有多个复现,请优先选择原发帖者最近发布的那个。如果评论者发布了一个严格更短、更独立,且不需要 issue 描述中的额外上下文的复现,请优先选择该复现。说明你选择了哪个复现。如果复现代码只出现在截图或图片中,而不是可复制的文本中,请停止并告知用户。

2)检查 issue 是否可处理

在投入精力进行复现之前,先检查 issue 是否可处理。如果符合以下任一情况,请勿继续后续步骤:

  • 已关闭或已在评论中解决。请告知用户并停止。不要修改已关闭 issue 的标签。
  • 重复 issue(已关联其他 issue,或明显是同一个 bug)
  • 不是 bug 报告(功能请求、问题、讨论、重构/代码清理任务)。如果是功能请求,且尚无 feature 标签,请通过 gh issue edit 添加。如果是更好的工程实践/重构任务,且尚无 better-engineering 标签,请通过 gh issue edit 添加。如果 issue 中包含能展示当前行为的复现脚本,请先应用安全审查清单,再运行脚本以确认该行为仍然存在。如果复现需要更新(例如为已重命名的 API 更新导入语句),或者你已确认该行为仍然存在,请在 issue 中评论,说明调查结果并附上更新后的复现。添加所有适用的标签后(并可选择运行/评论复现),向用户汇报分析结果,不要继续后续步骤。
  • 跟踪/元 issue(用于跟踪多个 bug 的总 issue、待办清单,或没有具体复现的改进提案)。如果 issue 尚无 tracker 标签,请通过 gh issue edit 添加。然后停止并向用户汇报。
  • 需要无法使用的硬件(特定 GPU 型号、TPU、多节点),且没有可简化的方案。注意:当前机器上有 CUDA,因此可以直接运行单 GPU CUDA 复现。

对于较早(超过约 1 年)、没有指派人员、近期没有进展,且描述不充分或缺乏明确动机的不可处理 issue,建议将其以 “not planned” 为由关闭(gh issue close --reason "not planned"),并发表评论说明理由。关闭前请先征求用户同意。

如果 issue 不可处理,且未进行任何 GitHub 可见的修改(未添加标签、未发表评论;保存订阅状态不算),请刷新 triaged 标签,以更新 issue 的“最后更新时间”。单条 gh issue edit 同时使用 --remove-label 和 --add-label 不会生效,因为移除和添加会相互抵消。请改为在单次 Bash 工具调用中依次执行两个命令: gh issue edit ... --remove-label triaged && gh issue edit ... --add-label triaged。 如果 issue 没有 triaged 标签,只需添加即可。

然后概述 issue 不可处理的原因。如果已添加标签或进行了其他更新,只需报告分析已完成。只有在未进行任何更新且情况不明确时,才询问用户接下来要如何处理。关闭 issue 前务必征求用户同意。

3) 分析复现步骤

评估问题是否有合理的复现步骤:

  • 是否有可以运行的代码片段?
  • 是否具备所需依赖(CUDA、分布式环境、特定硬件)? 注意:复现 torch.distributed 问题通常不需要特殊硬件——可在单台机器上使用 torchrun --nproc_per_node=1 或 mp.spawn 启动。
  • 是否描述了预期错误?
  • 复现过程是否自包含,还是需要外部数据/模型?

如果完全没有复现代码,或者问题缺少关键信息(没有错误消息,或没有描述预期行为与实际行为的差异),则添加 needs reproduction 标签(如果尚未添加),通过 gh issue edit 操作,然后停止并向用户报告。未经用户要求,不要根据问题描述尝试编写复现代码。

反之,如果问题已经带有 needs reproduction 标签,但提供了有效的复现步骤,则通过 gh issue edit --remove-label "needs reproduction" 移除该标签。

运行复现代码前,先按照安全审查清单(见上文)检查复现代码。

如果复现需要尚未安装的第三方软件包(例如 transformers、torchvision、numpy),请停止并询问用户如何继续,不要自行安装。

继续之前,先总结评估结果。

4) 检查近期验证情况

如果最近六个月内的评论已经确认该问题仍可复现(错误信息一致,且复现步骤合理),请停止并询问用户是要重新验证,还是直接进行最小化处理。

5)检查问题是否仍能复现

将复现代码提取到 /tmp/ 下的临时文件中,并在 120 秒超时限制下运行。对于涉及多次调用 torch.compile 的复现代码,如果在同一进程中多次编译,请在每次调用之间添加 torch._dynamo.reset(),以重置内存中的 Dynamo 状态。对于只编译一次后即退出的脚本,无需这样做。

如果脚本超时,请判断卡住是否就是所报告的问题,还是无关问题,并向用户报告。

运行前记录 PyTorch 版本 (python -c "import torch; print(torch.__version__)"),以便写入报告。

检查退出代码和输出以确定结果。退出代码 > 128 表示进程因信号而被终止(例如,段错误 = 139,OOM 终止 = 137)——即使没有 Python traceback,这也属于有效的崩溃复现。如果复现因 CUDA 内存不足错误而崩溃,且所报告的问题并非 OOM,请尝试缩小张量尺寸,再判断问题是否无法复现。对于正确性问题(数值结果错误而非崩溃),复现代码应包含一个在问题存在时会失败的断言。如果原始复现代码只打印输出而不包含断言,请根据问题描述中的预期行为添加一个简单断言(例如 assert torch.allclose(actual, expected)),使复现代码能明确判定通过或失败。

如果每次运行的结果不一致,请运行 3-5 次以评估其是否存在不稳定性。对于非确定性问题,请尝试设置 PYTHONHASHSEED=0 和固定的 torch.manual_seed,以稳定复现。向用户报告成功/失败比例。不稳定的复现仍然是有效的问题——请在 issue 评论(步骤 8)中注明其不稳定性,并附上成功/失败比例。

可能出现以下三种结果(判断属于哪种结果时,请匹配异常类和错误消息中有辨识度的子串——子串应足够具体,能识别出问题,例如 RuntimeError: expected scalar type Float,而不只是 RuntimeError):

  • 与报告的错误相同:问题仍能复现。继续执行步骤 6。
  • 没有错误(通过):问题可能已修复。尝试查找修复该问题的 PR(见步骤 5a),然后向用户报告。该 issue 将在步骤 8 中关闭。
  • 不同错误:区分环境问题(缺少导入、API 改名)与确实不同的问题。如果错误源于报告版本与当前版本之间的 API 变更(函数改名、模块移动、签名变更),请调整复现代码以使用当前 API,同时保留原始意图。如果错误原因不明确,请考虑使用 TORCH_LOGS=+dynamo 或其他相关日志标志重新运行,以获得更多诊断信息。向用户报告确实不同的错误。
5a) 确定修复时间和方式

当 Bug 不再复现时,尝试确定是哪个版本修复了它,以及哪个 PR 引入了修复。

版本二分:检查是否有名为 pytorch-<version> 的 conda 环境(例如 pytorch-2.6、pytorch-2.8)(conda env list | grep pytorch-)。如果有,就在这些环境中进行二分搜索,找到 Bug 首次修复的版本。在子 shell 中从 /tmp 运行,并清除 PYTHONPATH,以免载入本地源码树(否则会导致 torch._C 导入错误):(cd /tmp && PYTHONPATH= conda run -n pytorch-<version> python /tmp/repro_....py)。为加快二分搜索,每轮从候选范围中选取 2~3 个间隔均匀的探测点并行测试(例如,候选版本为 2.2 到 2.8 时,同时测试 2.4 和 2.6,将范围分成三段)。如果没有可用的版本化 conda 环境,就跳过二分搜索,只报告 Bug 在当前版本上已不再复现。

确定 PR:尝试找到修复 Bug 的具体 PR。对相关修复代码使用版本控制 blame 找到变更集,然后查找提交信息中的 PR 编号(格式为 (#NNNNN))。或者,在版本控制历史中搜索涉及相关文件且包含相关关键词的提交。如果很快找不到明确答案,就只报告版本,不要在确定 PR 上花费额外时间。

6) 精简复现代码

进行任何修改前,将原始可运行的复现代码保存到 /tmp/repro_<issue_number>_original.py。

首先,评估复现代码是否已经足够精简。只有在代码包含大量不必要的复杂内容(大型模型、未使用的代码路径、不必要的依赖等)时,才进行精简。计算复杂度时,不要把不可约的样板代码算在内——例如,只包含必需双下划线方法(__new__、__init__、__torch_dispatch__、__tensor_flatten__、__tensor_unflatten__)的张量子类定义,即使有 20 多行也不可再精简。重点关注触发代码和模型/设置的复杂度是否能得到实质性降低。如果唯一可能的“简化”只是表面调整(将变量内联、移除 __repr__),就跳过精简。

系统地减少复现代码,并测试每项简化是否仍会触发相同的错误。精简时使用较短的超时时间(30~60 秒),因为精简后的复现代码应运行得更快。如果多个候选简化彼此独立(即它们修改的代码部分互不重叠,且彼此移除的内容不存在依赖关系),就并行测试。

精简策略(大致按以下顺序执行):

  1. 移除不必要的导入和设置(分布式初始化、环境变量、日志记录)
  2. 缩小模型(用最小化的等效实现替换大型模块)
  3. 如果普通函数就足够,则移除类/模块封装
  4. 缩小张量尺寸(将较大的维度改为 4 或 8 等较小值)
  5. 移除设备/数据类型要求(先尝试 CPU 和 float32)
  6. 简化计算(用仍能触发 Bug 的最简运算替换复杂运算)
  7. 移除不必要的控制流(分支、循环、条件)
  8. 尝试更简单的后端(例如,如果 Bug 与后端无关,则用 aot_eager 替代 inductor)

每轮之后,都要验证错误是否仍会复现——异常类必须相同,且错误消息中的特征性子串必须与步骤 5 中描述的一致(回溯略有差异可以接受)。对于正确性 Bug,要保留能证明结果错误的断言,并验证它仍能展示相同的错误行为。合并多个并行简化中成功的改动时,要验证合并后的代码仍能复现,因为彼此独立的简化可能相互影响。当复现代码中的非空、非导入代码少于约 20 行时,或连续两轮(每轮为完整尝试一遍适用的精简策略)都无法进一步精简时,停止精简。

7) 应用简单修复

如果分析发现可以进行简单修复(例如,由于底层问题已修复,从测试中移除过时的 xfailIfTorchDynamo 或 expectedFailure 注解),请向用户报告该修复,并询问是否应用。未经用户批准,不要修改源文件。在第 8 步中,无论是否应用,都要提及该修复。

8) 报告调查结果

如果已精简复现用例,请将其保存到 /tmp/repro_<issue_number>.py,以便用户直接运行。

向用户提供调查结果,包括:

  • 该错误是否仍可复现(以及在哪个 PyTorch 版本上)
  • 修复该问题的 PR(如已找到,且仅当该错误已不再复现时)
  • 精简后的复现脚本(仅当已精简时)
  • 触发该错误所需的条件
  • 第 7 步中发现的任何简单修复(无论是否已应用)
  • 建议的后续操作(例如“仍是有效错误”“看起来已修复”“需要报告者提供更多信息”)

提供调查结果后,始终在该问题下发表评论。评论应简洁,不要重复问题中已有的信息。仅当复现用例相较原版有实质性更改时(例如,经过精简、更新了导入方式,或修复为可在当前 API 上运行)才附上复现用例。仅当触发条件是先前评论中未提及的新发现时,才说明触发条件。如果唯一的发现是“仍可复现”或“已不再复现”,简短评论即可。

This issue [still reproduces / no longer reproduces] on PyTorch <version>.

[If fixed and PR identified:]
Fixed by #NNNNN.

[If minimized or modernized — only include repro if changed from original:]
Minimized repro:

\`\`\`python
<repro script>
\`\`\`

[Only if new findings about trigger conditions:]
All of the following are necessary to trigger the bug:
- <condition 1>
- <condition 2>

(Analysis done by Claude.)

如果该错误已不再复现,请在发表评论后关闭问题: gh issue close <NUMBER> --repo pytorch/pytorch --reason completed --comment "Closing as this was fixed in PyTorch <version>."。 无需征求用户同意即可关闭——已修复的错误应始终关闭。

在最后一次 GitHub 修改后,恢复通知订阅状态(参见上文“保留通知订阅状态”)——但如果问题已关闭,则跳过恢复。

评论

支持 Markdown