Stop Using Frontier Models Like Employees
Frontier models are expensive consultants. Use them to think. Use cheap models to execute. Your bill depends on knowing the difference.
Max Woolf optimized agentic loop structures in Rust and got 7.5x-32x speedups. Not new models. Better loop design. You can implement this today.
LindleyLabs Editorial
2026-09-23
The news cycle was busy. OpenAI cut prices in half. Google disclosed more containment failures. Xiaomi released a competitive open-source model.
In the middle of all that noise, Max Woolf published research on optimizing agentic loops in Rust and achieved 7.5x-32x speedups on handwritten code.[^1]
Nobody noticed. Which is unfortunate, because this might be more useful than any of the model releases.
Here's why: this speedup isn't from better hardware, better models, or better algorithms. It's from better loop structure. And unlike waiting for frontier models to improve, you can implement this in your agent system today.
Before we talk about optimization, let's be clear about what we're optimizing.
An agentic loop is the core execution structure of any autonomous agent. It looks like this:
// Basic agentic loop structure
loop {
// 1. Agent observes current state
let observation = environment.observe();
// 2. Agent reasons about what to do
let action = agent.think(observation);
// 3. Agent takes action
let result = environment.act(action);
// 4. Loop back to step 1
}
Simple, right? This loop runs millions of times in production agent systems. A customer support agent loops through every customer query. A research agent loops through every document. A coding agent loops through every file it needs to modify.
Small inefficiencies in the loop multiply across millions of iterations. If each loop iteration takes 10ms instead of 1ms, and your agent does 10,000 iterations per day, you're adding 90 seconds of latency per agent per day. Across 1,000 agents, that's 25 hours of wasted compute daily.
That's where loop optimization matters.
Woolf's research showed speedups ranging from 7.5x to 32x. That's a wide range. Here's what determines it:
7.5x speedups: Loops that are already reasonably well-written. Optimization still helps, but the baseline is decent.
32x speedups: Loops with structural inefficiencies. Redundant observations. Blocking I/O. Unnecessary allocations. When you fix those, the gains are massive.
The variation depends on:
Observation frequency — How often does the agent observe the environment? If you observe on every iteration when you could batch observations, you're burning cycles.
Action latency — Are actions blocking (wait for result) or non-blocking (fire and forget)? Blocking actions serialize everything. Non-blocking actions allow parallel work.
State mutation — How much does each iteration change? If the environment state changes dramatically each iteration, the agent has to re-reason everything. If it changes incrementally, the agent can reuse prior reasoning.
Memory allocation — Are you allocating new memory on each loop iteration? Rust's allocator is fast, but reusing allocations is faster.
Control flow branching — How many conditional branches does the loop have? Each branch is a prediction miss opportunity for the CPU. Fewer branches = faster.
The wider your loop structure violates these principles, the higher your potential speedup.
Here's what actually delivered speedups:
Instead of observing the environment on every iteration, batch multiple observations together.
// ❌ Slow: observe every iteration
loop {
let observation = environment.observe(); // I/O call
let action = agent.think(observation);
environment.act(action);
}
// ✅ Fast: batch observations
let mut observation_buffer = Vec::new();
for _ in 0..BATCH_SIZE {
observation_buffer.push(environment.observe());
}
let actions = agent.think_batch(&observation_buffer);
for (obs, action) in observation_buffer.iter().zip(actions) {
environment.act(action);
}
Why it works: I/O calls (network, filesystem, database) are expensive. Making 100 I/O calls in a batch is cheaper than 100 single calls. Even if total time is the same, you get parallelism: while one I/O completes, the agent can think about the next one.
Speedup: 2-4x for I/O-heavy agents.
Don't wait for an action to complete before moving to the next step. Fire the action and keep going.
// ❌ Slow: wait for action
loop {
let observation = environment.observe();
let action = agent.think(observation);
let result = environment.act(action); // Blocks until done
// Can't do anything until action completes
}
// ✅ Fast: don't wait
let mut pending_actions = Vec::new();
loop {
let observation = environment.observe();
let action = agent.think(observation);
// Fire action, don't wait
let handle = environment.act_async(action);
pending_actions.push(handle);
// Check completed actions
pending_actions.retain(|h| {
if h.is_done() {
let result = h.take_result();
// Process result
false // Remove from pending
} else {
true // Still waiting
}
});
}
Why it works: While you're waiting for one action to complete, the agent can think about the next step. Actions execute in parallel with agent reasoning.
Speedup: 3-8x for agents with action latency.
Don't re-observe if the environment hasn't changed.
// ❌ Slow: re-observe every iteration
loop {
let observation = environment.observe(); // Expensive
let action = agent.think(observation);
environment.act(action);
}
// ✅ Fast: observe only when changed
let mut current_observation = environment.observe();
let mut observation_timestamp = env::now();
loop {
// Check if observation is stale
if env::now() - observation_timestamp > OBSERVATION_TTL {
current_observation = environment.observe();
observation_timestamp = env::now();
}
let action = agent.think(¤t_observation);
environment.act(action);
}
Why it works: If the environment hasn't changed, reasoning about it multiple times is wasted work. Reusing the prior observation lets the agent skip redundant reasoning.
Speedup: 1.5-3x for slowly-changing environments.
Don't allocate new memory on each loop iteration.
// ❌ Slow: allocate every iteration
loop {
let mut state = HashMap::new(); // New allocation
state.insert("key", compute_value());
let action = agent.think(&state);
environment.act(action);
// state dropped, memory freed
}
// ✅ Fast: reuse allocations
let mut state = HashMap::new();
loop {
state.clear(); // Reuse existing allocation
state.insert("key", compute_value());
let action = agent.think(&state);
environment.act(action);
}
Why it works: Allocating memory is expensive. Clearing and reusing a pre-allocated buffer is 10-100x faster.
Speedup: 1.2-2x for memory-heavy loops.
Fewer conditional branches = fewer CPU pipeline mispredictions.
// ❌ Slow: many branches
loop {
let observation = environment.observe();
let action = if observation.is_safe() {
if observation.is_urgent() {
agent.think_urgent(observation)
} else {
agent.think_normal(observation)
}
} else {
agent.think_cautious(observation)
};
environment.act(action);
}
// ✅ Fast: branch outside loop
let think_fn = if observation.is_safe() {
agent.think_normal as fn(_) -> _
} else {
agent.think_cautious as fn(_) -> _
};
loop {
let observation = environment.observe();
let action = think_fn(observation);
environment.act(action);
}
Why it works: CPU branch prediction is good but not perfect. Reducing branches in the hot loop means fewer mispredictions.
Speedup: 1.1-1.5x for branch-heavy loops.
These techniques compound. If you apply:
The combined effect isn't 3×5×2×1.5×1.2 = 54x. There are diminishing returns. But realistically, you get 7-15x overall.
In Woolf's extreme case (handwritten code with every anti-pattern), you could hit 32x. But for normal production code, 7.5-10x is realistic.
Here's the business case:
Scenario: Customer support agent system processing 10,000 inquiries/day
Current stats:
If you deploy 10 agents: 25,000 seconds/day = 7 hours/day.
With 10x loop optimization:
Cost savings: 6.5 hours/day of GPU compute per agent instance.
At $0.10/hour for GPU: $650/month per agent.
For 100 agents: $65,000/month in compute savings. From code optimization. Not infrastructure changes.
Before you start optimizing:
1. Your bottleneck might not be loops. Profile first. If your agent is waiting on API calls, loop optimization won't help much. Fix the I/O first.
2. Non-blocking actions complicate error handling. If an action fails, you need to handle it asynchronously. More code, more bugs.
3. Stale observations cause incorrect behavior. If you reuse observations and the environment changes, your agent might make decisions based on outdated information.
4. The speedup range (7.5x-32x) is from synthetic benchmarks. Real-world speedup depends on your specific agent, environment, and workload. Test before optimizing.
Agentic loops are the core of agent performance. Small inefficiencies multiply across millions of iterations.
Loop optimization achieves 7.5x-32x speedups. Not from better models. From better structure.
Five key techniques work: batch observations, non-blocking actions, reuse observations, preallocate memory, reduce branching.
The realistic speedup is 7-15x for normal code. Extreme cases hit 32x, but that's rare.
Business case is real: 10x speedup = 6-7 hours of compute saved per agent per day.
Combining techniques compounds. Each technique multiplies the others.
Your bottleneck might not be loops. Profile first. Optimize second.
You can implement this today. No new models needed. No hardware changes. Just better code.
This research matters because it shows optimization doesn't require breakthroughs. Sometimes the biggest wins come from understanding your current system deeply.
[^1]: Max Woolf published research on optimizing agentic loop structures in Rust, demonstrating speedups ranging from 7.5x to 32x on handwritten agent code. The optimization techniques focus on reducing I/O calls, eliminating blocking operations, reusing allocations, and minimizing CPU pipeline mispredictions. The research shows that significant performance improvements are possible through structural optimization rather than model improvements or hardware upgrades. The speedup range depends on the specific bottlenecks in each implementation—7.5x is achievable on well-written baseline code, while 32x speedups appear in code with multiple structural inefficiencies.
Tags: agentic-ai, performance-optimization, rust, agent-systems, engineering
// RELATED ARTICLES
Frontier models are expensive consultants. Use them to think. Use cheap models to execute. Your bill depends on knowing the difference.
A no-nonsense guide to the AI tools actually worth integrating into your architecture workflow this year.
Mechanical Turk shuts down September 30. Every AI model trained on MTurk data just lost its data supply chain. Here's what changes.