Infrastructure Platform API How it works Research Blog Docs Try for free
Blog/Research/Compiling AI agents
research · agent compiler

The agent loop is an interpreter. We compiled it.

346 agent programs, 1,729 production runs. Model calls per run down 40%, tool-call errors 2.2x lower, one program on its 393rd run from a single compile. And a determinism number we would rather not have to print.

results.txttl;dr
compiled_programs     346          tier 1: 303 · tier 2: 18
production_runs       1,729        max reuse: 393 runs
model_calls / run     5 → 3        -40%   paired, n = 78
tool_calls / run      4 → 2        -50%
tool_call_error_rate  5.7% → 2.6%   2.2x lower
completion_rate       94.9% → 95.4%
break_even            run 2
path_determinism      34%          run-weighted · open

Ask an agent to pull yesterday's failed payments, cross-reference them against your CRM and email the account owners. It thinks, picks a tool, reads the result, thinks again, picks the next tool. Eleven steps later you have your emails.

Run it again tomorrow and it does the same eleven steps, rediscovered from scratch, at full price. Not quite the same eleven, either: nothing guarantees it takes the same route twice.

Most of what an agent does is deterministic. Today you pay a model to rediscover it on every run.

01An agent loop is an interpreter

There is a precise name for what an agent loop does. It reads a program - the task plus the tools available - and executes it one instruction at a time, deciding at each step what to do next. That is an interpreter in the exact sense a computer scientist means it. Write the loop as a function and the rest of this post follows:

int(p, x) = ythe loop: program p (task + tools), input x, result y mix(int, p) = p*Futamura I (1971): specialize the interpreter to one program p*(x) = int(p, x) for all xsame answers cost(p*(x)) << cost(int(p, x))no planning left to pay for

mix is a partial evaluator. Feed it an interpreter and a fixed program and what falls out is a compiled program: the first Futamura projection. Freezing an agent against one task is exactly this operation. The planning collapses into a fixed artifact, and the interpreter's job shrinks to running it. The judgment the task genuinely needs - reading a document, choosing between two candidates - stays as residual model calls. Everything else is compiled away.

So we built a compiler for agents. It has been in production since April 2026. This is what it measured.

02Two tiers, like a tiered JIT

You cannot know which paths are worth compiling until you have watched them run, which is the same shape of problem a tiered JIT solves. So the compiler has the same shape.

tier 0 · interpretThe ordinary agent loopThe model decides every step. Every agent on the market lives here, and every agent still starts here.
5 model calls, 4 tool calls per run (medians)
tier 1 · freezeA typed programOne successful run distilled into goal, ordered tool calls with templated arguments, declared input and output schema. Calls with no path to the output are dropped by a def-use rule. The model executes it; it no longer plans it.
3 model calls, 2 tool calls
tier 2 · compileExecutable codeThe same trace emitted as a script that calls the tools directly. No model in the loop, no tokens, deterministic by construction.
0 model calls

Of the 346 programs compiled so far, 303 are tier 1 and 18 are tier 2. Tier 1 carries production traffic today, so tier 1 is what the numbers below describe.

03Method and results

The honest way to measure a compiler is to compare a program against itself before compilation - not against some other agent, and not against an average. For every compiled program we took the source chat session it was distilled from and compared it to the median of that program's own frozen runs. 78 programs have enough of both to qualify. Same agent, same task, same tools, before and after.

Model calls are counted from context-tracking steps, tool calls and tool errors from the execution step log, on completed production runs between April and September 2026.

tier 0 · interpretedtier 1 · compiledmodel calls / run53-40%tool calls / run42-50%tool-call error rate5.7%2.6%2.2x lowertime to result125 s48 s2.6x faster
Figure 1. Same program before and after compilation, medians over 78 paired programs. Each pair is drawn against its own baseline, so the bars compare shape, not units.
MetricTier 0 (chat)Tier 1 (compiled)Change
Model calls per run (median)53-40%
Tool calls per run (median)42-50%
Tool-call error rate5.7%2.6%2.2x lower
Run completion rate94.9%95.4%+0.5 pt
Time to result (median)125 s48 s2.6x faster
Runs per compile (mean / max)15.0 / 393-
Path determinism (run-weighted)-34%open

Two caveats we are not going to bury. First, "time to result" compares an attended chat session, which includes a human reading and typing, against an unattended run nobody is watching. The purely machine-side part of that win is the 40% drop in model calls. Second, compiled paths fail less partly because we only compile paths that already worked. Written out, the observed gain has two terms:

Δobserved = Δcompilation + Δselectionand we cannot yet separate the two terms

That is selection as much as it is compilation, and it is worth saying out loud. Separating the two terms needs compiled programs whose source runs were not successful, which is a study we have not run.

04The economics, in closed form

Compilation is not free: it costs one model pass over a trace we already have. Because that trace is longer than a normal step we count it as two calls' worth. With the measured medians the cumulative cost of running one task n times is linear in every tier, and the question of when compilation pays back has a one-line answer:

C0(n) = m0 · ninterpreted: m0 = 5 model calls per run C1(n) = c + m1 · ntier 1: c = 2 for the one compile pass, m1 = 3 C2(n) = ctier 2: m2 = 0, the compile pass is the whole cost
n* = c / (m0 - m1) = 2 / 2 = 1tier 1 is cheaper than interpreting from run 2 onward lim 1 - C1/C0 = 1 - m1/m0 = 40%the saving converges to the drop in per-run model calls
0102030405060123456789101112runs of the same task, ncumulative model callsbreak-even at run 2: 8 calls vs 10C0(n) = 5nC1(n) = 2 + 3nC2(n) = 2
Figure 2. Cumulative model calls for n repeated runs of one task. tier 0 grows at 5 per run, tier 1 at 3 after a 2-call compile, tier 2 is flat. The curves cross between run 1 and run 2.
Runs of the same taskTier 0Tier 1Tier 1 savingTier 2Tier 2 saving
1550%260%
210820%280%
10503236%296%
10050030240%299.6%
393 our most-reused program1,9651,18140%299.9%

Tier 1 breaks even on the second run. That is the number worth holding on to, and it is a direct consequence of where the compiler gets its input: an execution trace the platform already recorded, rather than a workflow synthesized from a specification. Published systems that generate a workflow from scratch report break-even around seventeen transactions. We start from evidence, so we start from one.

Tier 2 is flat because a compiled script calls no model at all. That row is a projection from the mechanism, not a measurement: tier 2 has 18 compiled programs and six executions so far, three of them clean. We are not going to dress six runs up as a benchmark.

05Reliability is the real product

The interesting result is not that compiled agents are cheaper. It is that they are steadier, and steadiness is what actually blocks agents from getting deployed. On τ-bench, the benchmark that introduced the pass^k metric, the best agents clear about 60% of tasks on one attempt and fall below 25% when you require all eight attempts to succeed. Nobody puts a business process into production on those odds. A process that works differently every Tuesday is not a process.

Compilation attacks the mechanism directly. Treat each tool call as an independent trial with error rate e; a run of t calls then survives with probability:

S(t) = (1 - e)tprobability that a run of t tool calls sees no tool error S0(4) = 0.9434 = 0.79interpreted: 4 calls at e0 = 5.7% S1(2) = 0.9742 = 0.95compiled: 2 calls at e1 = 2.6% pass^k = pkthe τ-bench statistic: 0.608 = 0.017 for an agent that passes 60% of single attempts
0.30.40.50.60.70.80.91.002468101214161820tool calls in the run, tP(no tool error in the run)t = 2, tier 1 median: 0.95t = 4, tier 0 median: 0.79e = 5.7%: 0.31 after 20 callse = 2.6%: 0.59 after 20 calls
Figure 3. Independent-error model of run survival. e = 5.7% (interactive), e = 2.6% (compiled). The compiled program wins twice: a lower error rate per call, and fewer calls to expose to it.

In production the picture matches the model: a compiled program fails 2.6% of its tool calls against 5.7% in an interactive session, and it does that while the runs worth compiling are the substantial ones. Completion holds at 95.4% with nobody watching the chat to nudge it back on track.

The mechanism is unglamorous and that is the point: a compiled program can only use argument shapes that already returned a valid result once. The model never gets another chance to guess a field name.

06The number that is not flattering

Here is the result we could have left out. We measured path determinism: across repeated runs of one compiled program, how often does it take the exact same sequence of tool calls? Define it per program as the share of runs on that program's most common path, and weight by runs to get a fleet-level figure:

D(p) = rmode(p) / r(p)share of program p's runs on its modal tool path runs = Σ r(p) · D(p) / Σ r(p) = 0.34run-weighted over 26 programs with 5+ runs, 1,534 runs in total medianp D(p) = 0.43and 23% of programs sit at D = 1
26 programs with 5+ runs · 1,534 production runs · one program took 170 distinct paths across 385 runsD(p) = share of a program's runs on its modal tool path0%25%50%75%100%run-weighted mean 34%median program 43%23% of programs sit here
Figure 4. Only the measured figures are plotted. The worst program took 170 distinct paths across 385 runs; the best took exactly one across 168. Both are called "frozen".

Both of those are called "frozen". That spread is the entire argument for tier 2.

The reason is structural, not a bug. A tier-1 program is still executed by a language model, and a language model reading an instruction can improvise: skip a step it judges unnecessary, retry one it judges failed, reorder two it judges independent. Sometimes that improvisation is why the run succeeds. Often it is just variance.

Tier 2 removes it by construction, because a Python script cannot take 170 paths. That is why the roadmap is what it is:

  • Guards and deoptimization. Preconditions and postconditions on every compiled tool call. When a provider renames a field, the guard trips and the run deoptimizes back into the interpreter mid-flight instead of failing, exactly how a JIT handles a failed speculation.
  • Compile-then-verify. A compiled script becomes the live version only after it has replayed its own source trace successfully.
  • Binding classification. Every argument tagged at compile time as a constant, a user input, a copied output, a transform, or a residual model decision, so we can predict a program's determinism before its first run instead of measuring it after 385.

07Where this sits in the literature

This idea arrived from several directions at once during 2026, which is usually a sign it is the right one. TraceCompiler mines noisy agent traces into mostly deterministic workflows and classifies every argument binding with auditable evidence. Compiled AI compiles once and then executes with zero runtime tokens. Agentic Plan Caching (NeurIPS 2025) keeps the model but caches the plan, for roughly half the cost. Agent JIT Compilation from Stanford borrows the same vocabulary we do and adds the invariant-enforcing tool protocol that makes guards safe, and LLMCompiler (ICML 2024) shows what you get once the program is a DAG you can parallelize.

What none of them has is a fleet. A compiler needs execution traces across many tools, many users and many failures, and that is the part you cannot download. We have 1500+ connectors, 500+ models and five months of production traces, and every run adds to them.

Compile your own agent

Build it in chat until it works once, then freeze it. The frozen program gets a schema, an API endpoint and a schedule, and it stops paying a model to rediscover what it already knows.