mcgatom/codex-cannbot/model-infer-runtime-debug
Claude Code and agent skill by mcgatom/codex-cannbot
- community
Checking that the SKILL.md file is still in the repository.
基于 PyTorch 框架的昇腾 NPU 模型推理运行时错误诊断与修复技能。系统化排查模型加载、初始化、推理执行全链路的运行时错误,包括 aicore timeout、HCCL 通信错误、OOM、算子约束违反、推理卡住等。触发场景:NPU 运行时错误(RuntimeError、aicore timeout 507014、HCCL timeout、device synchronize 失败、kernel crash、EZ9999/EE9999 错误码)、推理过程卡住不返回、权重加载阶段 crash、模型加载成功但 forward 失败、分布式推理某些 rank 挂死等。
Install
npx vskill@latest install mcgatom/codex-cannbot/model-infer-runtime-debugSKILL.md
NPU 推理运行时错误诊断与修复
核心理念:先定位再修复。不覆盖精度问题,精度调优见 model-infer-precision-debug。 —— 通过二分法逐步缩小故障范围,避免在错误方向浪费时间。
部署模式适配:诊断流程对框架部署 / 独立部署两模式均适用,差异点:- 启动协议:框架部署走cann-recipes-infer/executor/scripts/function.sh::launch多卡 fork python;独立部署走torchrun --nproc_per_node=N infer.py。卡住 / crash 时先确认进程模型对应。- 通信组管理:框架部署由executor.core.config.comm_manager.CommManager一次性建组,模型类用comm_manager.get_group(name);独立部署 Runner 内 inlineParallelContext,对外接口对齐get_group(name)/get_group_name(name)/get_rank(name)。HCCL 错误诊断时确认是哪条路径。- KV cache 接入:框架部署由cann-recipes-infer/executor/core/kv_cache/自动管理cache_entries/block_table[attn_type]/slot_mapping[attn_type];独立部署 Runner 自管 KV tensor +block_table+slot_mapping。详见 model-infer-kvcache。- 权重加载:框架部署enable_online_split_weight: True由 ParallelLinear.weight_loader 自动按 rank 切;独立部署 Runner 自管或调executor.model_loader.weight_utils.default_weight_loader。
诊断路径总览
npu-smi 状态检查
当没有明确错误信息时,通过设备状态判断问题类型:
| npu-smi 表现 | 含义 | 诊断路径 | |
|---|---|---|---|
| 前 N 进程存在,后面缺失,HBM 不均 | 高位 rank 在权重加载时 crash | → 多卡部署诊断 | |
| 8 进程,HBM 均匀,AICore 全 0% | 所有 rank 卡在通信等待 | → 推理卡住诊断 | |
| 有进程,HBM 不变 ~3GB,CPU 100%+ | CPU 密集操作(模型构造/权重初始化) | → 推理卡住诊断 - 模型构造阶段 | |
| 有进程,HBM 不变 ~3GB,CPU 0% | 死锁/通信等待 | → 推理卡住诊断 | |
| 8 进程,HBM 持续增长 | 权重加载中 | 等待 | |
| 0 进程 | 全部 crash | 查 rank 0 日志 → 通用诊断流程 |
通用诊断流程
适用于有明确错误信息的场景(aicore timeout、HCCL error、OOM、shape mismatch 等)。按分类 → 定位 → 查表 → 修复 → 验证线性推进。
第一步:错误分类
拿到错误信息后,先判断属于哪一类。不同类别的根因和排查路径完全不同,分类错误会浪费大量时间。
A. aicore timeout(错误码 507014)
特征:AclrtSynchronizeDeviceWithTimeout、error code is 507014、aicore timeout、fftsplus aivector error、Kernel task happen error, retCode=0x25
含义:某个 NPU 算子在设备上执行时超时未返回。这是最常见也最难排查的错误,因为报错的位置(synchronize 调用处)通常不是出错的位置(某个具体算子)。
常见根因:
- 算子入参违反硬件约束(如 A2 上 MC2 要求
experts_per_rank <= 24,见「常见算子约束」) - 算子 shape 超出硬件限制(如单次 matmul 的 M/N/K 维度超限)
- 死锁:部分 rank 走了不同的通信路径,导致集合通信永远等不齐
- 内存越界:slot_mapping/block_table 索引超出 KV cache 分配范围
B. HCCL 通信错误
特征:HCCL_CONNECT_TIMEOUT、HCCL error、AllReduce/AllToAll timeout、HCCL_EXEC_TIMEOUT
含义:分布式通信操作超时或失败。
常见根因:
- 各 rank 进入通信操作的顺序/次数不一致(代码分支导致部分 rank 跳过某次通信,常见于 modeling forward 内有
if forward_metadata.is_prefill等分支) - 通信组创建时参数错误:框架部署核查
CommManager.initialize()的 group_stride / group_num;独立部署核查ParallelContext.build_parallel_context()内init_comm_group调用参数 - MoE EP 场景缺
moe_ep_group_name:dispatch_v2 / combine_v2 算子要求 HCCL group name,框架部署用comm_manager.get_group_name("moe_ep_group");独立部署用parallel_ctx.get_group_name("moe_ep_group") - 网络问题(跨节点时 HCCL_IF_IP 配置错误)
- HCCL_BUFFSIZE 不足(大 batch / 大 hidden_size 的 dispatch/combine 失败)—— 调高至 512MB 试试
- 某些 rank 已经 crash 但其他 rank 还在等它参与通信
C. OOM(显存不足)
特征:NPU out of memory、Tried to allocate X GiB、ENOMEM
含义:NPU HBM 不够。
常见根因:
- 模型参数/KV cache/activation 总和超过单卡显存
- 中间 tensor 未及时释放(常见于 MoE EP all-to-all 中间 buffer)
- batch_size 或 seq_len 超出预期
- migrator 阶段单卡 OOM:编排层会标记"需多卡",并行化(parallel-impl skill)后再补采基线,不是必修问题
D. Shape 不匹配
特征:RuntimeError: shape mismatch、expected size X but got Y、mat1 and mat2 shapes cannot be multiplied
含义:tensor 维度不对。
常见根因:
- TP 切分后维度未正确除以 tp_size:核对 ParallelLinear 的
tp_size/tp_rank(标准用comm_manager.get_rank("attn_tp_group")/parallel_ctx.get_rank("attn_tp_group")等取,避免硬编码) - KV cache 的
num_head字段:必须用num_kv_heads_per_rank = max(num_kv_heads // attn_tp_size, 1),与 parallel-impl skillattn_tp_size改动联动 - EP 切分后每卡专家数计算错误:检查
experts_per_rank = num_experts // ep_size - Prefill/Decode 分支传入了错误 shape 的 tensor(阶段分支统一用
forward_metadata.is_prefill) - packed sequence 协议错误:modeling 内
hidden_states被 reshape 成[B, S, H](变长 batch 不能简单 reshape,应保持[TotalTokens, hidden_size]二维,详见 model-infer-kvcache §3.1) - 多 attn_type 混合模型:误把
block_table当 plain Tensor 传给 FA,应该取block_table[self.attn_type](dict 索引)
E. 算子约束违反
特征:不直接报约束错误,通常表现为 aicore timeout 或 SIGABRT。需要通过二分法定位后,查阅算子文档确认。
含义:NPU 自定义算子对入参有隐含约束(数据类型、维度范围、硬件平台限制),违反时行为未定义。
第二步:二分法定位(sync+barrier 检查点法)
核心方法。当错误发生在 torch.npu.synchronize() 时,错误信息只告诉你"设备上有东西出错了",不告诉你具体哪个算子。通过插入检查点逐步缩小范围。
2.1 定位到阶段(Prefill vs Decode)
在 runner 的 model_inference 方法中,prefill 和 decode 调用之间插入同步检查:
关键陷阱:NPU 操作是异步的。model.prefill() 返回不代表 prefill 完成 —— 只有 torch.npu.synchronize() 返回才代表所有已提交的操作完成。所以报错位置(synchronize 调用处)不一定是出错位置(某个具体算子)。确保检查点覆盖所有可能的异步操作。
2.2 定位到层
确认出错阶段后(如 Decode),在每个 decoder layer 之间插入检查点:
如果 Layer 0 就超时 —— 问题在第一层内部。如果 Layer 2 超时 —— 问题在第 2 层或其子模块。
2.3 定位到模块
进入出错层,在各子模块之间插入检查点:
2.4 定位到算子
进入出错模块,在每个 NPU 算子调用之间插入检查点。此时通常可以定位到具体算子及其入参,结合下文「常见算子约束」判断根因。
2.5 注意事项
- 先用 `torch.npu.synchronize()` 做单卡定位,确认是哪个算子出错。不要一开始就加
dist.barrier()——barrier 会在某 rank 已崩溃时导致其他 rank 永久挂起 - 怀疑多 rank 不同步时,用
dist.barrier()或torch.distributed.monitored_barrier()确认各 rank 是否走到同一位置。monitored_barrier在超时后会报告哪个 rank 未到达 - 查看所有 rank 的日志,确认各 rank 到达的检查点是否一致(不一致说明有条件分支差异 → 通信死锁)
- 不要一次插入太多检查点 —— 每次 sync 有开销,且大量 sync 可能改变时序。先粗粒度,再细粒度
- 保留日志:把每轮定位的检查点输出保存,供后续分析
第三步:常见 NPU 算子约束速查
以下约束来自本仓实际调试经验,定位到具体算子后应回到当前调用的 API 签名和官方文档核对,不要跨算子套用规则。违反约束的典型表现是 aicore timeout。
MoE 相关算子
| 算子 | 约束 | 违反表现 | 解决方案 | |
|---|---|---|---|---|
npu_moe_distribute_dispatch_v2 (MC2) | A2: experts_per_rank = moe_expert_num // (ep_world_size - shared_expert_rank_num) <= 24;A3 无此 24 限制 | aicore timeout,Decode 阶段挂死 | experts_per_rank > 24 时回退到 double_routing 路径(npu_moe_init_routing_v2 + manual all_to_all) | |
npu_moe_distribute_combine_v2 (MC2) | 同上 | 同上 | 同上 | |
npu_moe_init_routing_v2 | 无 EP 最小限制,但 moe_chunk_max_len 为 0 可能导致空 tensor | SIGABRT 或 shape error | 设置合理的 moe_chunk_max_len(如 1024) | |
npu_moe_gating_top_k | k 不能超过专家总数 | 静默错误输出或 crash | 检查 reduced model 的 moe_topk 是否已调整 |
FA (Flash Attention) 算子
| 约束 | 说明 | |
|---|---|---|
head_num 须匹配实际 Q heads | MLA 模型中 head_num = num_attention_heads,不是 kv_heads | |
sparse_mode + atten_mask 按路径分类 | 标准 LLM TND PA 路径 Prefill+Decode 统一 sparse_mode=3 + causal mask;滑窗层统一 sparse_mode=4 + band;MLA absorb Prefill 3 / Decode 0+None。详见 model-infer-kvcache §2.7 | |
| atten_mask shape | sparse_mode=3/4 时固定 [2048, 2048] bool(用 executor.utils.common_utils.get_init_attn_mask(2048, device) 构造) | |
input_layout 按 API 和阶段区分 | npu_fusion_attention 用 BSH/SBH/BSND/BNSD/TND;npu_fused_infer_attention_score 用复合 layout 如 TND_NTD(PA + MLA 默认推荐)、BSND_NBSD(KVP 场景),以实际 API 签名为准 | |
Decode PA 模式下 block_table | shape [batch, max_blocks],值不能超出 cache 分配的 block 数;框架部署是 Dict[attn_type → Tensor],attention 内取 block_table[self.attn_type] | |
| FA v1 + BSH + Q_S=1 Decode 算子级限制 | op 内部忽略 sparse_mode / pre_tokens(实测 sparse_mode 0 vs 4 等价);滑窗模型长序列正确性靠模型层 actual_seq_lengths_kv 截断 | |
| NZ 格式 cache | 需要 torch_npu.npu_format_cast 转换,且 hidden_dim 须为 16 的整数倍 |
actual_seq_lengths相关参数以"当前调用算子的签名与官方 API 文档"为准,不跨算子套用规则:-torch_npu.npu_fused_infer_attention_score/torch_npu.npu_fusion_attention:actual_seq_lengths*为List[int](文档为 int64 语义)-torch_npu.npu_kv_quant_sparse_flash_attention:actual_seq_lengths_query/kv为Tensor(文档为 int32)
通信算子
| 约束 | 说明 | |
|---|---|---|
all_to_all_single 的 split sizes | input_splits 和 output_splits 之和须分别等于 input 和 output 的第 0 维 | |
| 通信组内所有 rank 须同时到达 | 任何条件分支差异都可能导致部分 rank 跳过通信 → 死锁 | |
| HCCL group 创建顺序 | 所有 rank 须以相同顺序创建相同的通信组 |
第四步:修复策略模式
定位根因后,选择合适的修复策略。
模式 1:算子回退(Operator Fallback)
当某个高性能算子在当前硬件/配置下不可用时,回退到功能等价但限制更少的替代算子。
适用场景:硬件约束、EP/TP size 不满足算子要求 注意:回退通常有性能损失,需记录在优化报告中
模式 2:参数修正(Parameter Fix)
算子入参计算错误(如 FA head_num 用了 KV heads 而非 Q heads、TP 切分后维度未除以 tp_size)。定位到具体算子后,逐个核对入参与算子文档/参考模型的差异。
适用场景:shape 不匹配、dtype 错误、维度计算错误
模式 3:路径统一(Path Unification)
部分 rank 走不同代码路径导致通信死锁。
适用场景:多 rank 死锁、HCCL timeout
模式 4:配置降级(Configuration Downgrade)
配置组合不兼容时,调整 YAML 参数(如降低 moe_chunk_max_len、减小 batch_size)。
适用场景:OOM、性能异常
第五步:验证清单
修复后,按以下清单验证:
- [ ] 单步验证:在出错位置前后加 sync+barrier,确认不再超时
- [ ] 全流程验证:移除所有调试检查点,运行完整 warmup + inference
- [ ] 全 rank 验证:检查所有 rank 的日志,确认全部成功(
grep "model run success" log_*.log) - [ ] 输出一致性:各 rank 的最终输出应一致(对 DP 模式,同 DP group 内的 rank 输出应一致)
- [ ] 性能记录:记录修复后的 Prefill/Decode 耗时,与修复前对比
- [ ] 回退文档:如果使用了算子回退,记录性能影响和未来可恢复条件
特定场景诊断
以下场景有独立的诊断路径,不走通用流程。通过入口 npu-smi 表判断后直接跳转。
多卡部署诊断
多卡部署引入了一类单卡不存在的问题:权重加载切分、vocab 对齐、部分 rank 崩溃、config 兼容性。共同特点:部分 rank 成功、部分 rank 失败,错误出现在权重加载阶段而非 forward 阶段。
启动协议区分:框架部署用cann-recipes-infer/executor/scripts/function.sh::launch多卡 fork python(每个 rank 单独起进程,通过LOCAL_RANK/RANK_ID环境变量区分);独立部署用torchrun --nproc_per_node=N infer.py(torchrun 自动注入 RANK / WORLD_SIZE / LOCAL_RANK / MASTER_ADDR / MASTER_PORT)。卡 / crash 时先确认对应启动方式的进程模型。
权重加载 TP 切分越界
典型错误:
或:
根因:ColumnParallelLinear / VocabParallelEmbedding 将权重沿 output 维度切分为对应 *_tp_size 份。如果 checkpoint 的实际维度不等于模型参数的维度,或者不能被对应 *_tp_size 整除,高位 rank 的 narrow() 操作就会越界。
常见场景:
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/model-infer-runtime-debug/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/mcgatom/codex-cannbot/model-infer-runtime-debug)