Context Window Budgeting Strategies for Long-Running Agents

Context windows fill up faster than you expect in agentic workflows. A systematic approach to allocating tokens across system prompts, memory, tools, and user messages.

AgentixForce Team··11 min read

Why Token Budgeting Matters

Long-running agents are context hungry. Each tool call appends its full input and output. Every retrieved document lands verbatim in the prompt. System prompts grow as capability instructions accumulate. Without a deliberate budget, you hit the model's context limit at the worst possible moment, mid-task, mid-reasoning, in the middle of a complex multi-step workflow.

The consequences range from hard failures (the API returns a 400 context_length_exceeded) to soft failures (the model silently ignores the earliest messages because its attention degrades on extremely long sequences). Neither is acceptable in production. A systematic budget prevents both.

The Cost Dimension

Token budgeting is not just an availability concern, it's a cost concern. LLM providers charge per token on both input and output. A 128K context window at $15/M input tokens costs $1.92 per request before a single output token is generated. If your agent loops 20 times with a growing context, you're paying $38+ per task in input costs alone. Budget discipline directly controls cost.

The Latency Dimension

Time-to-first-token (TTFT) scales with context length. At 4K tokens, TTFT is typically 300–500ms. At 64K tokens, it's 2–4 seconds. At 128K tokens, it's 8–15 seconds on most providers. Keeping contexts lean directly translates to a faster, more responsive agent.

Context Window Budget Allocation (10,000 token window)20%15%30%25%10%System Prompt2,000 tokensTool Definitions1,500 tokensMemory / RAG3,000 tokensConversation History2,500 tokensUser Input Reserve1,000 tokensBudget Enforcement ZonesGREEN (0–70%)Normal operation full context availableYELLOW (70–85%)Compression triggers pruning beginsRED (85–95%)Aggressive pruning summarize history
Recommended token allocation across a 10,000-token context window. System prompt and tool definitions are fixed costs; memory and history are variable and must be actively managed.

Anatomy of a Context Window

Before you can budget, you need to understand what occupies context. Every agentic context window consists of five logical regions, each with different management characteristics.

Fixed vs Variable Cost Regions

  • System prompt (FIXED): Instructions, persona, constraints, output format. Ranges from 500 to 4,000 tokens. Rarely changes per request. Optimize once, compress aggressively.
  • Tool definitions (FIXED): JSON schema for every registered tool. Each tool adds 100–400 tokens. Use lazy registration, only include tools relevant to the current task phase.
  • Memory / RAG chunks (VARIABLE): Retrieved documents, past summaries, knowledge injections. The most variable region. Budget 20–40% of total window here.
  • Conversation history (VARIABLE): The growing accumulation of turns. Grows by 400–1,000 tokens per round trip. Needs active pruning after 5–10 turns.
  • User input + assistant response reserve (VARIABLE): Space for the current turn. Always reserve at minimum 1,000 tokens for user input and 2,000 for model output.

Hidden Token Consumers

Beyond the obvious categories, several hidden consumers quietly eat tokens. Special tokens (BOS, EOS, role delimiters) add 4–20 tokens per message. Structured output format instructions (JSON schemas, XML constraints) can add 200–500 tokens. Chain-of-thought prompting instructions inflate the assistant prefix. Count all of these in your budget model.

Static vs Dynamic Allocation

The simplest budgeting strategy is static allocation: reserve fixed token counts for each region up front. This is easy to implement but wastes capacity. If your memory region is budgeted at 3,000 tokens but the current task requires no retrieval, those 3,000 tokens go unused while your history region might be starved.

Static Allocation Implementation

python
from dataclasses import dataclass
from typing import Optional

@dataclass
class ContextBudget:
    total: int = 10_000
    system_prompt: int = 2_000
    tool_definitions: int = 1_500
    memory_rag: int = 3_000
    conversation_history: int = 2_500
    user_input_reserve: int = 500
    assistant_output_reserve: int = 1_500

    def __post_init__(self):
        allocated = (
            self.system_prompt + self.tool_definitions +
            self.memory_rag + self.conversation_history +
            self.user_input_reserve + self.assistant_output_reserve
        )
        assert allocated <= self.total, (
            f"Budget overallocated: {allocated} > {self.total}"
        )

    @property
    def unallocated(self) -> int:
        return self.total - (
            self.system_prompt + self.tool_definitions +
            self.memory_rag + self.conversation_history +
            self.user_input_reserve + self.assistant_output_reserve
        )

Dynamic Allocation Implementation

Dynamic allocation computes region sizes at runtime based on actual content. It requires a BudgetManager that tracks live usage and adjusts limits as the task progresses.

python
import tiktoken

class DynamicBudgetManager:
    def __init__(self, model: str, total_tokens: int):
        self.enc = tiktoken.encoding_for_model(model)
        self.total = total_tokens
        self._usage: dict[str, int] = {}

    def count(self, text: str) -> int:
        return len(self.enc.encode(text))

    def measure_region(self, region: str, content: str) -> int:
        tokens = self.count(content)
        self._usage[region] = tokens
        return tokens

    @property
    def used(self) -> int:
        return sum(self._usage.values())

    @property
    def remaining(self) -> int:
        return self.total - self.used

    def can_fit(self, content: str, reserve: int = 1000) -> bool:
        return self.count(content) <= (self.remaining - reserve)

    def budget_for_region(
        self, region: str, base_pct: float, min_tokens: int = 500
    ) -> int:
        # Give each region a dynamic slice of what's left
        # after fixed costs are accounted for
        fixed_used = sum(
            v for k, v in self._usage.items()
            if k in ("system_prompt", "tool_definitions")
        )
        variable_budget = self.total - fixed_used - 2000  # output reserve
        return max(min_tokens, int(variable_budget * base_pct))

Token Counting Methods and Tools

Accurate token counting is a prerequisite for any budgeting system. Different models use different tokenizers, and approximate counting leads to budget overruns or overly conservative pruning.

Tokenizer Libraries by Provider

  • OpenAI (GPT-4o, GPT-4): Use tiktoken library, cl100k_base encoding. Install: pip install tiktoken.
  • Anthropic (Claude): Use anthropic.count_tokens() API or the official anthropic Python SDK's count_tokens method.
  • Google (Gemini): Use google.generativeai.count_tokens() or the Vertex AI API countTokens endpoint.
  • Local models (Llama, Mistral): Use transformers.AutoTokenizer from HuggingFace. Load the exact checkpoint tokenizer for accuracy.
  • Estimation fallback: 1 token ≈ 4 characters for English text. Useful for quick estimates but never for production budget enforcement.

Counting Overhead Beyond Raw Text

python
import tiktoken

def count_chat_tokens(messages: list[dict], model: str = "gpt-4o") -> int:
    """Count tokens including per-message overhead for chat format."""
    enc = tiktoken.encoding_for_model(model)
    # Each message adds overhead for role + delimiters
    # gpt-4o: 3 tokens per message, 1 for reply priming
    tokens_per_message = 3
    tokens_per_name = 1
    num_tokens = 3  # reply priming tokens
    for msg in messages:
        num_tokens += tokens_per_message
        for key, value in msg.items():
            num_tokens += len(enc.encode(str(value)))
            if key == "name":
                num_tokens += tokens_per_name
    return num_tokens

def count_tool_schema_tokens(tools: list[dict], model: str = "gpt-4o") -> int:
    """Tool schemas are serialized to JSON before tokenization."""
    import json
    enc = tiktoken.encoding_for_model(model)
    schema_json = json.dumps(tools, indent=2)
    return len(enc.encode(schema_json))

Implementing Budget Enforcement

Counting tokens is only useful if you enforce the budget. Enforcement means intercepting context assembly before the API call and triggering compression or pruning when limits are exceeded.

Three-Zone Enforcement Model

Model your budget as three zones rather than a binary fit/overflow check. The green zone (0–70% utilization) operates normally. The yellow zone (70–85%) activates light compression: summarize the oldest 20% of history, drop low-priority tool results. The red zone (85–95%) triggers aggressive pruning: keep only the system prompt, last 3 turns, and the most recent tool result.

python
from enum import Enum
from dataclasses import dataclass, field

class BudgetZone(Enum):
    GREEN = "green"
    YELLOW = "yellow"
    RED = "red"
    CRITICAL = "critical"

@dataclass
class ContextAssembler:
    budget: DynamicBudgetManager
    compressor: "ContextCompressor"  # forward ref

    def get_zone(self) -> BudgetZone:
        pct = self.budget.used / self.budget.total
        if pct < 0.70:
            return BudgetZone.GREEN
        elif pct < 0.85:
            return BudgetZone.YELLOW
        elif pct < 0.95:
            return BudgetZone.RED
        return BudgetZone.CRITICAL

    async def assemble(
        self,
        system_prompt: str,
        tools: list[dict],
        history: list[dict],
        memory_chunks: list[str],
        user_message: str,
    ) -> list[dict]:
        # Always include fixed regions first
        self.budget.measure_region("system_prompt", system_prompt)
        self.budget.measure_region("tool_definitions", str(tools))

        zone = self.get_zone()

        if zone == BudgetZone.GREEN:
            trimmed_history = history
            trimmed_memory = memory_chunks
        elif zone == BudgetZone.YELLOW:
            trimmed_history = await self.compressor.light_compress(history)
            trimmed_memory = memory_chunks[:3]  # top-3 chunks only
        else:
            trimmed_history = history[-3:]  # last 3 turns only
            trimmed_memory = memory_chunks[:1]  # single most relevant

        # Measure and assemble
        self.budget.measure_region("history", str(trimmed_history))
        self.budget.measure_region("memory", " ".join(trimmed_memory))

        return self._build_messages(
            system_prompt, trimmed_history, trimmed_memory, user_message
        )
Context Overflow Detection and Handling FlowNew Message ArrivesCount tokensBudget Checkremaining > threshold?YES (fits)Append toContextNO (overflow)Step 1: PruneRemove low-relevance itemsStep 2: CompressSummarize old turnsStep 3: CheckpointSave state snapshotStep 4: RebuildReconstruct contextRe-run budget check after overflow handlingStrategies: LRU eviction • importance scoring • sliding window • hierarchical summarization • RAG offload
Context overflow handling flow. When a new message would exceed the budget, the system runs a 4-step pipeline: prune low-relevance items, compress old turns, checkpoint current state, rebuild context.

Priority Queuing Strategies

Not all context items are equal. Priority queuing assigns a retention score to each item and evicts the lowest-scored items first when the budget is under pressure.

Priority Score Formula

A good priority score combines recency (newer items score higher), relevance (semantic similarity to current task), and type (tool results generally more valuable than conversational filler). A practical formula: score = (recency_weight × normalized_position) + (relevance_weight × cosine_similarity) + type_bias.

Type-Based Priority Tiers

  • TIER 0, Protected (never evicted): system prompt, current task specification, hard constraints from user, active in-progress reasoning.
  • TIER 1, High priority: last 3 conversation turns, most recent tool results, cited sources, explicit user decisions.
  • TIER 2, Medium priority: tool results from earlier steps, retrieved knowledge chunks, background context documents.
  • TIER 3, Low priority (first to evict): verbose explanations, intermediate reasoning steps, duplicate information, metadata blocks.
  • TIER 4, Purgeable: filler text, pleasantries, auto-generated commentary without substance.

Implementing Scored Eviction

python
from dataclasses import dataclass, field
from typing import Literal
import numpy as np

ContextTier = Literal[0, 1, 2, 3, 4]

@dataclass
class ContextItem:
    content: str
    tier: ContextTier
    position: int          # index in conversation, 0 = oldest
    token_count: int
    relevance: float = 0.5  # cosine similarity to current task

    @property
    def priority_score(self) -> float:
        tier_bias = {0: 100.0, 1: 10.0, 2: 5.0, 3: 1.0, 4: 0.1}
        recency = self.position / 100  # normalized 0–1
        return tier_bias[self.tier] + recency * 3.0 + self.relevance * 2.0

def evict_to_fit(
    items: list[ContextItem],
    token_budget: int,
) -> list[ContextItem]:
    """Remove lowest-priority items until total fits within budget."""
    total = sum(i.token_count for i in items)
    if total <= token_budget:
        return items

    # Sort by priority ascending, lowest priority evicted first
    sortable = sorted(
        [i for i in items if i.tier > 0],  # never touch tier 0
        key=lambda x: x.priority_score
    )
    protected = [i for i in items if i.tier == 0]

    result = list(sortable)
    while result and total > token_budget:
        evicted = result.pop(0)
        total -= evicted.token_count

    return protected + sorted(result, key=lambda x: x.position)

Context Overflow Handling

Even with good budgeting, overflow happens, especially in long-running autonomous agents where tasks expand unpredictably. A robust overflow handler must not lose information; it must transform it into a more compact form.

The Four-Step Overflow Pipeline

  • Step 1, Prune: Apply priority-based eviction to remove purgeable and low-priority items. Fast operation, no LLM required.
  • Step 2, Compress: Run extractive summarization on the oldest history window. Group turns into 2-turn batches and summarize each with a cheap model (haiku, mini).
  • Step 3, Checkpoint: Persist the full state to external storage before continuing. This creates a recovery point if the agent needs to restart.
  • Step 4, Rebuild: Reconstruct the context from protected items + summaries + recent raw turns. Verify the rebuilt context fits within budget before proceeding.

Checkpoint Storage Strategy

Checkpoints should be stored in fast key-value storage (Redis, DynamoDB) keyed by session ID and turn number. Include: full conversation history up to this point, all tool call results, the current task state, and the agent's working memory. Checkpoints enable resumption after crashes, budget-triggered restarts, and post-hoc debugging.

Multi-Agent Budget Sharing

In multi-agent systems, multiple agents may share a token budget for a single task. The orchestrator must coordinate budget allocation across workers, ensure no single agent starves others, and collect results efficiently.

Budget Allocation Patterns

  • Equal split: Divide the task budget evenly across all worker agents. Simple but inefficient, some tasks require more tokens than others.
  • Capability-weighted split: Allocate more budget to agents running complex reasoning tasks and less to simple extraction or formatting agents.
  • Demand-based allocation: Each worker requests the budget it needs before starting. The orchestrator approves, denies, or negotiates a smaller allocation.
  • Pool-based allocation: Maintain a shared token pool. Workers draw from the pool as needed. Risk: a runaway agent can exhaust the pool.
  • Hierarchical budgets: Each parent agent has a budget for itself and a child pool budget. Children get allocated from the pool, never from the parent's own budget.

Monitoring Budget Utilization

Budget monitoring closes the feedback loop. Without observability into how tokens are being spent, you're flying blind and can't identify which regions are bloated or which tasks are unexpectedly expensive.

Key Metrics to Track

  • context_utilization_pct: Percentage of total budget used at time of API call. Alert when > 85% consistently.
  • region_tokens_by_type: Token counts broken down by system_prompt, tools, memory, history, reserve. Identifies which region is growing fastest.
  • overflow_events_per_session: Count of times overflow handling was triggered per agent session. High values indicate structural budget misalignment.
  • compression_ratio: Tokens before vs after compression. Tracks compression efficiency over time.
  • tokens_wasted_on_pruned_items: Tokens spent computing content that was ultimately pruned. Indicates upstream inefficiency.

Prometheus Instrumentation

python
from prometheus_client import Histogram, Counter, Gauge

context_utilization = Histogram(
    "agent_context_utilization_pct",
    "Context window utilization percentage at API call time",
    ["agent_id", "task_type"],
    buckets=[0.3, 0.5, 0.6, 0.7, 0.8, 0.85, 0.9, 0.95, 1.0],
)

region_tokens = Gauge(
    "agent_context_region_tokens",
    "Token count by region in current context",
    ["agent_id", "region"],
)

overflow_events = Counter(
    "agent_context_overflow_total",
    "Number of context overflow events triggering compression",
    ["agent_id", "zone"],  # zone: yellow, red, critical
)

def record_context_snapshot(
    agent_id: str, task_type: str, budget: DynamicBudgetManager
) -> None:
    pct = budget.used / budget.total
    context_utilization.labels(agent_id, task_type).observe(pct)
    for region, tokens in budget._usage.items():
        region_tokens.labels(agent_id, region).set(tokens)

Common Budgeting Mistakes

Token budgeting is conceptually simple but practically tricky. Here are the mistakes that cause the most production incidents.

Mistake 1: Counting Tokens Too Late

The most common mistake is counting tokens after assembling the full context, by which point there's nothing to do except truncate crudely. Count tokens incrementally as each region is added, and make go/no-go decisions at each stage.

Mistake 2: Not Reserving Output Space

Many teams allocate the full context window to input and forget that the model needs room to generate output. If your context is 127,500 tokens in a 128K window, the model can only generate 500 tokens of response. Always reserve at least 1,500–2,500 tokens for output, more for tasks that require long structured responses.

Mistake 3: Ignoring Tool Definition Token Cost

Tool schemas are surprisingly expensive. A complex tool with nested parameters can cost 300–500 tokens. An agent with 20 registered tools might spend 6,000–8,000 tokens just on definitions. Use lazy tool registration: only include tools relevant to the current phase of the task.

Mistake 4: Different Tokenizers for Different Models

If you switch models mid-deployment (e.g., from GPT-4o to Claude), the tokenizer changes. GPT-4 and Claude have meaningfully different token counts for the same text. Always use the tokenizer that matches your current model, or you'll consistently misestimate your budget.

Frequently Asked Questions

Build secure agentic systems with AgentixForce

We help companies design, build, and secure production-grade AI agent systems. From architecture reviews to full implementation, our team brings deep expertise to every engagement.

More from Token Management

All articles
ORIGINAL12,400 tokensCOMPRESSextractiveSUMMARY1,800 tok-85.5%PROMPT COMPRESSION ENGINE
Token Management

Prompt Compression and Summarization Techniques That Preserve Meaning

Compressing long contexts without losing the information that matters. Techniques from extractive summarization to hierarchical compression that hold up under adversarial conditions.

10 min read
May 10, 2026
SLIDING CONTEXT WINDOWturn 1turn 2turn 3turn 4turn 5turn 6turn 7nowactive windowprunedCOMPRESSED SUMMARYturns 1–3 → 240 tokensDYNAMIC CONTEXT PRUNING
Token Management

Dynamic Context Pruning During Long Agentic Tasks

Not everything in a growing context window is still relevant. How to identify and remove stale context at runtime without breaking the agent's ability to complete its task.

9 min read
May 8, 2026
RAGFULL CONTEXTVECTOR DBqueryTOP-K+ cheap • scalable- retrieval miss riskALL DOCUMENTS+ no retrieval error- expensive • slowRAG vs FULL CONTEXT ARCHITECTURE
Token Management

RAG vs Full-Context: Choosing the Right Knowledge Architecture

Retrieval-augmented generation and full-context approaches have fundamentally different performance profiles. Here is the data you need to choose between them for your use case.

12 min read
May 6, 2026
CONTEXT GROWTH OVER TURNST115k tokT228k tokT345k tokT468k tokT595k tokT6118k tokT7128k tok⚠ LIMIT128k→ summarize + compact at turn 6MULTI-TURN TOKEN GROWTH
Token Management

Managing Token Limits in Multi-Turn Agentic Loops

Multi-turn agents accumulate context with every round trip. Strategies for sliding windows, checkpoint summarization, and conversation compaction that keep agents productive over long sessions.

10 min read
May 4, 2026
Context Window Budgeting Strategies for Long-Running Agents