ByteDance Seed and Tsinghua AIR Introduces CUDA Agent: A Large-Scale Agentic RL System for CUDA Kernel Generation
ByteDance Seed and Tsinghua AIR have released CUDA Agent, an agentic reinforcement learning system that trains a large language model to write GPU kernels that beat a compiler. The gap it targets is narrow but stubborn: frontier models already produce correct CUDA, they just produce slow CUDA. On KernelBench, the base model Seed1.6 passes 74.0% of tasks yet outruns torch.compile on only 27.2% of them, at a 0.69× geometric-mean speedup which means its kernels are, on average, slower than what the compiler generates on its own. CUDA Agent closes that gap by putting the model inside a real CUDA development environment with profiling, correctness checks and a permission-locked sandbox, then training it with PPO for 150 steps at a 131,072-token context. The result is a 98.8% pass rate and a 96.8% faster-than-torch.compile rate across the 250-task benchmark, at 2.11× geomean over compile — roughly 40 points ahead of Claude Opus 4.5 and Gemini 3 Pro on the hardest Level-3 split.
Is it deployable?
Partly, but the trained agent is not released. It is built on Seed1.6, a proprietary MoE model with 23B active and 230B total parameters, and the paper ships no weights. Public: the CUDA-Agent-Ops-6K dataset, the SKILL.md spec and the reward and warm-up recipes.
Which companies: The profiling sandbox alone used 128 NVIDIA H20 GPUs, which puts full replication inside frontier labs, GPU clouds and large infrastructure teams. Mid-size teams can still adopt the parts — dataset, milestone reward, anti-reward-hacking constraints, skill spec — on top of an open base model.
Industries and applications: AI infrastructure and inference serving, GPU cloud, autonomous driving, quantitative trading, medical imaging and recommendation systems — anywhere fused kernels sit on a latency-critical path. Uses include fusing operator sequences torch.compile handles poorly, cutting cost per token, and re-tuning kernels across GPU generations.
Data synthesis
The research team crawls reference operators from the torch and transformers libraries. An LLM then samples up to five torch operator classes and stacks them into one fused layer. A filter keeps only operators that execute in both eager and compile modes, are deterministic, produce non-constant outputs, and run between 1 ms and 100 ms in eager mode. Samples with AST similarity above 0.9 to any KernelBench task are removed. The result is CUDA-Agent-Ops-6K: 6,000 samples, 83.77% of them two-operator compositions.
Environment and reward
The agent loop mirrors OpenHands tooling — Bash, Read/Write, Edit/MultiEdit, Glob, Grep, NotebookEdit, BashOutput, KillBash — under a ReAct pattern. CUDA instructions ship in the Agent Skills format. SKILL.md tells the model to profile the PyTorch model, rewrite model_new.py with custom kernels, compile in a GPU sandbox, and iterate until the kernel is at least 5% faster than torch.compile at atol=1e-2, rtol=1e-2.
Reward hacking gets five countermeasures: permission-locked verification and profiling scripts, context managers that forbid torch.nn.functional fallbacks, checks against five random inputs, profiling with device synchronization and warm-up, and no web search tool.
The reward is discrete rather than a raw speedup ratio. r ∈ {−1, 1, 2, 3}: −1 on correctness failure, 3 if the kernel clears both eager and torch.compile by more than 5%, 2 if it clears eager only, 1 otherwise.
Results
Table 1, overall: 98.8% pass rate, 98.4% faster than eager, 96.8% faster than torch.compile, at 2.60× and 2.11× geomean respectively. Level 2 (operator sequences) is the strongest split: 100% pass, 100% faster rate, 2.80× over torch.compile. Level 3 lands at 94.0% pass, 90.0% faster rate and 1.52×, roughly 40 points above Claude Opus 4.5 (50.0%) and Gemini 3 Pro (52.0%) on faster rate versus compile.
One inconsistency: the abstract and introduction state 100% / 100% / 92% faster rates for Levels 1–3, while Table 1 reports 97.0% / 100.0% / 90.0%. Table 1 is the main results table.
Ablations are blunt. Removing the agent loop drops faster rate versus compile from 96.8% to 14.1%. A raw speedup reward gives 60.4%, no RFT gives 49.8% plus reward collapse, no value pretraining gives 50.9% plus runaway trajectories.
Case studies show what the policy learns. A diagonal matmul rewritten as row-wise scaling: 73.31× over torch.compile. A matmul-divide-sum-scale chain reordered and fused: 24.04×. A ResNet BasicBlock with BatchNorm folded into convolution andcudnnConvolutionBiasActivationForward: 3.59×.
Play loop</button><button class="btn ghost" id="l-stop">Pause</button></div>
<div class="loop">
<div class="node" id="n0"><div class="ic">
</div><div class="nm">SKILL.md</div><div class="sub">Profile → write kernel → compile → iterate</div></div>
<div class="node" id="n1"><div class="ic">
</div><div class="nm">CUDA Agent</div><div class="sub">Bash, Read/Write, Edit/MultiEdit, Glob, Grep</div></div>
<div class="node" id="n2"><div class="ic">
</div><div class="nm">CPU sandbox</div><div class="sub">Docker compile of .cu + binding.cpp</div></div>
<div class="node" id="n3"><div class="ic">
</div><div class="nm">GPU pool</div><div class="sub">Correctness + profiling on 128 H20</div></div>
</div>
<div class="gauge">
<div class="g"><div class="k">Turn</div><div class="v" id="g-turn">0</div></div>
<div class="g"><div class="k">Torch eager</div><div class="v warn" id="g-eager">2.30 ms</div></div>
<div class="g"><div class="k">torch.compile</div><div class="v warn" id="g-comp">1.80 ms</div></div>
<div class="g"><div class="k">Generated</div><div class="v good" id="g-gen">— ms</div></div>
</div>
<div class="note">Illustrative: the turn-by-turn descent of the generated kernel time is a simulation of the loop. The three end-state timings (2.30 ms eager, 1.80 ms compile, 1.26 ms generated) are the exact values shown in Figure 2 of the paper.</div>
<div class="ref">Anti-reward-hacking: verification and profiling scripts are permission-locked, context managers forbid <span class="mono">torch.nn.functional</span> fallbacks, outputs are checked against five random inputs, profiling uses device sync plus warm-up and repeats, and the agent gets no web search tool.</div>
</section>
<!-- 03 -->
<section class="mod" id="m3">
<h3>Why the reward is discrete, not a speedup ratio</h3>
<p class="lede">Raw speedup rewards bias the policy toward easy kernels and blow up on outliers. CUDA Agent uses milestones instead. Move the slider to set your kernel's runtime and watch the reward flip.</p>
<div class="ctrl">
<label>Generated kernel runtime <span class="mono" id="rt-lab">1.26 ms</span></label>
<input type="range" id="rt" min="20" max="320" step="1" value="126">
</div>
<div class="row"><button class="btn ghost" id="ok-tog">Correctness check: <b id="ok-lab">PASS</b></button></div>
<div class="bars3" id="bars3"></div>
<div class="verdict" id="verdict">
<div class="r" id="v-r">3</div>
<div class="why" id="v-why"></div>
</div>
<div class="ref">Exact rule from Equation 1: r = −1 if correctness fails; 3 if faster than both eager and <span class="mono">torch.compile</span>; 2 if faster than eager only; otherwise 1. "Faster" means b(t, t₀) = 𝟙[(t₀ − t)/t₀ > 5%]. Baselines fixed at the Figure 2 values.</div>
</section>
<!-- 04 -->
<section class="mod" id="m4">
<h3>KernelBench results, Table 1</h3>
<p class="lede">250 tasks across three levels, weighted 100 / 100 / 50. Switch the split and the metric — the bars redraw with the paper's reported numbers.</p>
<div class="selrow">
<div class="seg" id="lvl">
<button data-k="ov" class="on">Overall</button><button data-k="l1">Level 1</button><button data-k="l2">Level 2</button><button data-k="l3">Level 3</button>
</div>
<div class="seg" id="met">
<button data-k="pass">Pass rate</button><button data-k="fe">Faster vs eager</button><button data-k="fc" class="on">Faster vs compile</button><button data-k="se">Speed-up vs eager</button><button data-k="sc">Speed-up vs compile</button>
</div>
</div>
<div id="chart"></div>
<div class="ref" id="chart-note"></div>
<div class="note">The abstract and introduction state 100% / 100% / 92% faster rates over <span class="mono">torch.compile</span> for Level 1 / 2 / 3, while Table 1 reports 97.0% / 100.0% / 90.0%. This widget uses Table 1, the paper's main results table.</div>
</section>
<!-- 05 -->
<section class="mod" id="m5">
<h3>What breaks when you remove a piece</h3>
<p class="lede">Leave-one-out variants, overall split, faster rate versus <span class="mono">torch.compile</span>. The agent loop matters most; the two warm-up stages keep training from collapsing.</p>
<div id="abl"></div>
<div class="row" style="margin-top:14px"><button class="btn" id="st-run">
Replay training curve</button></div>
<svg class="spark" id="spark" viewBox="0 0 600 150" preserveAspectRatio="none"></svg>
<div class="legend"><span><i style="background:#4D9BFF"></i>PPO with RFT + value pretraining</span><span><i style="background:#f5a623"></i>PPO without warm-up</span></div>
<div class="note">Schematic redraw of Figure 4a, illustrative. The paper's stated facts: the first RL trial stayed stable for 17 steps before collapse; with actor RFT and critic value pretraining, training ran 150 steps with consistent reward growth.</div>
<div class="ref">Root cause given in the paper: CUDA code is under 0.01% of pretraining data, so sampled low-probability tokens make the PPO importance ratio fluctuate or explode under train/inference precision mismatch.</div>
</section>
<div class="foot">
<span>Source: Dai, Wu, Yu et al., arXiv 2602.24286 · ByteDance Seed × Tsinghua AIR</span>
<span><b>Marktechpost</b> · interactive explainer</span>
</div>
</div>
<script>
(function(){
var $=function(s){return document.querySelector(s)};
var $$=function(s){return Array.prototype.slice.call(document.querySelectorAll(s))};
/* ---- resize ---- */
var wrap=document.getElementById('ca-wrap');
var lastH=0;
function ping(){
var h=wrap.offsetHeight+40;
if(h===lastH)return; lastH=h;
try{ parent.postMessage({type:'mtpEmbedHeight',id:'cuda-agent-explainer',height:h},'*'); }catch(e){}
}
setInterval(ping,600); window.addEventListener('load',ping); ping();
/* ---- nav ---- */
$$('nav.ca-nav button').forEach(function(b){
b.addEventListener('click',function(){
$$('nav.ca-nav button').forEach(function(x){x.classList.remove('active')});
$$('section.mod').forEach(function(x){x.classList.remove('show')});
b.classList.add('active');
var m=b.getAttribute('data-m');
document.getElementById(m).classList.add('show');
if(m==='m5'){ setTimeout(drawSpark,30); }
ping();
});
});
/* ---- 01 pipeline ---- */
var comp=[['torch ops ×2',83.77],['torch ops ×3',7.62],['torch ops ×1',3.40],
['torch ops ×4',2.80],['torch ops ×5',1.23],['transformers',1.18]];
var compHTML='';
comp.forEach(function(c,i){
compHTML+='<div class="cb"><div class="lab">'+c[0]+'</div><div class="track"><div class="fill" data-w="'+
(c[1]/83.77*100)+'"></div></div><div class="val">'+c[1].toFixed(2)+'%</div></div>';
});
$('#comp').innerHTML=compHTML;
function tick(el,to,ms,suffix){
var t0=null;
function step(ts){ if(!t0)t0=ts; var p=Math.min((ts-t0)/ms,1);
el.textContent=Math.round(to*(1-Math.pow(1-p,3))).toLocaleString()+(suffix||'');
if(p<1)requestAnimationFrame(step); }
requestAnimationFrame(step);
}
function runPipe(){
resetPipe();
setTimeout(function(){$('#s1').classList.add('lit'); $('#c1').textContent='torch + transformers';},80);
setTimeout(function(){$('#s2').classList.add('lit'); $('#c2').textContent='\u2264 5 ops / task';},1100);
setTimeout(function(){$('#s3').classList.add('lit'); tick($('#c3'),6000,1000,' samples kept');},2200);
setTimeout(function(){$$('#comp .fill').forEach(function(f,i){
setTimeout(function(){f.style.width=f.getAttribute('data-w')+'%'},i*110)});},2900);
}
function resetPipe(){
['s1','s2','s3'].forEach(function(id){$('#'+id).classList.remove('lit')});
['c1','c2','c3'].forEach(function(id){$('#'+id).textContent='—'});
$$('#comp .fill').forEach(function(f){f.style.width='0%'});
}
$('#p-run').addEventListener('click',runPipe);
$('#p-reset').addEventListener('click',resetPipe);
/* ---- 02 agent loop ---- */
var lt=null, li=0, turn=0, gen=2.90;
function loopStep(){
['n0','n1','n2','n3'].forEach(function(id){$('#'+id).classList.remove('act')});
$('#n'+(li%4)).classList.add('act');
if(li%4===3){
turn++; gen=Math.max(1.26, gen-(gen-1.26)*0.42);
$('#g-turn').textContent=turn;
$('#g-gen').textContent=gen.toFixed(2)+' ms';
$('#g-gen').className='v '+(gen<1.71?'good':'warn');
}
li++;
}
function loopStart(){ if(lt)return; loopStep(); lt=setInterval(loopStep,460); }
function loopStop(){ clearInterval(lt); lt=null; }
$('#l-run').addEventListener('click',function(){ if(turn>=6){turn=0;gen=2.90;} loopStart(); });
$('#l-stop').addEventListener('click',loopStop);
/* ---- 03 reward ---- */
var EAGER=2.30, COMP=1.80, ok=true;
function b(t,t0){ return (t0-t)/t0 > 0.05; }
function drawReward(){
var t=parseInt($('#rt').value,10)/100;
$('#rt-lab').textContent=t.toFixed(2)+' ms';
var max=3.4;
var rows=[['torch eager',EAGER,'#f5a623'],['torch.compile',COMP,'#4D9BFF'],['your kernel',t,'#5BE1F5']];
var h='';
rows.forEach(function(r){
h+='<div class="b3"><div class="lab">'+r[0]+'</div><div class="track"><div class="fill" style="width:'+
(r[1]/max*100)+'%;background:linear-gradient(90deg,'+r[2]+'55,'+r[2]+')"></div></div><div class="val">'+
r[1].toFixed(2)+' ms</div></div>';
});
$('#bars3').innerHTML=h;
var be=b(t,EAGER), bc=b(t,COMP), r, why, col;
if(!ok){ r=-1; why='Correctness check failed. Runtime is irrelevant — the trajectory is penalised.'; col='#f5a623'; }
else if(be&&bc){ r=3; why='More than 5% faster than eager AND than torch.compile. Top milestone.'; col='#3ddc97'; }
else if(be){ r=2; why='More than 5% faster than eager, but not than torch.compile.'; col='#5BE1F5'; }
else { r=1; why='Correct, but no significant speed-up over either baseline.'; col='#8fa3c0'; }
$('#v-r').textContent=(r>0?'+':'')+r; $('#v-r').style.color=col;
$('#v-why').textContent=why;
$('#verdict').style.borderColor=col;
}
$('#rt').addEventListener('input',drawReward);
$('#ok-tog').addEventListener('click',function(){
ok=!ok; $('#ok-lab').textContent=ok?'PASS':'FAIL'; drawReward();
});
drawReward();
/* ---- 04 chart (Table 1) ---- */
var MODELS=['Seed1.6 (base)','GLM 4.6','Kimi K2','Gemini 3 Pro','Claude Opus 4.5','CUDA Agent'];
var D={
ov:{pass:[74.0,75.6,66.8,91.2,95.2,98.8],fe:[43.6,44.8,40.8,87.6,90.4,98.4],
fc:[27.2,19.2,22.8,69.6,66.4,96.8],se:[0.95,0.78,0.93,1.92,1.99,2.60],
sc:[0.69,0.57,0.66,1.42,1.46,2.11]},
l1:{pass:[90.0,86.0,85.0,95.0,96.0,100.0],fe:[63.0,57.0,56.0,90.0,88.0,99.0],
fc:[51.0,32.0,39.0,72.0,72.0,97.0],se:[1.65,0.99,1.43,1.99,2.03,2.48],
sc:[1.25,0.73,1.00,1.51,1.54,1.87]},
l2:{pass:[74.0,76.0,65.0,93.0,98.0,100.0],fe:[40.0,43.0,40.0,91.0,97.0,100.0],
fc:[16.0,11.0,15.0,76.0,69.0,100.0],se:[0.68,0.60,0.93,2.03,2.24,3.27],
sc:[0.50,0.42,0.65,1.46,1.60,2.80]},
l3:{pass:[42.0,54.0,34.0,80.0,88.0,94.0],fe:[12.0,24.0,12.0,76.0,82.0,94.0],
fc:[2.0,10.0,6.0,52.0,50.0,90.0],se:[0.60,0.83,0.40,1.58,1.52,1.80],
sc:[0.40,0.62,0.29,1.17,1.10,1.52]}
};
var NOTES={ov:'Overall = weighted by problems per level (Level 1: 100, Level 2: 100, Level 3: 50).',
l1:'Level 1 = single operations.', l2:'Level 2 = operator sequences, where fusion matters most.',
l3:'Level 3 = realistic neural-network blocks, the hardest split.'};
var lvl='ov', met='fc';
function drawChart(){
var vals=D[lvl][met], pct=(met==='se'||met==='sc')?false:true;
var max=Math.max.apply(null,vals)*1.06;
var h='';
MODELS.forEach(function(m,i){
var v=vals[i];
h+='<div class="brow'+(i===5?' ours':'')+'"><div class="lab">'+m+'</div><div class="track"><div class="fill" data-w="'+
(v/max*100)+'"></div></div><div class="val">'+(pct?v.toFixed(1)+'%':v.toFixed(2)+'×')+'</div></div>';
});
$('#chart').innerHTML=h;
$('#chart-note').textContent=NOTES[lvl]+' All figures from Table 1 of the paper.';
setTimeout(function(){$$('#chart .fill').forEach(function(f,i){
setTimeout(function(){f.style.width=f.getAttribute('data-w')+'%'},i*70)})},30);
}
$$('#lvl button').forEach(function(b2){b2.addEventListener('click',function(){
$$('#lvl button').forEach(function(x){x.classList.remove('on')});b2.classList.add('on');
lvl=b2.getAttribute('data-k');drawChart();})});
$$('#met button').forEach(function(b2){b2.addEventListener('click',function(){
$$('#met button').forEach(function(x){x.classList.remove('on')});b2.classList.add('on');
met=b2.getAttribute('data-k');drawChart();})});
drawChart();
/* ---- 05 ablation ---- */
var ABL=[['w/o Agent Loop',14.1],['w/o Robust Reward',60.4],['w/o RFT',49.8],
['w/o Value Pretraining',50.9],['CUDA Agent (full)',96.8]];
var ah='';
ABL.forEach(function(a,i){
ah+='<div class="brow'+(i===4?' ours':'')+'"><div class="lab">'+a[0]+
'</div><div class="track"><div class="fill" data-w="'+a[1]+'"></div></div><div class="val">'+
a[1].toFixed(1)+'%</div></div>';
});
$('#abl').innerHTML=ah;
setTimeout(function(){$$('#abl .fill').forEach(function(f,i){
setTimeout(function(){f.style.width=f.getAttribute('data-w')+'%'},i*90)})},250);
/* ---- 05 spark ---- */
var good=[0.35,0.62,0.95,1.10,1.02,1.28,1.20,1.44,1.35,1.52,1.41,1.63,1.55,1.72,1.66,1.80,1.74,1.88,1.82,1.95];
var bad =[0.32,0.58,0.88,1.05,1.18,1.30,1.22,1.05,0.86,0.62,0.40,0.22,0.12,0.06,0.03,0.02,0.02,0.01,0.01,0.01];
function pts(a){ return a.map(function(v,i){
return (30+i*(555/(a.length-1))).toFixed(1)+','+(130-v/2.1*112).toFixed(1); }).join(' '); }
function drawSpark(){
var s=$('#spark');
s.innerHTML='<line x1="30" y1="130" x2="588" y2="130" stroke="#1c2942" stroke-width="1"/>'+
'<line x1="30" y1="18" x2="30" y2="130" stroke="#1c2942" stroke-width="1"/>'+
'<line x1="200" y1="18" x2="200" y2="130" stroke="#f5a62355" stroke-width="1" stroke-dasharray="4 4"/>'+
'<text x="205" y="30" fill="#8fa3c0" font-size="10" font-family="monospace">step 17: collapse</text>'+
'<text x="4" y="24" fill="#8fa3c0" font-size="9" font-family="monospace">reward</text>'+
'<polyline id="pl-bad" points="'+pts(bad)+'" fill="none" stroke="#f5a623" stroke-width="2"/>'+
'<polyline id="pl-good" points="'+pts(good)+'" fill="none" stroke="#4D9BFF" stroke-width="2"/>';
['pl-bad','pl-good'].forEach(function(id){
var p=document.getElementById(id), L=0;
try{ L=p.getTotalLength(); }catch(e){ return; }
if(!L) return;
p.style.strokeDasharray=L; p.style.strokeDashoffset=L;
p.style.transition='stroke-dashoffset 1.8s ease';
setTimeout(function(){p.style.strokeDashoffset=0},60);
});
}
$('#st-run').addEventListener('click',drawSpark);
drawSpark();
})();
</script>
</body>
</html>
">
Key Takeaways
- CUDA Agent hits 98.8% pass rate and 96.8% faster-than-
torch.compilerate on KernelBench, at 2.11× geomean. - Level 2 fusion is the standout: 100% faster rate and 2.80× over
torch.compile. - The discrete milestone reward beats a raw speedup ratio by 36.4 points on faster rate.
- RFT plus value pretraining is what turns a 17-step collapse into 150 stable steps.
- Weights are closed; the 6,000-sample dataset,
SKILL.mdand the recipe are public.
Check out the Paper, the Project Page and the Dataset. Also, feel free to follow us on Twitter and don’t forget to join our 150k+ML SubReddit and Subscribe to our Newsletter. Wait! are you on telegram? now you can join us on telegram as well.
Need to partner with us for promoting your GitHub Repo OR Hugging Face Page OR Product Release OR Webinar etc.? Connect with us