AscendKernelGen: A Systematic Study of LLM-Based Kernel Generation for Neural Processing Units 【华为26年paper】这篇文章在讲什么这篇文章研究的是能不能让大语言模型替人写 NPU 内核代码而且写出来的不只是“像代码”而是真的能编译、能跑对、最好还能跑得快。这里的 NPU 不是我们平时写 Python、C 那种通用编程环境而是华为 Ascend 这类 AI 加速器对应的底层编程体系。作者关注的语言是 AscendC。这个领域的特点是1. 不是“会写程序”就能写好。2. 你必须同时理解硬件、内存层次、并行执行方式、同步机制、tiling分块、数据布局等很多底层约束。3. 代码是否正确不只是看语法还要看是否满足硬件接口约束、数值是否正确、运行是否高效。所以这篇文章不是普通的“代码生成论文”而是在讨论一个更难的问题LLM 能否掌握硬件相关的专门知识并把这些知识转化成真正可执行的低层 kernel。作者的核心判断很明确1. 通用 LLM 在这种任务上几乎不行。2. 问题不只是 prompt 不够好而是数据、推理模式、训练方式、评测方式都不对。3. 想把这件事做起来必须把“数据集 专项训练 硬件级评测”一起做。1. 什么叫 kernel在 AI 加速器里kernel 可以理解成“一个非常底层、非常专用的计算小程序”。比如矩阵乘、归一化、激活函数、TopK、Attention 的某个子步骤都可能由一个或多个 kernel 完成。上层框架里你可能只写一行y layer_norm(x)但在底层真正把这个计算搬到 NPU 上执行的往往就是一段专门写出来的 kernel。2. 为什么 kernel 难写因为你不是只写“算什么”你还得写“怎么在这块硬件上高效地算”。例如1. 数据先放在哪里放到全局内存还是片上缓存2. 一次处理多少元素怎么分块3. 什么时候搬数据什么时候算4. 数据搬运和计算能不能并行重叠5. 多个执行单元之间要不要同步6. 输入尺寸不是整齐对齐时边界怎么处理这些问题如果处理不好会出现三类后果1. 编译不过。2. 编译能过但结果算错。3. 结果对了但性能很差甚至比手写基线慢。3. AscendC 和 CUDA / Triton 有什么不同如果你熟悉 GPU 方向可以把 AscendC 理解成一种强硬件约束、强接口约束的低层 DSL。但它和 CUDA/Triton 又不完全一样1. 生态更封闭。2. 开源训练数据更少。3. API 语义更专门。4. 很多正确写法依赖厂商文档、工程模板和经验积累。这意味着通用代码模型虽然见过大量 Python、C、Java但并没有真正学到 AscendC 这种窄而深的知识体系。4. 为什么“能编译”不等于“能用”这是硬件代码生成里最容易被忽略的一点。普通代码生成 benchmark 往往只关心功能测试是否通过但 kernel 任务至少要看三层1. Compilation能不能过编译。2. Correctness输出数值对不对。3. Performance性能是否达到合理水平。比如一个模型可能会生成一个“语法看起来挺像”的 kernel但1. 调了一个并不存在的 API。2. 参数顺序错了。3. tile 大小算错了。4. host 侧算出来的 tiling 参数和 device 侧实际读取的逻辑不一致。5. 边界 mask 少写了一个条件结果只有部分输入会算错。所以这类任务比 HumanEval 那种“写个函数通过单元测试”难得多。一、INTRO1. 为什么这个问题重要开头先从大背景切入AI 和深度学习发展很快为了追求更高计算效率domain-specific accelerators越来越重要其中 NPU 已经成为现代 AI 基础设施里的关键硬件但 NPU 真正能不能发挥性能不只取决于硬件本身还取决于底层compute kernel的质量这里作者想建立的逻辑是NPU 很重要 → kernel 很关键 → kernel 开发问题值得单独研究。kernel quality 是释放 NPU 能力的前提。2. 传统 kernel 开发为什么难因为它通常依赖厂商专用的硬件编程方式文中把这类东西称为vendor-specific DSLs, such as AscendC。而开发者必须掌握很多很底层的知识例如分层内存管理global memory / on-chip memory数据 tiling异步流水线编程向量单元和矩阵单元的显式利用作者这里要突出两个结论学习门槛很高人工开发代价很大而且容易出错所以 Intro 的第二步是在说这个任务难不是因为代码长而是因为它要求程序员理解硬件执行机制。3. 引出 LLM但立刻指出通用 LLM 不行然后文章顺势过渡到 LLM现在大模型在通用代码生成上很强所以自然会想到能不能让 LLM 自动生成 NPU kernel但作者没有直接唱好而是马上泼冷水不行至少通用 LLM 直接上基本不行。原因有两点3.1 领域知识本质不同作者认为NPU 这种硬件特定代码所需知识和普通编程知识不一样涉及严格 API 约束架构相关语义性能敏感优化模式这说明作者对问题的判断不是“模型不够大”而是训练分布不对任务本质也不一样。3.2 高质量训练数据稀缺通用代码很多但高质量 NPU kernel 数据很少。所以通用 LLM 没法自然学到这一类知识。4. 用实验事实证明“通用模型不行”为了避免只是口头判断作者在 Intro 里给了一个前测结果这里要特别注意“Compilation Success”和“Functional Correctness”是分开的。比如 Llama3.1-8B 在复杂任务上的编译成功率居然还有 19.44%但功能正确率是 0。这说明1. 模型可以凑出某种“形式上像代码”的东西。2. 但它并没有真正理解 kernel 的执行语义。很多人会以为“能编译就已经八九不离十了”。但在底层硬件代码里能编译只是第一道门槛。通用模型在 zero-shot 生成 AscendC kernel 时表现极差常见问题包括幻觉不存在的 API比如AscendC::Softmax严重误用硬件接口编译失败率很高对复杂的 L2/L3 kernel执行成功率几乎掉到0%作者想借这个结果说明现有通用代码大模型不能直接迁移到复杂 NPU kernel 生成。也就是说这篇文章的研究动机不是“让效果更好一点”而是先把这个任务从几乎不可用推到可用。5.提出作者自己的核心判断在证明通用模型不行之后作者就给出自己的诊断要想让 LLM 能做 NPU kernel generation需要两个关键条件5.1 模型必须学会硬件专用编程范式也就是要理解硬件架构特性API 约束kernel 的推理方式5.2 必须有专业可靠的评测框架不能只测“像不像代码”而要测compilationfunctional correctnessperformance作者认为问题不是单点模型问题而是两个层面的问题训练问题模型没学到这个领域知识评测问题没有足够严谨的 benchmark 去判断生成结果到底行不行6. 正式抛出本文方案于是作者提出AscendKernelGen并把自己的贡献概括成三部分6.1 Ascend-CoT一个面向低层 NPU kernel 编程的数据集强调pipeline constructionsynchronization logicarithmetic reasoning patterns这意味着作者不是只收集代码而是收集推理过程。6.2 KernelGen-LM在强基座模型上做领域自适应后训练专门提升低层 NPU kernel 生成能力。6.3 NPUKernelBench一个评测框架从三个维度评估生成 kernel编译是否成功功能是否正确性能怎么样所以 Intro 最后的落点不是“我们设计了一个新模型”而是我们搭了一个从数据、训练到评测的完整研究框架。二、挑战这一节是整篇论文里我认为最应该认真读的理论部分之一。作者没有陷入“Ascend 某个指令长什么样”的细节泥潭而是先抽象出 NPU kernel 编程的结构本质。作者把低层 NPU kernel 概括成一种“静态结构化程序”它同时规定了1. 全局数据怎么分块。2. 异步流水各阶段怎么排。3. 同步关系怎么建立。4. 在多个处理单元上如何复制执行模板。例如你不只是写一行加法而是在安排1. 第一步从全局内存把数据搬到片上。2. 第二步让计算单元处理当前 tile。3. 第三步把结果写回。4. 与此同时下一块数据可能已经在预取。5. 中间还要靠同步原语保证“先搬完再计算”“先算完再写回”。作者在这一节总结了四个关键难点我认为非常准确1. 长距离语义依赖。例如 block index、tiling factor、边界大小等参数可能在 host 侧算出来在 kernel 多个位置使用。模型必须跨多段代码保持语义一致。2. 显式同步推理。同步原语不是“写了就安全”而是必须成对、按时序、按依赖关系出现。少一个会数据冒险多一个会卡死顺序错了也会错。3. 边界敏感的算术推理。输入尺寸往往不是块大小的整数倍所以需要处理尾块。一个 写成 或者 mask 少一位结果就会错。4. 布局感知推理。某个阶段为了适配硬件单元数据物理布局可能和逻辑张量布局不同。代码必须知道“现在这个数据长得像什么”和“它语义上代表什么”。这一节的价值在于作者把问题从“模型没见过 AscendC”提升到了“这种程序天然需要跨区域、多约束、时序化推理”。这使得后面的数据设计和训练设计有了逻辑基础。二、文章总体思路作者提出了一个完整框架 AscendKernelGen。它不是单点方法而是三部分联动1. Ascend-CoT面向 AscendC 内核生成的领域推理数据集。2. KernelGen-LM在通用模型基础上做领域后训练得到的专门模型。3. NPUKernelBench真正落到硬件上的评测基准检查编译、正确性和性能。这三者的关系可以借助文中的 Figure 1 来理解。Figure 1 不是简单流程图而是在说明作者的总体研究立场他们不把“生成代码”看成一个孤立的文本任务而是看成一个闭环系统。这个闭环包括1. 从文档、代码、工程项目中构造训练数据。2. 用这些数据对模型做 SFT 和 RL。3. 让模型生成 host 代码和 kernel 代码。4. 把生成结果送进真实的编译与执行流水线。5. 再把错误信息和执行反馈反哺回训练。这张图真正要表达的重点是作者不是只想证明“模型能输出看起来像 AscendC 的文本”而是想让模型在“生成 - 编译 - 执行 - 修正”的工业闭环里逐步变强。这也是这篇工作相对扎实的地方。在系统概览中作者把 AscendKernelGen 分成两大部分1. 生成侧Ascend-CoT KernelGen-LM。2. 评测侧NPUKernelBench。如果只看文字这很像标准套路但结合 Figure 1 来读就会发现作者在强调三个层面的“闭环”1. 知识闭环文档知识、代码知识、项目知识都被转成监督信号。2. 训练闭环SFT 先教会基本结构RL 再根据执行反馈做细化。3. 评测闭环从编译到正确性到性能层层筛。也就是说Figure 1 其实是在反对一种常见的偷懒做法只做 prompt engineering然后用少数 case 展示几个成功样例。作者想证明的是这种任务必须在系统工程意义上搭完整。这里可以给一个很通俗的类比如果把通用代码生成看成“让模型写作文”那这篇文章处理的是“让模型按工艺标准绘制并验证一张可投产的工程图纸”。后者不能只看语言流畅度必须有生产线验证。数据构建这篇论文的一个重要贡献不是“想了个更巧的 prompt”而是认真构建了领域推理数据。作者把数据分成三类这个拆法是有逻辑的。Documentation-Based CoT把文档变成“会推理的知识”第一类数据来自官方文档包括1. Operator Development Guide。2. API Reference。3. Best Practices。很多人做领域适配时会简单把文档喂给模型继续预训练但作者这里没有停在“灌知识”层面而是把文档转成 question-answer 加 reasoning trace 的形式。这个设计很关键因为它不是让模型机械记忆 API而是让模型学习1. 某个 API 什么时候该用。2. 参数约束是什么。3. 典型错误长什么样。4. 为什么某种写法会违反硬件/接口约束。换句话说作者不是只想让模型“背 API 手册”而是想让模型像工程师一样解释 API 使用逻辑。这类数据的作用主要是解决两个问题1. 降低 hallucination。2. 把“接口合法性”显式注入模型。不过也要客观看它的上限是有限的。因为文档能覆盖规则但不一定能覆盖复杂工程中的隐式配合关系。Code-Centric CoT第二类数据来自真实 AscendC operator 实现。作者把这类数据又分成两种1. 能独立编译的单体 kernel 文件做 kernel-level CoT。2. 复杂工程项目拆成 host-kernel 对做 project-level CoT。这里的 project-level CoT 非常关键。因为很多真正复杂的问题并不在 kernel 单体内部而在 host 和 device 的协同。举个例子1. host 侧根据输入形状算出 tiling 参数。2. 这些参数通过结构体传给 kernel。3. kernel 侧再依据这些参数安排内存与计算。如果 host 侧算的块大小、循环次数、边界条件和 kernel 侧消费这些参数的方式不一致代码可能编译通过但运行就错。所以作者不是简单用“代码 - 注释”配对而是试图让模型学到跨 host/device 边界的因果关系。这一点比很多只做 kernel 片段学习的工作更像工业真实场景。这部分还有一个比较扎实的点作者说只保留通过自动验证的 CoT 样本。也就是说他们知道 reasoning 数据很容易“写得头头是道但其实不对”所以增加了一层过滤。当然局限也存在论文并没有完全展开说明这些 CoT 的生成质量到底如何、人工校验比例有多少、是否存在模型自举生成 reasoning 再训练自己的风险。如果这些推理链主要由别的 LLM 生成那么它的可靠性仍然值得继续追问。General CoT防止模型过窄第三类数据是一般推理数据比如数学、代码推理、科学问答等。作者的理由是如果全用窄领域数据训练模型可能会失去一般问题求解能力。这个思路是合理的因为 kernel 生成不是纯背模板它依然需要一般性的逻辑推理、算术推理和多步规划能力。训练设计这一节讲训练流程先 SFT再 RL。思路本身并不新但作者做得比较扎实的地方在于他们没有把 SFT 理解成“拿正确答案直接训”而是引入了 error-derived supervision。Error-Derived SupervisionFigure 2 讲的是作者如何把错误转化成训练信号。它不是简单说“收集错误样本”而是分成两层1. API-level error correction。2. Kernel-level numerical inconsistency correction。这两个层次分别对应两类很常见、但性质不同的问题。第一类是 API 级错误。比如1. 参数顺序错。2. 参数类型不匹配。3. 调用了不存在的重载。4. 某个接口少了必要参数。作者在 Algorithm 1 里给出了流程从 build log 里抽错把相关代码片段和 API 文档拼起来再让模型分析根因、给出修正实现。这个思路是对的因为编译错误日志本身就是一种“强监督信号”它明确告诉你哪里违反了接口约束。第二类是 kernel 级数值错误。也就是代码能编译但结果不对。这个比 API 错误难因为它往往意味着1. memory staging 有问题2. 累加顺序不对3. host-kernel 的 tiling 语义不一致4. 某个边界条件没处理好。作者在 Algorithm 2 里做的事是找出这类“能编译但验错”的样本再配对 ground-truth kernel用重构式 CoT 让模型重新分析错误并生成正确实现。这套做法的意义在于它把“失败样本”从噪声变成了高价值教材。普通 SFT 像是在给学生看标准答案而 error-derived SFT 像是在把错题本系统化整理出来再教学生为什么错、应该怎么改。这通常比只看标准答案更有针对性。当然这里也有一个值得警惕的点作者把 GT kernel 当作监督目标这会明显提升“向已有实现靠拢”的能力但也可能让模型更擅长模仿已有写法而不是探索真正新的优化结构。所以它提升的是“可靠复现与修正”能力不一定直接等价于“原创优化”能力。Reinforcement Learning在 RL 部分作者采用 DPO 风格的偏好优化。这里最重要的是正负样本怎么构造1. 编译通过且精度通过的作为正样本。2. 编译通过但精度失败的作为负样本。这比拿“编译失败样本”做负例更有信息量因为1. 编译失败说明模型连门槛都没过2. 编译通过但精度失败说明它已经走到了更接近可用实现的位置3. 此时正负样本之间的差别往往更接近真正关键的执行语义差别。不过这部分也有一条明显短板当前 RL 的优化目标主要还是围绕正确性性能只是在最终评测里看并没有形成一个强的性能导向奖励。作者自己在结论里也承认未来要进一步引入 performance-aware reward。这其实意味着现阶段的 RL 更像“让模型少犯执行级错误”而不是“系统性学会性能最优”。NPUKernelBench如果没有一个像样的 benchmark这篇文章很容易退化成“作者自己说自己模型写得不错”。NPUKernelBench 的作用就是尽量把这个问题制度化。Benchmark Overview作者强调 benchmark 是 end-to-end 的给定任务、生成代码、编译、执行、验证正确性、测性能全流程自动化。这点很重要因为很多代码生成 benchmark 到了硬件方向就偷懒只做静态检查或者少量运行样例。这里作者明确把真实硬件执行纳入评测闭环这让结果更可信。Table 2 把 158 个 kernel 按 Level 1、2、3 分级还进一步区分 static-shape 和 dynamic-shape。这个设计很有必要因为如果把所有任务混在一起平均分会掩盖问题。1. Level 1 是简单元素级或算术操作例如 Add、Sqrt。2. Level 2 是常见神经网络算子如激活、norm、mask、reduce 等。3. Level 3 则是 Gemm、TopK、attention 相关这类具有全局依赖或复杂控制流的任务。这个分层背后的逻辑很清楚1. Level 1 更像“会不会写基本模板”。2. Level 2 开始考察局部数据复用、结构化计算和标准优化套路。3. Level 3 才真正逼近复杂工业 kernel 的推理深度。从后面结果看这个分层是有效的因为模型在 Level 1、2、3 上的表现差异非常明显。Figure 3 的双路径设计是这篇 benchmark 的一个亮点。作者区分了1. Device-Only Path只让模型生成 kernelhost 端由固定驱动提供。2. HostDevice Path让模型同时生成 host 和 kernel。这背后的现实考虑是1. 有些任务主要难在 kernel 本体2. 有些任务真正难在 host 和 device 的协同比如动态 shape、tiling 计算、shape inference。如果不区分这两种情况就会把“kernel 逻辑错误”和“host 侧 orchestration 错误”混在一起最后很难分析模型到底卡在哪。Figure 3 其实是在告诉你作者不把 kernel 生成看成一个单文件补全问题而是把它看成系统代码生成问题。这一点和工业需求是吻合的。Table 3 列出了通用 prompt 指令比如1. 角色设定是专业 Ascend kernel 工程师。2. 必须使用 Ascend C。3. 输出格式上 host 与 kernel 分离。4. 注意数据类型、shape、layout。这张表的价值不在“prompt 写得多漂亮”而在“作者试图规范输入接口”减少因为 prompt 随意性导致的评测波动。不过这里要保持客观这类 role prompt 和格式约束确实能帮助编译率但它们更多是“把模型约束在轨道上”不等于模型真的学会了深层推理。所以它是必要工程措施不是根本创新。Table 4 给了编译日志示例Table 5 给了评分准则。它们说明作者对评测链条做了拆解1. 先看能否编译。2. 再看数值精度是否过线。3. 再看性能相对基线的速度提升。这里尤其值得注意的是精度检查并不是一句“输出相同”这么简单而是带绝对误差和相对误差阈值的。对浮点 kernel 来说这比简单的 exact match 更合理。三、实验Table 6 汇总了数据构建、SFT、RL 阶段的模型和配置。作者不只训了一个模型而是还比较了不同规模的 Qwen 变体并分析了 full fine-tuning 和 LoRA。这使得论文更像“systematic study”而不只是“我们选了一个模型调一调”。Table 7 是全文最核心的结果表之一。它展示了 base model、SFT、SFTRL 在不同 level、不同 passk 下的编译率和执行率以及 speedup。最值得看的点有四个。第一base model 基本只在 Level 1 上还有一点点能力。Qwen3-32B 在 Level 1 上 Pass1 编译率 38.08%执行率 17.39%说明它能碰巧写出一些简单 kernel但到了 Level 2Pass1 和 Pass10 几乎全灭Level 3 更是基本无执行成功。这再次证明普通代码能力不能直接迁移到底层 NPU 代码能力。第二SFT 带来了决定性的跃升。Qwen3-32B SFT 在 Level 2 上1. Pass1 编译率到 60.5%2. Pass10 编译率到 96.54%3. Pass10 执行率到 40.48%4. Pass100 执行率到 75%这说明领域数据和领域训练确实把模型从“几乎不会”拉到了“能做相当一部分复杂任务”。第三RL 的增益主要体现在执行正确性和性能而不是简单编译率。加入 RL 后Level 2 上 Pass10 执行率从 40.48% 提升到 64.28%速度提升从 1.50x 提升到 1.86x。这个变化很符合作者方法设计的逻辑因为 RL 更像是在细化已经基本可用的候选实现。第四Level 3 依然很难。即便在 SFTRL 后Level 3 还是处在“编译率有所提高但执行正确率接近没有真正突破”的状态。这一点非常重要因为它说明作者的方法不是“已经解决了 NPU kernel 生成”而是主要把 Level 1/2 打通了。所以如果客观评价 Table 71. 在中等复杂度任务上结果是很强的。2. 在真正最难的任务上离实用还有明显距离。Figure 4 画的是若干代表 kernel 在 base、SFT、SFTRL 三阶段下的 Pass1 表现。这张图的价值在于它说明模型提升不是只靠少数容易任务把平均分拉高而是在多个典型 kernel 上都有明显改善。作者给出的平均 Pass11. base7.92%2. SFT26.26%3. SFTRL33.46%从解释上看1. SFT 主要教会模型“正确的结构和接口”2. RL 则进一步帮助模型在多个“看起来都差不多像对了”的候选中偏向真正执行正确的版本。这张图还能帮你理解一个问题为什么 RL 没有像 SFT 那样带来数量级提升因为 RL 不是从零教模型写 AscendC而是在已有基础上做细修。它更像打磨而不是从无到有地立框架。Table 7 的 speedup 列值得单独说。base model 在 Level 1 上只有 0.60x意思是连专家基线的 60% 都达不到在 Level 2/3 基本没有有效性能结果。SFT 后 Level 2 达到 1.50xRL 后进一步到 1.86x。也就是说在部分中等复杂算子上模型生成的 kernel 已经不只是“能跑”而是可能比人工基线更快。这里有两种解读都要保留1. 正向解读说明模型确实学到了一些有效的 tiling、memory reuse、pipeline 组织方式。2. 保守解读这里比较的是“专家实现基线”但我们需要进一步知道这些基线有多强、是否充分优化、不同任务间方差多大。所以这个 1.86x 是有说服力的积极信号但还不能被简单解读成“模型全面超过专家”。Figure 5 说明随着模型规模增大Level 1 和 Level 2 的表现稳步提升而 Level 3 仍然难。这告诉我们两件事1. 更大的模型确实更能吸收这种专门知识。2. 但仅靠加参数解决不了最复杂 kernel 的结构推理问题。Table 8 则比较了 full fine-tuning 和 LoRA。结果很鲜明full tuning 在各层级都显著优于 LoRA尤其在复杂任务上差距更大。比如在 Qwen3-8B 上1. LoRA 的 Level 2 执行率只有 0.67%。2. Full tuning 的 Level 2 执行率是 3.08%。3. Full tuning 的 Level 2 speedup 还能到 2.77x而 LoRA 只有 0.52x。这个结论其实很合理。因为 NPU kernel 生成不是简单的“输出风格适配”而是要把很多硬件相关的深层知识写进模型。LoRA 这种低秩适配往往够做格式对齐不一定够做深层知识重塑。这也是这篇论文一个比较有价值的经验结论在这种 precision-critical、知识密集型代码任务上full tuning 可能比参数高效微调更必要。Figure 6a 比较了不同数据组成的影响。结论非常清楚1. 去掉 kernel code性能掉得最厉害。2. 去掉文档数据或通用数据也会变差但没有那么致命。这说明1. 文档能教规则2. 通用数据能保推理基础3. 但真正让模型学会写 kernel 的还是高质量真实 kernel 及其 reasoning。Figure 6b 又说明数据量增加会持续带来提升。这种结果通常意味着领域还没有被“喂饱”更多高质量数据大概率仍然有效。这也是这篇文章最有现实启发的一点之一在硬件代码生成里数据稀缺是头号瓶颈而不是单纯缺一个更花哨的训练技巧。Table 9 比较了不同 DPO 设置。最关键的发现是1. 用“编译通过但执行失败”的样本做负例比用“编译失败”的样本做负例更好。2. cosine 学习率衰减优于 constant。这个结果和方法论是统一的。因为编译失败太“初级”了负例信息密度不高而执行失败的样本更接近正确实现模型才能学到真正关键的差别。这张表虽然不是全篇最显眼的结果但它证明作者对 RL 训练并不是拍脑袋。作者统计了约 4000 个失败样本Figure 7 给出错误分布1. API 签名/重载错误占 51.9%2. 数据类型与类型转换错误占 19.8%3. 变量作用域和生命周期错误占 16.4%4. 内存与对象使用错误占 8.1%5. 纯语法和结构错误只是小头这个结论非常重要。它说明当前模型的主要问题已经不是“不会写 C 语法”而是不会处理硬件 DSL 中那些严格的语义契约。换句话说难点并不在表面文本生成而在1. API 合法性推理2. 类型规则3. host/device 跨边界变量一致性4. 内存对象语义。这个发现也反过来支持了作者的方法路线为什么要做文档 CoT、错误驱动监督、执行反馈学习因为真正的失败点就在这些语义约束上。