The Real Bottleneck in AI Agents Is Not the Model

The AI agent demos look great. The agent navigates to a page, clicks a button, fills a form, extracts data. Clean, fluid, purposeful. Then you try to run the same task across fifty concurrent sessions, or against a site with a slightly different DOM than last week, and everything falls apart.

For a long time, the industry consensus was that this was a model problem. Make the LLM smarter and the agent gets more reliable. I spent enough time building browser automation infrastructure to know that view is wrong. The model is not the bottleneck. The execution substrate is.

This is the core insight that drove me to design a stateless browser execution layer for AI agents and what building it taught me about where agentic systems actually break.

The Substrate Problem Nobody Talks About

Here is what a typical AI browser agent does when it receives a task: it initializes a browser session, loads a page, reads the DOM, sends a snapshot to the LLM, receives instructions, acts on those instructions, and loops. Simple enough in theory.

The problem is that live browser environments are not stable. Every session inherits whatever state the previous interaction left behind. Cookies accumulate. DOM elements render differently depending on ad loads, A/B tests, and CDN variations. Event listeners conflict. A component that was #submit-btn yesterday is now generated dynamically and carries a random hash.

The agent is not hallucinating because its reasoning is bad. It is hallucinating because the environment it is reasoning over is undefined. You are asking the model to make precise decisions about a surface that changes out from under it between calls.

I think of this as DOM drift: the silent gap between the web environment you indexed and the one the agent is actually touching. Most reliability discussions focus on prompt engineering or model choice. Almost none focus on controlling the execution substrate itself.

What Stateless Execution Actually Means

The standard framing for stateless in web development is about servers: no session data persists between HTTP requests. I borrowed that principle and applied it to browser automation.

In a stateless browser execution layer, each agent session starts from a clean, pre-indexed context. There is no inherited state. No residual cookies from prior runs. No DOM drift from accumulated interactions. The browser is initialized fresh, and the page structure is pre-processed into a normalized, machine-readable format before the agent touches it.

This matters for three interconnected reasons.

  • Predictability. If you know exactly what state the agent is starting from, you can reason about its behavior. Debugging becomes tractable. A failure in session 37 is reproducible in session 38 because the initial conditions are identical.

  • Parallelism. Stateless sessions are independent by definition. You can run a thousand concurrent agent sessions without worrying about shared state collisions. Throughput scales horizontally, limited by compute, not coordination overhead.

  • Decoupling. When the agent’s performance is isolated from the variability of live web environments, you can evaluate the model’s reasoning separately from execution reliability. That is a much cleaner signal for iteration.

How I Approached the Architecture

The first design decision was where to put the pre-processing work. The naive approach is to let the LLM handle DOM interpretation at inference time: dump the raw HTML into the context, let the model figure out what is interactable. This is how a lot of early browser agents worked, and it has two compounding problems. It is slow, and it burns enormous amounts of tokens on structure the model does not actually need.

A compressed DOM snapshot for a complex page can run 50,000 tokens. The model spends most of its budget parsing markup boilerplate instead of reasoning about the task. And when the page structure changes, you get mismatched references: the agent calls a selector that no longer exists, and the task fails.

My approach was to shift the structural work upstream. Before the agent session starts, a pre-indexing pass converts the live DOM into a normalized action map: a clean, minimal representation of the interactable elements on the page, their semantic roles, their state, and their relationships to each other. The LLM never sees raw HTML. It works from a pre-digested map.

This cut token consumption by roughly 95% compared to the raw-DOM approach, and reduced the number of interaction steps per task by around 90%. The agent is not wading through markup. It is working from a structured, task-relevant context.

The second decision was how to handle action translation. LLM outputs are probabilistic. The model might say click the submit button when the actual selector has changed or when there are two elements that could plausibly match. A deterministic action engine sits between the model output and the browser’s Chrome DevTools Protocol calls, validating and resolving intent against the indexed action map before any browser interaction happens.

This is where the stateless approach pays its biggest dividend. Because the action map was built from a controlled, pre-indexed snapshot, the engine can validate model intent against a known-good representation of the page. Ambiguous or invalid actions get caught before they produce a browser error. The hallucination rate drops not because the model got smarter, but because the gap between model output and executable reality got smaller.

The Benchmarks and What They Actually Tell You

On the Mind2Web and BrowserComp benchmarks, the two primary public evaluations for AI browser agents, this architecture hit an 85% or higher task success rate. The industry baseline for comparable agents sits around 50%.

I want to be careful about what that number means and does not mean. Benchmarks are artificial. Mind2Web tasks are curated; production web environments are not. An 85% success rate in benchmark conditions does not guarantee 85% in production. The gap depends on how close your target environments are to benchmark conditions and how well your pre-indexing handles the sites you are actually automating.

What the benchmark number does tell you is that the architecture is sound. The delta from 50% to 85% did not come from a better base model. Both approaches can use the same underlying LLM. The delta came from controlling the execution substrate. That is the point.

The Insight I Did Not Expect

Building this, I expected to learn things about browser automation. What I did not expect was how clearly it would expose the actual structure of the reliability problem in agentic systems more broadly.

The pattern is this: when you ask a model to operate in an environment it does not fully control, you are combining two sources of variance. The model’s reasoning and the environment’s state. Failures compound. A model that is 90% reliable on a clean environment might drop to 50% on a live one because the environmental variance adds a second multiplicative failure mode.

The right response to this is not to chase higher model accuracy on a dirty substrate. It is to reduce environmental variance as close to zero as you can. Stateless execution is one way to do that for browser environments. The principle extends further: wherever agents operate, the more you control the state they are reasoning over, the more predictable their behavior becomes.

This is why I think the next major reliability gains in agentic systems will not come from model scaling. They will come from execution infrastructure: sandboxing, state management, environment normalization, action validation layers. The model is capable enough for most production tasks. The substrate is not.

If you are building an agent pipeline that needs to be reliable at scale, start with your execution environment, not your prompt. Clean up what the model is reasoning over before you ask it to reason better.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.