用AI Agent自动寻优CUDA kernel:从118名冲到第15名的完整实践

发布时间:2026/11/4 13:46:27

用AI Agent自动寻优CUDA kernel:从118名冲到第15名的完整实践 年初我在一个 GPU 算子性能榜单上刷着玩。榜单规则很直接给定一个核心算子每人提交一份 CUDA kernel按端到端吞吐量排名取最优成绩。我手动调这个算子已经有段时间了排名卡在 100 名开外怎么都上不去。后来发现同一个榜单上开始有人用 Agent 自动寻优的方式冲榜——他们不是调出来的 kernel而是让 Agent 在 24 小时窗口里自动改代码、自动验证、自动刷榜直接把成绩抬进了前二十。这彻底改变了我对自动调优的认知。这篇文章要拆解的就是我复刻这套玩法的一次完整经历一个 AI Agent 自动寻优闭环怎么从 baseline 一路改到 NVIDIA kernel 榜单第 15 名。核心覆盖三块Agent 怎么决定改哪一行代码、怎么验证改完对不对、怎么在时间压力下收敛出靠谱结果。适合正在做 CUDA kernel 优化、GPU 算子开发或者单纯对AI 驱动代码优化感兴趣的朋友参考。1. 这次调的是什么 kernelAgent 为什么能干这活1.1 榜单比的是个什么算子这个榜给定的是一个很常见的融合算子y relu(A * B bias)也就是矩阵乘后加偏置再走 ReLU。数据形状固定评测环境固定输入输出都用 fp32最终的浮点误差允许在 1e-4 量级以内。提交的 kernel 要在固定的 GPU 上跑按吞吐量从高到低排取每个人提交的最好成绩。这类算子我没少见工作的这些年里 CUDA 优化写过不少。但真要冲榜的时候问题就暴露出来了性能调优的搜索空间太大一个人手动试很难覆盖所有组合。矩阵乘这个算子哪怕只考虑最常用的套路也可能组合出上千种写法要不要用共享内存分块、分块尺寸选多大、循环展开几轮、向量宽度走 1 还是 4、block 尺寸设多少、load 和 compute 怎么重叠……这些维度彼此耦合改一个往往牵一发而动全身。手动调的时候我基本靠经验和直觉但直觉这东西换一个 GPU换一个形状可能就完全失效。1.2 手动调优的天花板恰好是 Agent 的起跑线手动调优遇到的另一个麻烦是反馈链路太长。每改一版得先编译、再跑正确性验证、再跑 benchmark有时还得到 profiling 工具里翻一遍访存、占用率、bank conflict 这些指标。整个流程下来至少三五分钟。一次 24 小时的冲榜窗口满打满算手动也就试几百个版本。但 Agent 干这事不一样。它不知道累也不会因为改坏了排名掉了一位就心态崩掉。给它一条自动化管线它可以在同样 24 小时里迭代几百甚至上千个候选版本而且每次改动的依据不是拍脑袋而是根据上一版跑出来的 profiling 数据做决策。手动调优和 Agent 寻优有个本质区别手动调优是在我认为正确的方向上做局部试探Agent 寻优是在数据指向的方向上做系统性搜索。前者依赖功力后者依赖反馈质量。这也是我这次最大的体会——Agent 能不能调出好 kernel很大程度上不是模型智商问题而是你有没有给它搭一套好用的反馈闭环。2. 搭一套能让 Agent 自己跑 24 小时的自动寻优管线2.1 核心循环生成、编译、验证、评分、决策在让 Agent 接手之前我花了不少时间搭管线。因为如果每一步都还需要人工参与那就谈不上 24 小时无人值守了。整个循环大概是这样的loop: 1. 根据历史记录Agent 从候选池中选一个代码变换 2. 渲染出新的 CUDA kernel 源码 3. nvcc 编译超时自动 kill 4. 编译失败 - 记录原因回到 1 5. 运行正确性检查数字误差 边界 case 6. 正确性不过 - 记录原因回到 1 7. 运行 benchmark采集 perf 和 profile 指标 8. 把结果打包成结构化反馈交给 Agent 9. 若性能提升 - 更新当前最优快照否则 - 回滚到上一个稳定版本这个环我跑下来发现最容易被忽略但最关键的其实不是 Agent 本身而是第 8 步——反馈信号的设计。2.2 给 Agent 的反馈一定要够结构化一开始我把 nvcc 的编译日志、Nsight Compute 的原始输出直接丢给 Agent。效果很差。原因很朴素这些工具的输出是给人看的一页里面 70% 是无关信息而且格式零散。LLM 虽然能读但读完之后很容易被噪声带偏——本来该关注访存瓶颈它却在纠结一个无关紧要的 warning。后来我把反馈统一成结构化 JSON只放真正有决策价值的字段。每次迭代喂给 Agent 的数据大概是这样的{ iteration: 127, action_taken: apply_vectorize(4), compile_status: ok, correctness: { max_abs_err: 1.2e-5, rel_err: 3.1e-6, passed: true }, perf: { avg_us: 152.4, throughput_tflops: 8.3 }, profile: { sm_occupancy_pct: 62, memory_throughput_pct: 91, sm_busy_pct: 47, shared_mem_bank_conflicts: 4, regs_per_thread: 42, max_dynamic_smem_bytes: 8192 }, best_so_far: { rank_est: 15, avg_us: 148.1 } }字段不在多但每个都要对 Agent 的决策有直接引导作用。比如shared_mem_bank_conflicts一高Agent 就该去尝试 paddingmemory_throughput_pct高但sm_busy_pct低说明卡在访存而不是计算regs_per_thread过高则意味着编译期寄存器溢出风险。这一步是这套系统里投入产出比最高的一处改进。反馈干净了Agent 的决策质量立刻上了一个台阶。2.3 动作空间不要让 Agent 自由写 kernel这里有一个我在设计之初差点犯的错误想让 Agent 直接从头生成一个完整的 CUDA kernel 源码。试了几次之后发现自由生成的问题很多——编译失败的代码修起来麻烦隐藏 bug 不容易暴露而且 Agent 经常用一个看起来很合理但跑起来很怪的写法浪费大量迭代轮次。正确的做法是给 Agent 定一个受限的动作空间。我预定义了 8 种常见的代码变换Agent 每次从中选一个动作执行动作说明apply_tiling(tile_size)调整共享内存分块尺寸apply_vectorize(vec_width)向量宽度 1/2/4 切换apply_register_block(m, n)寄存器分块配置调整apply_unroll(factor)循环展开因子change_block_config(x, y)block 形状调整apply_shared_memory_load()是否启用共享内存预加载avoid_bank_conflict(pad)对共享内存做 paddingrevert_last()回滚上一步这么做的好处是Agent 的每一次尝试都在可控的合法变换范围内编译通过率显著提升。坏处是它会受限于我预设的优化套路——不过说实话这只是把天花板设在了已知优化全集上而这个全集对于一个榜单排名已经足够了。2.4 防挂机制让无人值守不变成无人收尸24 小时自动跑如果不设防护很可能早上起来看到的是一个挂了 12 小时的 Agent。我加了几个硬性限制。第一编译设置超时120 秒跑不完直接杀掉避免 nvcc 在一些极端展开组合下卡死。第二benchmark 每条候选跑 3 次取中位数防止偶然波动触发错误决策。第三只有性能相比当前最优提升超过 0.5% 才接受新版本否则一律回滚避免假优化叠加。第四每个版本的源码、编译日志、评测结果全部落盘方便事后复盘 Agent 的决策链路。另外我定义了一个总的迭代预算24 小时内最多跑 600 次有效迭代。超过预算即使没到 24 小时也停止。因为 Agent 在最后阶段如果还在大跨度搜索很可能把好不容易冲上去的成绩又调坏。3. 真正让 Agent 改出来的四个关键优化点3.1 访存合并与向量化加载baseline 版本朴素得不能再朴素每个线程直接读A的一行、B的一列算内积累加。这种写法的典型问题就是访存完全不合并——同一 warp 里的相邻线程读到的地址跨度很大每笔内存事务的利用率低到吓人。Agent 做的第一次有效改动是向量化加载把连续的float4读入而不是逐元素读。这一改效果立竿见影memory throughput 从 40% 出头上到了 70% 左右。原理很简单float4一次加载 16 字节相同的内存事务数量可以搬运四倍的数据对 memory-bound 的算子来说等于直接把访存带宽利用率拉高。不过这里要提个醒向量化不是无脑加。float4要求内存地址 16 字节对齐。我的 baseline 代码里矩阵按行存储如果某一行起始地址没对齐到 16 字节边界编译出来的代码会落到慢速路径。Agent 在后来的迭代里也踩过一次这个坑是在它尝试对bias向量做向量化时踩到的——bias的地址连续但长度不一定能被 4 整除。最终的处理是加了一层对齐 padding。3.2 共享内存分块与 bank 冲突消解向量化之后瓶颈逐渐从访存转移到内存事务的重复上。因为每个线程都在自己读整行数据同一个 A 块会被相邻线程重复读取多次。Agent 从 profiling 数据里看到 memory throughput 已经拉满但 SM busy 很低于是判断需要做共享内存 tile 化。做法是典型的 tiling把计算拆成子块每个 block 先从全局内存协作加载一个TILE_M x TILE_K的块到共享内存然后从共享内存里反复读。这一步相当于把板子上的访存次数从每人读一遍全行降到了每人读一遍自己负责的块。共享内存引入之后Agent 没多久就触发了一个新问题bank conflict。当时 profiling 报告shared_mem_bank_conflicts: 32每次共享内存访问都打满冲突。Agent 选择的修复方案是加 padding——把每行共享内存从TILE_K扩展到TILE_K 1。代价极小bank 冲突直接降到了 0。这里我想强调一个经验bank conflict 对人来说很容易看不到。你读代码看不出问题跑结果也看不出问题只有 profiling 才能暴露。Agent 的优势在于它每次都看 profile不会像我一样调了三版才想起去查 bank conflict。3.3 寄存器分块和循环展开的平衡共享内存 tiling 做完之后排名从 50 名开外进到了 30 名左右。再往后因为计算强度不够SM 的算术单元利用率上不去。Agent 又做了一个动作寄存器分块register blocking让每个线程一次计算一个REG_M x REG_N的小矩阵块把数据在寄存器里复用多次而不是每个输出元素都去重新读一遍。寄存器分块是个双刃剑。块太大寄存器用量飙升可能导致 occupancy 下降块太小复用率不够计算强度上不去。Agent 测试了(2,2)、(4,4)、(4,8)、(8,8)几组配置最终落在(4,8)上寄存器数每线程 56 个occupancy 还能保住 50% 以上。同样的拉锯发生在循环展开上。展开因子从 1 调到 4 时 ILP指令级并行提升明显再往上就是反效果——代码体膨胀导致 I-Cache 命中率下降编译时间也拉长。Agent 后来自己收敛到了展开 4 分块 (4,8)的组合效果最好。3.4 Block 与 Grid 形状的显式搜索最后一段性能来自看起来不起眼的参数调整。Agent 在最末尾阶段开始大量尝试change_block_config在(32,4)、(64,2)、(128,1)、(16,8)这些形状之间来回切换。这个动作一开始我不太理解感觉就是在玄学调参。后来看数据才明白block 形状会同时影响访存合并模式、共享内存分配方式和硬件调度粒度。在(32,4)到(64,2)的切换中吞吐量涨了约 3%可能来自访存模式的逐渐合并而到了(128,1)又因为每个 block 太大了调度灵活性下降性能反而回落。这种多维数值搜索正是 Agent 擅长的领域。它的决策逻辑是记下每组的数值结果做一个小范围的贝叶斯式试探逐步接近局部最优。我手动调参时每次只改一个维度Agent 却能同时维护多组配置的历史对比。4. 从 118 名到 15 名24 小时的复盘4.1 前两个小时被基建吃掉的时间理想中的 24 小时应该是 Agent 从第一分钟就开始疯狂迭代。实际上前两个小时全部浪费在管线和环境调试上。不是 Agent 不行是我自己的 pipeline 第一次跑就有 bug正确性检查用了统一误差阈值结果relu之后接近 0 的位置误差占比过大导致好几个实际上有效的候选版本被误杀Agent 被迫反复尝试同一条路。这个问题修完之后还有第二个基准 benchmark 的 GPU 抢占机制。我机器上开了网页等杂七杂八的东西跑分抖动很大Agent 被噪声误导过两次。最后把进程优先级调高、关掉桌面特效噪声才降下去。这两小时的教训是自动寻优管线的稳定性优先级高于 Agent 的聪明程度。4.2 第 2 到第 8 小时Agent 快速吃到底基础修好后Agent 的推进速度非常快。向量化、共享内存 tiling、bank conflict padding这三个动作几乎是一气呵成。每次迭代大约两分钟三个小时里跑了近 90 次有效迭代。排名从 118 跳到 52。这个阶段让我第一次真切感受到自动寻优的含义——Agent 选定一个方向后不会因为已经试过类似方案而犹豫它只是单纯地按 profile 数据往上堆。4.3 第 8 到第 16 小时停滞期与一次必要的人工干预52 名之后Agent 陷入了一段将近四个小时的原地打转。它的动作开始变得琐碎反复在apply_unroll(2)和apply_unroll(4)之间横跳每次只有 0.1% 到 0.3% 的波动。我当时做了一次人工干预现在看是全程最正确的一个决定把 register blocking 动作加进了候选池。Agent 之前没有主动权因为它的动作空间里根本没有这一项而它自己也很难凭空想到寄存器分块这种需要经验才能沉淀出来的变换。加入之后第一版 (4,4) 就带来了 4% 的提升直接把排名推到 27。这个细节我想多说一句LLM 虽然能读代码、能理解矩阵乘但它不会天然知道这个形状在这个架构下应该用寄存器分块。这类经验必须通过动作空间注入系统。所谓 Agent 自动寻优其实是人的经验 机器执行力的结合不是完全放手。4.4 第 16 到第 24 小时收敛与冲榜后半夜 Agent 的动作收敛下来基本都是 block config 微调和循环展开因子的小步试探。排名在 20 名上下浮动最好的几次是在(64,2)的 block 形状下跑出来的。最终成绩锁定在榜单第 15 名端到端吞吐量相比 baseline 提升了大概 4.8 倍。我也把整个晋级过程简单记录了一下时间段关键动作排名变化0-2h管线稳定、解决评测噪声1182-8h向量化、共享内存、bank 冲突118 - 528-16h停滞、人工注入寄存器分块动作52 - 2716-24hblock 形状搜索、循环展开收敛27 - 155. Agent 自动寻优期间的真实翻车现场5.1 共享内存直接爆掉Agent 有一次想把 tile 尺寸从 16 调到 32同时又把好几个中间结果全部放进共享内存结果动态共享内存直接超了上限编译报错。编译失败本身不吓人吓人的是 Agent 在下一轮居然把 tile 调到了 64——仿佛根本没记住上一个错误。后来我查日志才发现原因编译失败时反馈 JSON 里的compile_status字段是no但错误详情我塞在了一个长字符串里。Agent 看到了no却没理解具体为什么。修复方式很简单把max_smem_limit直接作为数值放进 JSON让 Agent 一眼看到还有多少字节可用。这又是一个反馈设计影响决策质量的例子。5.2 浮点误差涨了一个量级做revert决策时我发现 Agent 在某个版本上跑出来的性能非常高但正确性检查差点没通过。原因是 FMA 融合和计算重排导致误差扩大。我的误差阈值是 1e-4那个版本在部分数据点上误差到了 8e-5虽然还在阈值内但已经让我警惕了。处理方式是对浮点敏感的操作做了约束矩阵乘中间累加用double累加器不行性能要崩折中的方案是不允许 Agent 对累加顺序做激进重组同时把误差阈值从 1e-4 收紧到 5e-5。这样能筛掉那些靠数值冒险换性能的版本。5.3 假优化性能好只是噪声朝你笑了五秒钟有一种翻车不是报错而是波动。Agent 有几次接受的版本在下一次验证时性能反而跌了 5%。原因是我最初只跑一次 benchmark 就做决定某个版本赶上了 GPU 频率放宽或者后台负载低谷给出了虚高成绩。修这个的办法上面提过——每个版本跑 3 次取中位数。代价是迭代速度慢了三分之一但换来的是决策质量的提升。自动寻优本质是个决策问题喂给决策器的数据必须稳定宁可慢不能虚。5.4 Agent 在一个小坑里反复跳最后一种翻车模式是鬼打墙。Agent 在某次尝试里把 block 尺寸从(32,4)换到(64,1)性能下降 2%回滚下一轮又试(32,8)又下降又回滚然后又试回(64,1)。看日志我很崩溃但它其实是在按照自己的策略网格扫描。这个问题的解决不是禁止它扫而是给它的动作空间加入一个简单启发式凡是 block 形状的变更如果没有带来提升就把相近形状标记为已探索。虽然还是笨但至少不会无限循环试同一个点。6. 关于Agent 调 kernel这套路我最后的体会6.1 经验沉淀成动作空间才是核心资产这次跑完我最大的感受是Agent 自动寻优的上限不由模型决定由动作空间决定。它不会发明 register blocking也不会无中生有想到 padding 消解 bank conflict它把动作空间里已有的变换执行到极致。所以如果你也想用 Agent 调自己的算子最值得花的功夫不是调 prompt而是把你知道的所有优化套路整理成清晰、可组合、可验证的动作集。每一个动作背后都是一个人踩过的坑和攒出来的经验。6.2 反馈结构的质量 决策质量的地板如果要给这套系统里所有要素排序我的选择是反馈结构 动作空间 Agent 模型能力。结构化 JSON、误差阈值处理、benchmark 噪声控制这些不起眼的工程细节每一个都比换个更强的模型带来的提升大。很多失败的 Agent 项目不是模型不够聪明而是喂给模型的眼睛看不见关键信息。6.3 这类玩法真正的适用边界不是所有场景都适合搭这一套。这次能成前提是单次编译加评测只要两三分钟、优化目标清晰、性能信号稳定。如果一个算子跑一次就要十分钟或者正确性验证本身就模棱两可那 Agent 自动寻优的效率会大打折扣。但反过来只要这几条基本满足人在环外的自动优化就是值得投入的方向。我自己现在的习惯是新接触一个算子先手动调出一个能跑通的中等版本再把其余搜索空间交给 Agent 扫。人负责搭骨架Agent 负责填肌肉。这个分工方式至少在这次冲榜里被证明是有效的。
延伸阅读

更多相关文章

2026/11/4 13:41:22

Ubuntu系统下OpenClaw安装配置全攻略

1. 项目概述 最近在Ubuntu系统上折腾OpenClaw时,发现虽然官方文档很全面,但实际操作中还是会遇到不少坑。作为一款开源的网络安全工具,OpenClaw在渗透测试和漏洞扫描领域有着广泛的应用,但它的安装配置过程对新手来说并不友好。这…

2026/11/4 13:41:22

大模型时代产品经理的核心技能与转型路径

1. 大模型时代的产品经理角色重塑 2026年的产品经理岗位正在经历一场前所未有的范式转移。当我在2023年第一次接触GPT-4时,就意识到这个领域将发生根本性变革。三年后的今天,大模型不仅改变了产品形态,更重新定义了产品经理的能力模型。 传统…

2026/11/4 13:41:22

DeepSeek 实战:API调用、本地部署与生产避坑

简介:《DeepSeek从入门到精通》由清华大学新闻与传播学院新媒体研究中心元宇宙文化实验室团队编写,面向希望系统了解并上手DeepSeek的开发者、内容创作者与AI学习者,重点解决模型认知、任务匹配和提示语设计等问题。压缩包内为1个PDF文件&…

2026/11/4 14:32:17

Jev:一场针对AI话痨的数字静默行为艺术

1. “Jev”不是新模型,是网友集体创作的“哑巴式AI行为艺术” 最近刷到好几条短视频,标题都写着“Jev是什么?哑巴模型居然全网爆火”,点进去一看,画面里是个黑底白字的极简界面,输入框旁写着“请说话”&…

2026/11/4 14:32:17

Jev现象解密:AI语音‘哑巴模型’的声学缺陷与拟人化边界

1. 项目概述:当“Jev”成为全网热词,我们到底在讨论什么?最近刷短视频、逛论坛、看弹幕,你大概率已经撞见过这个词——Jev。它不是新出的美妆品牌,不是某款游戏的隐藏BOSS,更不是某个小众乐队的缩写。它是一…

2026/11/4 14:32:17

自考论文写作工具横评:10款工具实测对比与优化建议

1. 论文写作工具横评背景与价值 最近指导几位自考学生完成毕业论文时,发现他们普遍面临三个核心痛点:文献检索效率低、论文格式混乱、写作时间严重不足。这促使我系统测试了市面上主流的10款论文辅助工具,实测发现优质工具能帮助自考考生节省…

2026/11/4 14:32:17

BUUCTF PWN题解:栈溢出与格式化字符串漏洞实战

1. 解题思路与工具准备最近在BUUCTF平台上刷了几道PWN题(46-50题),发现这几道题虽然难度不算太高,但涉及的知识点比较全面。作为二进制安全方向的练习者,我觉得有必要把解题过程记录下来,既是对自己思路的梳…

2026/11/4 14:32:17

React渲染模式演进与性能优化实战

1. React渲染模式的演进背景2013年React的横空出世,彻底改变了前端开发的范式。最初作为Facebook内部解决动态数据更新问题的解决方案,React凭借虚拟DOM和组件化思想迅速成为构建单页应用(SPA)的首选框架。但传统SPA存在三个致命短板:首屏性能…

2026/11/4 14:27:16

Tomcat 404错误排查与解决方案大全

1. Tomcat报404问题概述 作为一名Java后端开发工程师,我经常遇到新手同事在启动Tomcat时遇到404错误的问题。Tomcat作为最流行的Java Web应用服务器之一,其404错误可能由多种原因导致,有些情况甚至Tomcat本身运行正常(控制台无报错…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/4 0:03:20

AI辅助技术栈评估:提升研发决策效率60%

1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年…

2026/11/4 0:03:20

从生成Token到直接决策:Jev如何重塑AI Agent工程实践

1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你…

2026/11/4 0:03:20

32G统一内存跑大模型:内存账、TPS实测与端云分流

想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑