An LLM multi-agent framework that discovers end-to-end machine-learning pipelines by extending tree search to a graph, accumulating experience in memory, and separating "what to change" from "how to code it" — reaching state-of-the-art on MLE-Bench in half the standard time budget.
You hand an AI agent a Kaggle competition. "Here is a dataset of audio clips. Predict the bird species. You have 12 hours and a GPU. Go." No human in the loop. The agent must write data-loading code, pick a model, train it, read the error when it crashes, fix it, try a better architecture, ensemble its best attempts, and submit — over and over, hundreds of times.
This is Machine Learning Engineering (MLE) as an autonomous task, and it is brutal precisely because it is long-horizon. A single good idea is not enough. The agent must keep getting better over hundreds of attempts, learning from its own failures faster than it burns through the clock. The paper calls this capability self-evolution.
The trouble: today's MLE agents do not really self-evolve. They get stuck. The authors diagnose three concrete diseases, and the entire MLEvolve design is a cure for each one.
Hold those three diseases in your head. By the end of this lesson you will see exactly which MLEvolve component cures each one — Progressive MCGS for isolation, Retrospective Memory for memorylessness, and Hierarchical/Adaptive coding for the lack of control.
If you had to compress MLEvolve into one sentence: turn the search tree into a search graph, give the search a memory, and split the agent's brain from its hands.
That is literally three insights, one per disease. The elegance is that they compose into a single loop.
The word doing the heavy lifting is progressive. A human expert with 12 hours does not explore at a constant rate. In the first few hours they try wildly different approaches — gradient boosting, a CNN, a transformer. In the last few hours, having found that the CNN clearly wins, they stop wandering and pour every remaining minute into squeezing that CNN: tuning, augmenting, ensembling. MLEvolve bakes this exploration→exploitation arc directly into the search schedule.
Here is the headline result that tells you the cure works: under a 12-hour budget — half the standard 24-hour budget other agents get — MLEvolve reaches a 65.3% average medal rate on MLE-Bench, beating every prior method including ones that ran twice as long. And the same machinery, pointed at pure math-optimization problems, beats AlphaEvolve on 11 of 15 tasks. The design generalizes.
Before any of the clever machinery, we need to frame the task precisely. The paper poses MLE as optimization over a space of candidate solutions.
A single "candidate solution" is a complete program — preprocessing, feature engineering, model definition, training loop, and prediction, all in one runnable file (think solution.py that emits submission.csv). The space of all such programs is called S. We want the single best one.
Reading that in words: s* is the solution we are hunting for. T is the task (this Kaggle competition). h(T, s) is the score you get by running program s on task T — it might be accuracy, AUC, or a loss, whatever the competition grades on. S is the (astronomically large, mostly-broken) set of all programs you could write. We cannot enumerate S, so we search it: generate a candidate, run it, read the score, generate a better one, repeat.
A 30-second refresher on MCTS, because everything builds on it. Monte Carlo Tree Search repeats four steps:
Standard MCTS has the fatal flaw from Chapter 0: that tree structure isolates branches. The reward in step 4 is a lone number. MLEvolve keeps the four-step loop but surgically upgrades two of them — it adds graph edges to expansion (so branches can borrow from each other) and a memory write/read around the whole loop (so the content, not just the number, survives).
Here is the first cure. Disease 1 was branch isolation. The cure is to stop treating the search as a tree and start treating it as a directed graph with two kinds of edges.
The vertices V are the candidate solutions. The edges split into two families that do completely different jobs:
Primary edges (ET) — the "born from" relation. If node v was created by taking node u and applying some operator (improve it, debug it), we draw a primary edge u→v. These edges form the tree backbone. They — and only they — carry credit during backpropagation. Think of them as parent→child lineage.
Reference edges (Eref) — the "inspired by" relation. If node v also looked at node r for ideas — even though r lives in a totally different branch — we draw a reference edge r⊣v. These edges carry information (the agent reads r's code/plan as context) but carry no credit during backpropagation.
And the beautiful boundary condition: when there are no reference edges at all (Eref = ∅), the graph collapses back into a plain tree, and Progressive MCGS reduces exactly to standard MCTS. MCGS is a strict generalization — it can never do worse than the tree it contains, because the tree is a special case.
Play with the toggle below. With references OFF you see the isolated tree (standard MCTS). Flip references ON and watch the dashed cross-branch edges appear — suddenly a stagnating branch can pull a strong idea from across the graph.
Solid teal = primary edges (ET, carry credit). Dashed purple = reference edges (Eref, carry ideas only). Toggle references and pick which expansion type fires.
Those three buttons map to the three graph-based expansion types the paper defines (alongside plain "primary expansion" with no references):
Notice these are escalating responses to escalating stagnation — a theme we'll formalize in the next chapter. The ablation later reveals intra-branch evolution is the single most important of the three: reflecting on your own recent history beats blindly borrowing from strangers.
This is the heart of the paper, so we will build it piece by piece and then make it interactive. Three sub-mechanisms live here: (a) the selection rule (UCT), (b) the entropy-inspired soft switch from exploration to exploitation, and (c) stagnation-triggered graph expansions.
To pick which node to expand, MCGS walks the tree backbone using the classic UCT (Upper Confidence bound for Trees) score on each child:
Decode every symbol: Qi is child i's average reward (how good it has looked so far — the exploit term). Ni is how many times we visited child i, Nv is visits to the parent. The square-root term is the explore bonus: it is large for rarely-visited children (small Ni) and shrinks as we visit them. ε is a tiny constant so we never divide by zero. c(t) is the exploration constant — and crucially it is a function of time, decaying from c0=2 down to cmin=0.5. As the clock runs, the explore bonus literally shrinks.
Decaying c(t) is a gentle nudge. MLEvolve adds a sharper mechanism: at each step it flips a biased coin to choose between two whole modes:
The weight w(t) starts at 1.0 (always explore via UCT) and decays to a floor wmin=0.2. Early on, the coin almost always says "explore." Late on, it usually says "exploit." When it says Elite-exploit, the agent ignores the local tree entirely and jumps to one of the globally best nodes, picked by inverse rank:
So the rank-1 node gets weight 1/1, rank-2 gets 1/2, rank-3 gets 1/3. Worked example with top-K=3: weights are 1, 0.5, 0.333, summing to 1.833. Probabilities: 54.5% / 27.3% / 18.2%. The best node is favored but the runners-up still get real chances — exploitation that isn't blindly greedy.
When does each graph expansion from Chapter 3 fire? On stagnation, at two levels:
Backpropagation needs a reward. MLEvolve uses a deliberately coarse 3-level signal:
This is smart: it cleanly separates "broken," "feasible-but-meh," and "genuine improvement," giving stable credit without depending on the raw metric's wildly different scales across tasks (an AUC of 0.9 vs a loss of 0.02 are not comparable, but "+2 = improved" always is). Each ancestor on the primary path then updates its visit count and cumulative reward, and Q = W/(N+ε).
The simulator below runs Progressive MCGS one step at a time. Click Run step to expand the search. Watch two things: (1) the strategy badge flips from blue EXPLORE to orange EXPLOIT as the weight w(t) decays, and (2) the effective branch count readout falls as effort concentrates. Toggle to Vanilla MCTS to see the difference: vanilla keeps w fixed, so it never concentrates — it sprays effort across branches forever.
Each circle is a candidate solution; brightness = score. Blue halo = expanded under EXPLORE (UCT). Orange halo = expanded under EXPLOIT (elite-guided). Dashed edges appear when stagnation triggers a cross-branch reference.
Cure number two, for the memoryless disease. MLEvolve gives the agent two memories that work together: a static domain knowledge base for cold start, and a dynamic global memory that grows during the search.
Drop an LLM into a niche task — say, protein-structure regression — and its first attempts are often naive: it reaches for whatever it half-remembers. The fix is a small, curated library of "for task-type X, these models tend to work, used like this," synthesized from open-source repos and competition write-ups. Given a task T, the system retrieves matching entries by keyword and offers them as an optional hint to the very first draft:
Where Init(·) is the routine that writes the first plan + code, and RKB(T) is the retrieved set of relevant model suggestions. It is a prior, not a mandate — it just stops the agent from face-planting on attempt #1.
This is the real engine of self-evolution. After every valid node executes, the system writes a structured record: the plan, the outcome, the analysis, and the feedback signal. This is exactly the "content" that scalar backpropagation threw away in Chapter 0. The memory grows into a searchable diary of the agent's entire campaign.
How do you find the relevant past records? Keyword search (BM25-style, "lexical") is great for exact terms like a specific error string. Semantic search (FAISS embeddings, "vector") is great for meaning ("this crash feels like that one"). Each is weak where the other is strong, so MLEvolve runs both and fuses their rankings with Reciprocal Rank Fusion (RRF):
Decode it: for a record d, rlex(d) is its rank in the keyword results and rvec(d) is its rank in the vector results. RRF rewards records that rank high in either list (rank 1 contributes a big 1/(k+1); rank 50 contributes almost nothing). k is a smoothing constant that dampens how much the very top ranks dominate. α tilts the blend toward lexical (α→1) or vector (α→0).
Drag the α slider below to watch the fused ranking re-order live as you shift trust between the keyword list and the semantic list.
Six memory records, each with a lexical rank and a vector rank. The fused column re-sorts by the RRF score as you change α and k.
Critically, memory is queried differently depending on what the agent is doing:
The third cure. Disease 3 was one-shot generation that fuses strategy and implementation. The fix is to split the agent into a planner and a coder, and to let the coder pick from three edit modes depending on the situation.
This is the same separation a senior engineer enforces in code review: the design discussion ("we should swap to a transformer encoder and add early stopping") is distinct from the diff that implements it. Fusing them is how the model "fixes" one thing and silently breaks another.
The coder does not always rewrite everything. It chooses granularity to match the situation — this is the controllability that one-shot generation lacks:
Pick a search state below and see which mode the framework selects, and why:
The framework is realized as a roster of single-purpose agents, each tied to a search phase or operator. This specialization is what makes the modes reliable — each agent has a narrow, well-defined job:
| Agent | Job | Maps to |
|---|---|---|
| Draft | Generate initial root solutions; can pull from the knowledge base | Base mode, cold start |
| Improve | Refine a runnable solution via controlled revisions | Diff mode, primary expansion |
| Debug | Repair crashes from error traces; minimal edits until fixed | Triggered on failure |
| Evolution | Aggregate recent same-branch nodes; reflect & refine | Intra-branch evolution |
| Fusion | Pull strong solutions from other branches | Cross-branch reference |
| Aggregation | Fuse top trajectories into a new branch root | Multi-branch aggregation |
| Code Review | Catch naming/import errors, metric inconsistencies pre-run | After every generation |
| Data Leakage | Check for train/eval leakage to prevent inflated scores | Quality gate |
| Result Parse | Extract metric, status, insights from logs back into the loop | Simulation → backprop |
The benchmark is MLE-Bench (OpenAI): 75 real Kaggle competitions across vision, NLP, signal processing, and tabular data, split into 22 low / 38 medium / 15 high complexity. An agent "earns a medal" when its submission would have placed at bronze/silver/gold on the real human leaderboard. The backbone LLM is Gemini-3.1-Pro-preview, temperature 1.0, with 500 expansion steps on a single H200.
The comparison below plots medal rate against the strongest baselines. Toggle the metric to see how MLEvolve's lead holds across overall medals, golds, and above-median rate. Bars are theme-aware and read off the paper's Table 1.
The same machinery — unchanged — was pointed at 15 open-ended mathematical optimization problems from AlphaEvolve (circle packing, kissing numbers, autocorrelation inequalities, and the like). These are not ML pipelines at all, but they share the iterative shape: propose a candidate, score it, refine. MLEvolve won the best result on 11 of 15, edging out AlphaEvolve, AlphaEvolve-v2, SimpleTES, TTT-Discover, and OpenEvolve.
A result table tells you that it works; ablations tell you why. The authors removed one component at a time on MLE-Bench Lite (22 tasks).
| Configuration | Medal % | Gold % | Beat Ratio % |
|---|---|---|---|
| Full MLEvolve | 81.82 | 54.55 | 88.39 |
| − Progressive MCGS | 68.18 | 40.91 | 79.91 |
| − Retrospective Memory | 68.18 | 50.00 | 81.90 |
| − Adaptive Code Generation | 72.73 | 40.91 | 84.14 |
Reading the table: every removal hurts, confirming all three components pull weight. The biggest drop comes from removing Progressive MCGS (medal 81.8→68.2) — without it the search reverts to fixed-strategy MCTS that wastes the late budget on dead branches. Removing memory costs a full 13.6 points of medal rate. Drilling deeper, the paper finds intra-branch evolution is the most critical sub-mechanism inside MCGS, while Elite-Guided exploitation mainly sharpens leaderboard rank by polishing already-good solutions.
Recall the Chapter 4 claim that w(t) makes branch-selection entropy fall over time. The authors verify it directly. Within a sliding window they compute the branch distribution πt and report exp(H(πt)) — the "effective number of active branches." A value of 5 means effort is spread as if over 5 equal branches; a value of 1 means all effort is on one.
The curve below reproduces Figure 3. MLEvolve (teal) slides from ~4.8 effective branches down to ~2.8 as search progresses — it concentrates. Vanilla MCTS (gray), with its fixed exploration constant, stays flat near 4.3 the whole way, spraying effort even after the winners are obvious.
Two more findings round out the analysis. (1) Backbone-agnostic: swapping the LLM among Gemini-3.1-Pro, GPT-5.5, DeepSeek-v4-Pro, and Kimi-K2.6 keeps MLEvolve competitive — each backbone has domain strengths (GPT-5.5 tops NLP at 96.2% beat ratio; Kimi leads audio at 99.2%) but the framework isn't bolted to any one model. (2) Sustained improvement: over the 12-hour budget MLEvolve keeps climbing to a 98.2% beat ratio on representative tasks, while Vanilla MCTS plateaus early around 70% — the visible signature of self-evolution actually working.
MLEvolve sits at the crossroads of three lines of work. Place it in the map and the contribution sharpens.
Explore these on the site to deepen each thread:
| Symbol / Eq. | Meaning | When it fires |
|---|---|---|
| s* = argmax h(T,s) | Best solution program for task T | The overall objective |
| E = ET ∪ Eref | Primary (credit) + reference (ideas) edges | Graph structure; Eref=∅ ⇒ plain MCTS |
| UCT = Qi + c(t)√(ln(Nv+1)/(Ni+ε)) | Selection score; c(t) decays 2→0.5 | Picking which node to expand |
| P(UCT)=w(t), P(Elite)=1−w(t) | Soft switch; w(t) decays 1.0→0.2 | Every selection step |
| P(vi) ∝ 1/rank(vi) | Inverse-rank pick among top-K elites | Exploitation mode |
| R(v) ∈ {−1, +1, +2} | Fail / no-gain / new best | Simulation reward |
| RRF: α/(k+rlex) + (1−α)/(k+rvec) | Fuse keyword + semantic retrieval | Memory retrieval |
| exp(H(πt)) | Effective # of active branches | Diagnostic: 4.8→2.8 |