← All posts
Blog

Context Rot Is the Real Reason Your Agents Fail in Production

July 30, 2026

The failure mode nobody was measuring

For two years, the industry's answer to unreliable agents was bigger windows. Ship a million tokens of context and let the model figure it out. A June 2026 arXiv paper on long-horizon search agents shows why that bet doesn't pay off: across four flagship open-source models and three deep-search benchmarks, degradation wasn't caused by hitting the physical context limit. Models rarely ran out of room. Instead, as accumulated context grew, models increasingly gave up early or hedged with uncertain answers rather than committing to a wrong one [1]. That's a distinct failure mode from the classic "lost in the middle" problem, and it's worse for production systems — an agent that silently punts on a task is harder to catch in monitoring than one that confidently produces a bad answer.

The paper's authors tested seven context-management strategies against this rot and found real separation in performance, cost, and rot-resistance between them — meaning the fix isn't "use less context," it's choosing the right operation for the right moment [1]. That distinction is exactly what's driving a wave of production engineering guides published this quarter.

Four operations, one pipeline

Across the practitioner writeups published since May, the same architecture keeps surfacing, formalized originally by LangChain and now showing up — named or not — in most production agent frameworks: write, select, compress, isolate [5]. Write means persisting state outside the active window (scratchpads, memory files, running plans) so the model doesn't have to re-derive facts it already established. Select means pulling in only what's relevant for the current step via retrieval or targeted file reads, not a dump of everything available. Compress means summarizing or truncating what's already in the window once it stops earning its token cost. Isolate means giving subtasks their own clean context window — a supervisor agent handing off narrow, scoped work to subagents that don't inherit each other's noise.

Sourcegraph's practical guide draws the line that matters for engineers deciding where to spend effort: if your improvements come from rewording, you're still doing prompt engineering; if they come from changing what data gets retrieved, in what order, and what gets evicted, you've moved into context engineering — and that's the discipline that actually holds up past the demo stage [2]. LangGraph's checkpointing and state-graph model is built around exactly these four operations, which is a large part of why it's become the default choice for regulated or high-stakes agent workloads this year [5].

Context is a compute cost center, not just a quality lever

What the quality-focused writeups undersell is the economics. A ReAct-style agent making ten tool calls in a session might generate 500 output tokens total while consuming 800,000 input tokens, because every call carries the full system prompt, tool schemas, and conversation history [3]. Generation is fast; the prefill pass over tens of thousands of input tokens is what you actually pay for, on every single call.

This is why prefix caching has become inseparable from context engineering rather than a separate infra concern. SGLang's RadixAttention stores KV activations in a radix tree keyed by token sequence, so any request sharing a system prompt — and every subsequent turn in a multi-turn conversation — hits cache instead of recomputing [3]. vLLM's automatic prefix caching does the equivalent at the block level, hashing fixed-size KV blocks so they're reused across requests when the hash matches [3]. Cached prefixes run roughly 10x cheaper than fresh prefill [4]. Practically, this means the character-for-character stability of your system prompt is now a performance and cost variable, not just a formatting preference — reordering or reformatting a prompt between calls silently kills your cache hit rate.

AppScale's reference architecture treats the context window as a capped per-turn budget rather than a bucket you fill until something breaks, with explicit compaction triggers for long agent loops, a defined boundary between working context and durable memory, and telemetry on context precision and cache-hit rate as first-class production metrics [4]. That's a meaningfully different mental model than "just use a bigger window."

Agents that manage their own budget

The more interesting 2026 development is context management moving from something an engineer decides at design time to something the agent manages at runtime. Research out of Stanford, SambaNova, and UC Berkeley splits this into three roles: a Generator that produces reasoning trajectories, a Reflector that distills concrete lessons from what worked and failed, and a Curator that folds those lessons back into a structured, evolving context playbook [5]. Instead of a human hand-tuning what goes into the window, the agent's own execution feedback becomes the curation signal. It's early, but it points at where the manual budget-allocation work described above eventually gets automated.

Implementation sketch

A minimal budget-aware assembler that most of the above practices converge on:

def assemble_context(task, tools, history, retriever, max_tokens=32_000):
    budget = {
        "system": 0.05, "tools": 0.10,
        "retrieval": 0.35, "history": 0.30, "scratch": 0.20,
    }
    system_prompt = load_fixed_system_prompt()  # stable string, never reordered
    tool_defs = select_relevant_tools(tools, task, cap=int(max_tokens * budget["tools"]))
    retrieved = retriever.query(task, k=8, cap_tokens=int(max_tokens * budget["retrieval"]))
    trimmed_history = compact_if_over(history, cap=int(max_tokens * budget["history"]))
    scratchpad = load_scratchpad(task.session_id, cap=int(max_tokens * budget["scratch"]))

    context = pack(system_prompt, tool_defs, retrieved, trimmed_history, scratchpad)
    emit_telemetry(cache_hit=is_prefix_cached(system_prompt),
                    context_precision=score_retrieval(retrieved, task))
    return context

The details matter less than the shape: a fixed budget per source, explicit compaction triggers instead of "summarize when it feels long," and telemetry on cache hits and retrieval precision emitted every call — not sampled after the fact.

Avant Concepts take

This whole trend confirms something we've said since our first RAG build: the LLM call is the easy part. The hard, unglamorous work is deciding what earns a place in the window, and most teams skip that work because there's no visible failure until an agent quietly gives up on a hard case in production. That's an eval problem as much as an architecture problem — if you're not measuring context precision and cache-hit rate per call, you don't actually know why your agent got worse last week.

We're also skeptical of the swing toward multi-agent isolation as a first move. Isolation solves real context-clash problems, but it multiplies your surface area for coordination bugs and makes debugging materially harder. For most production use cases we build, a single well-tooled agent with a disciplined context budget — select, compress, cache — outperforms a supervisor-and-subagents dance, and it's an order of magnitude easier to eval and observe. Reach for isolation when you've proven the single-agent version actually needs it, not because it's the pattern everyone's blog post is running this quarter.

On infra: don't hand-roll prefix caching or a custom retrieval re-ranker. vLLM and SGLang already ship production-grade prefix caching; a managed vector DB already does re-ranking better than what you'll build in a sprint. Spend your engineering time on the budget allocator and the telemetry, not on reinventing KV cache management.