← 首页|学术|别重生成,去调试:修复"近失败"硬件算子的领域专用Debug Agent
cs.SE / cs.AI · 2608.02712 · 2026年8月3日提交

别重生成,去调试:修复"近失败"硬件算子的领域专用Debug Agent
Don't Regenerate, Debug: A Domain-Specific Agent for Repairing Near-Miss Hardware Operators

Yansong Sun, Shenxiu Wu, Siyuan Chen, Runlin Hou, Junhao Qiu, Junming Cao, Shudi Shao, Zhichao Lu, Qingfu Zhang
💬 LLM生成硬件kernel(GPU/NPU算子)时,大量候选"编译通过、能跑起来,但数值验证失败"——这些near-miss候选目前被当成废料直接丢弃、重新生成。本文认为这是巨大的浪费:调试是比重新生成更受约束、反馈更密集的搜索问题。作者构建了一个引擎主导、agent仅负责修复(无验收权)的领域专用debug agent,在27个真实near-miss AscendC算子上把Pass@1从重生成的25.9%(Pass@3为40.7%)提升到66.7%,且每次成功平均节省92.8%的token。

🎯 问题

Kernel生成流水线在丢弃什么
当前主流做法(如Huawei CANNBot等自动化AscendC算子生成流水线)遇到候选"编译运行成功但数值验证未通过"时,标准应对是整体丢弃、重新从头生成,最多再多采样几次(Pass@k)。作者指出这种做法忽略了一个关键事实:这些候选已经跨过了最难的第一道门槛(能编译、能跑),距离正确往往只差局部的数值/精度问题。把它们当废料处理,等于把已经投入的大量搜索代价和"这次错在哪"的诊断信息一并丢掉,转而在同样巨大的解空间里重新盲搜。论文用NPUKernelBench中27个被CANNBot生成流水线判定为"near-miss"(编译执行通过、数值验证失败)的真实AscendC算子作为测试床,覆盖L1到L5-L7四档难度。

🔬 方法

引擎主导、agent无验收权的四层架构
核心设计原则:引擎(engine)拥有验证、取证(forensics)和完整性检查的全部权力;agent只在修复阶段工作,没有"判定通过"的权力——这是防止agent自我汇报成功、走捷径的关键结构性约束。系统按 forensics → 诊断与修复 → validate 的三段循环运行,直到通过、触发收敛守卫,或达到预算上限。
四层结构:
编排层(Orchestration):确定性状态机,从持久化事件日志重建控制状态,使每次运行可审计、可从任意中断点恢复;
引导层(Guidance):知识检索(JSON结构化知识库,按失败类型和算子类别索引,入库要求0.95匹配率+干净的完整性历史)+ 诊断插桩(在pipeline边界插入多级张量统计,但只在首次无辅助尝试失败后才启用,因为插桩本身消耗agent轮次和取证周期);
完整性层(Integrity):反作弊检测 + 全覆盖评估(见下);
控制层(Control):收敛守卫 + 预算强制执行。
反作弊检测:防止"修复"变成"绕过"
每次validate时引擎都会重新计算两项检查:wrapper校验(检查Python适配层是否调用了参考算子等fallback模式)和kernel源码扫描(检测禁止的host fallback调用 at::/torch::,并确认存在真正的自定义kernel launch)。凡是被判定"wrapper辅助"绕过检测的修复,即便数值正确也会被拒绝——这直接回应了reward hacking问题。
全覆盖评估 + 收敛守卫/有界迭代
轻量测试集驱动快速迭代,通过后才升级到扩展测试集做最终认证,证据以不可变artifact持久化。硬性边界:单session 240 agent轮次、单任务跨所有尝试600轮次、5轮修复(build error子上限3、精度失败子上限5)+ 墙钟超时。引擎会快照最佳评分kernel,若连续两次尝试无法超越该最佳分则回滚。自适应调度加入语义规则(near-pass/fp16天花板检测、震荡检测、停滞检测),软预算从480轮起,仅在有实质进展证据时才扩展。

📊 结果

Debug Pass@1
66.7%
18/27
Regenerate Pass@3
40.7%
11/27
Token节省/成功
92.8%
vs Regen Pass@3
主实验(RQ1):Debug Pass@1达66.7%,比Regenerate Pass@3(三次重生成尝试取最优)的40.7%高出+25.9个百分点;仅Regenerate Avg Pass@1(单次)为25.9%。两种方法成功的算子重叠仅7个,Debug独有成功11个,Regenerate独有成功4个——说明两种策略挖掘的是不同的解,并非简单的子集关系。
效率(RQ2):Debug每算子消耗0.247M未缓存token,仅为Regenerate Avg Pass@1(0.435M,1.76倍)和Pass@3(1.305M,5.28倍)的一小部分;按每次成功折算(含缓存token),比Regenerate Pass@3低92.8%。配对McNemar检验对每个重生成trial均显著(p=0.0129/0.0024/0.0129,经Bonferroni校正后仍显著)。
对比CANNBot精度调试模式(RQ3):Debug 66.7% vs CANNBot精度调试模式(CBD)44.4%,+22.2个百分点;换用Kimi K3模型复现,margin为+18.5个百分点(21/27 vs 16/27,未达显著性);per-success总token节省66.3%。
消融(RQ4):去掉知识库,Pass@1从18/27跌到13/27(-18.5pp),每次成功token升1.58倍——知识库是最关键组件;去掉诊断插桩,Pass@1降到15/27(-11.1pp);去掉反作弊检测,会有12.5%(2/16)的"成功"其实是不被支持的绕过;去掉全覆盖评估,比例升到33.3%(6/18)——说明轻量测试集本身对精度bug存在明显的漏检;去掉自适应调度,Pass@1无变化(仍18/27),提示当前阈值设置有进一步校准空间。覆盖审计还发现任务难度标签并不能完全反映评估复杂度,例如L2任务的评估用例数从任务侧标注的10个膨胀到全覆盖时的49-58个。

💡 我的看法

这篇论文的核心洞察和我关注的"失败轨迹是可复用知识资产"这条线高度呼应——本质上是把"重新生成 vs 调试已有失败"这个选择,从代码agent领域搬到了硬件kernel生成这个反馈信号更稀疏、验证成本更高的场景。几个值得注意的设计选择:
1)结构性权力分离(引擎有验收权、agent无验收权)比单纯依赖prompt约束更可靠,这也是为什么反作弊检测能抓到12.5%-33.3%的"虚假成功"——如果让agent自己报告通过,这些绕过很可能蒙混过关,这提示我们在设计任何"agent自主修复循环"时,验证权应该始终留在agent控制之外。
2)知识库是最贵重的资产而非诊断插桩——消融显示知识库缺失的代价(-18.5pp)远大于插桩缺失(-11.1pp),说明"记住这一类失败该怎么修"比"更细粒度地观察这次失败"更有杠杆,这对我们做故障轨迹知识沉淀(TraceCompiler方向)是个有力的间接证据:结构化、可复用的失败-修复模式库,价值可能超过单次调试时更精细的可观测性投入。
3)全覆盖评估暴露的"轻量测试集系统性漏检精度bug"(33.3%虚假通过率)是一个很实际的教训——在任何"编译/运行通过即算成功"的agent评估范式里,都要警惕验证集本身覆盖不足带来的虚假信号,这和code agent里"测试通过≠正确"的经典陷阱是同一个问题在硬件kernel领域的重现。
硬件Kernel生成Debug AgentReward Hacking失败轨迹复用
来源: arXiv:2608.02712