n4nAI

Context rot: what happens when agents stuff the window

Context rot LLM agents silently undermines reliability as agents stuff the window. Analysis of causes, tradeoffs, and engineering fixes like compaction and eviction.

n4n Team4 min read777 words

Audio narration

Coming soon — every post will get a voice note here.

Context rot LLM agents is the silent failure mode in production agentic systems: as the loop appends every tool result, error trace, and retry, the prompt becomes a landfill where the original instruction is the faintest signal. The model doesn’t crash; it just gradually stops following orders, misses key facts, and confidently hallucinates.

What context rot actually is

The term context rot LLM agents describes the progressive degradation of task performance as the input context accumulates irrelevant or redundant tokens. It is not a model bug. It is a systems design problem created by treating the transformer context window as an append-only log.

A typical agent loop looks like this:

def run_agent(task, model="gpt-4o"):
    messages = [
        {"role": "system", "content": "You are a helpful agent."},
        {"role": "user", "content": task}
    ]
    for step in range(20):
        resp = client.chat.completions.create(model=model, messages=messages)
        msg = resp.choices[0].message
        messages.append({"role": "assistant", "content": msg.content})
        if msg.tool_calls:
            for call in msg.tool_calls:
                tool_out = call_tool(call)
                messages.append({"role": "tool", "content": str(tool_out)})
    return messages

Every iteration adds assistant reasoning, tool calls, and raw tool output. After ten steps, the system prompt from step 0 is buried under 8,000 tokens of intermediate JSON. The model’s effective attention weight on that system prompt drops.

Why bigger windows don’t fix it

Buying a 200k-token context does not cure context rot LLM agents. Research on long-context models consistently shows “lost in the middle” behavior: retrieval and instruction-following accuracy dip sharply when critical information sits away from the edges. A larger window just gives you more room to accumulate noise before the model fails.

Latency and cost scale with context length. A 32k-token prompt costs roughly 16x a 2k prompt in time-to-first-token on most GPUs, even if only the last 500 tokens matter. Ignoring context rot LLM agents by scaling hardware is a tax on every request.

Mechanisms of decay

Attention dilution

Self-attention is not uniform. With thousands of tokens, the softmax distribution over keys flattens. The model spreads its limited “focus budget” across everything, so the signal from the user’s actual goal gets averaged into the mush of stale tool outputs.

Error propagation and self-reinforcement

Agents retry. When a tool fails, the error string is appended. The agent often repeats the same broken call, appending another error. The context now contains a self-reinforcing loop of failure that biases the next generation toward more of the same.

Instruction drift

System prompts that say “only call the tool when X” lose enforceability when they are 30 scroll-backs away. The model attends to the most recent few messages, which are usually tool results, not the governing rules.

Strategies that work

Summarize and compact

Periodically collapse the middle of the conversation into a structured summary. Keep the system prompt, the current task, and the last few exchanges verbatim.

def compact_history(messages, model, keep_last=3):
    sys = messages[0]
    tail = messages[-keep_last:]
    middle = messages[1:-keep_last]
    if not middle:
        return messages
    summary = client.chat.completions.create(
        model=model,
        messages=[
            {"role": "system", "content": "Summarize the agent transcript. Preserve decisions, key values, and open sub-tasks. Drop raw logs."},
            {"role": "user", "content": str(middle)}
        ]
    ).choices[0].message.content
    return [sys, {"role": "system", "content": "Compaction summary: " + summary}] + tail

Call this every N steps or when messages exceeds a token budget.

Structured scratchpad external to context

Move volatile state—like a list of fetched URLs, intermediate SQL, or parsed JSON—into an external store (Redis, SQLite). Inject only a pointer or a trimmed view into the prompt:

state_id = redis.set("agent:123:scratch", json.dumps(big_obj))
messages.append({"role": "system", "content": f"Scratchpad updated: {state_id} (keys: a,b,c)"})

The agent retrieves details via a tool only when needed.

Eviction policies

Treat the context as an LRU cache. Assign each message a relevance score based on recency and type. Tool outputs older than K steps with no subsequent reference get dropped. Never evict the system prompt or the active user task.

Trim tool outputs at the source

Most tools return far more than the model needs. Wrap them:

def call_tool_safe(call, max_chars=500):
    raw = call_tool(call)
    if len(raw) > max_chars:
        return raw[:max_chars] + "...[truncated]"
    return raw

This single change often removes 70% of token growth in data-agent loops.

Tradeoffs and failure modes

Compaction loses nuance. A summary might drop the exact error code that later becomes relevant. Mitigate by storing full history externally and only summarizing for the live context.

External scratchpads add retrieval latency and a new failure point. If the store is down, the agent goes blind. For low-latency agents, keep a small hot cache in the context and push cold data outward.

Eviction risks dropping a needed fact. Use conservative thresholds and log evictions for replay debugging.

The cost of context rot LLM agents is not just accuracy; it is unpredictable failures that pass staging and rot in production under load.

Measuring and metering the rot

You cannot fix what you do not measure. Track prompt token counts per agent step and alert when growth is superlinear. If you run these agents through a gateway, per-token metering exposes the bleed. n4n.ai forwards provider cache-control hints and meters usage per token, so you can set a context budget and alert when an agent’s window balloons across provider fallbacks.

A simple guard:

MAX_CTX_TOKENS = 12000
if estimate_tokens(messages) > MAX_CTX_TOKENS:
    messages = compact_history(messages, model)
    assert estimate_tokens(messages) < MAX_CTX_TOKENS

Decisive takeaway

Context rot LLM agents is a design debt, not a model limitation. Engineer the context like you would a cache: bound its size, evict ruthlessly, summarize aggressively, and externalize state. Ship a compaction pass and a token budget before you scale the agent to more steps. The teams that treat the window as a managed resource—not an infinite scratchpad—are the ones whose agents stay reliable past step five.

Tagscontext-rotcontext-windowllm-agentsreliability

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All context window & token management for agents posts →