LLM Context Windows: What They Mean for System Design
Context window size shapes every architectural decision in LLM applications. This post covers how to reason about context allocation, the limits that still matter even with large windows, and the patterns that scale.
Context Windows Have Grown Enormously - and Still Matter
In 2020, GPT-3 had a 4,096-token context window. By 2024, Claude 3.5 Sonnet supported 200,000 tokens, and current frontier models offer as much or more. This growth might suggest context management is a solved problem. It is not.
Larger context windows shift but do not eliminate the constraints. Cost scales with context size. Latency increases. Performance on information buried deep in the context can be worse than information near the edges. And most importantly: dumping everything into the context is not the same as having the model reliably use it.
The Token Budget Framework
Every LLM call consumes tokens from a fixed budget. Allocate that budget explicitly:
pythondef build_rag_context( system_prompt: str, query: str, retrieved_chunks: list[str], max_context_tokens: int = 100_000, model: str = "claude-sonnet-4-6" ) -> str: import anthropic client = anthropic.Anthropic() # Measure what we have system_tokens = client.count_tokens(system_prompt) query_tokens = client.count_tokens(query) overhead = 500 # Buffer for formatting, separators, response available_for_context = max_context_tokens - system_tokens - query_tokens - overhead # Fill available context greedily (best chunks first) context_parts = [] used_tokens = 0 for chunk in retrieved_chunks: chunk_tokens = client.count_tokens(chunk) if used_tokens + chunk_tokens > available_for_context: break context_parts.append(chunk) used_tokens += chunk_tokens return "\n\n---\n\n".join(context_parts)
The "Lost in the Middle" Problem
Research shows that LLMs perform worse on information buried in the middle of a long context than on information near the start or end. The model "attends" more strongly to the beginning and end of the prompt.
Practical implications:
- Put the most important instructions at the start of the system prompt
- Put the most relevant retrieved chunks first (not last) in the context
- For very long contexts, consider chunking the context and running multiple calls
pythondef sort_chunks_for_context(chunks: list[dict]) -> list[dict]: """Put highest-relevance chunks at the beginning of the context.""" return sorted(chunks, key=lambda c: c.get("rerank_score", 0), reverse=True)
Prompt Caching: A Must for Long Contexts
When your system prompt or context is static (or changes infrequently), prompt caching reduces cost dramatically by caching the prefix:
pythonresponse = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, system=[{ "type": "text", "text": long_system_prompt_with_company_docs, "cache_control": {"type": "ephemeral"} # Cache this prefix }], messages=[{"role": "user", "content": user_query}] ) # First call: full input cost # Subsequent calls with same prefix: ~90% lower input cost
For a RAG system with a 50,000-token context that is 80% static knowledge and 20% per-query retrieval: prompt caching reduces the input token cost by ~80% after the first call.
Multi-Turn Conversation Context Management
In a multi-turn conversation, history grows indefinitely. Eventually it exceeds the context window. Strategies:
Sliding window: Keep only the last N turns.
pythondef trim_conversation(messages: list[dict], max_turns: int = 10) -> list[dict]: if len(messages) > max_turns * 2: return messages[-max_turns * 2:] return messages
Summarization: Summarize older history, keep recent turns verbatim.
pythondef compress_history(messages: list[dict], keep_recent: int = 5) -> list[dict]: if len(messages) <= keep_recent * 2: return messages older = messages[:-keep_recent * 2] recent = messages[-keep_recent * 2:] summary_prompt = "Summarize this conversation briefly:\n" + \ "\n".join(f"{m['role']}: {m['content'][:200]}" for m in older) summary = call_llm(summary_prompt, max_tokens=200) return [{"role": "user", "content": f"[Earlier conversation summary: {summary}]"}, {"role": "assistant", "content": "Understood."}] + recent
When Not to Use a Large Context Window
Large context windows enable new patterns - but they are not always the right tool:
- For many independent queries: Each query gets only the context it needs, not a 200K-token window of everything
- For real-time applications: 200K tokens × latency per token = slow responses; use RAG to retrieve only what matters
- When precision matters: A targeted 2,000-token context often produces better answers than a diluted 200,000-token context where the relevant information is 1% of the total
Large contexts are most valuable for: document analysis, long code review, comprehensive research synthesis. Not for standard chatbots or classification tasks.
Common Mistakes
Ignoring the "lost in the middle" effect. Research consistently shows that language models recall information placed at the very beginning or end of a long context much more reliably than information placed in the middle. If you concatenate retrieved chunks without considering position, the most relevant chunk may land in the middle and get underweighted. Experiment with placing high-priority content at the start or end of your context window.
Treating the full context window as free. Every token in the context window costs money at inference time and increases latency. A 128K-token window does not mean you should fill it - it means you can when necessary. Always measure whether expanding the context actually improves task performance before committing to large contexts in production.
Forgetting that KV cache memory scales quadratically with context length. The key-value cache used for efficient autoregressive generation grows as O(n^2) with sequence length, not linearly. At long contexts this becomes the dominant memory cost and can exceed the model weights themselves. Profile KV cache memory usage at your target context length before committing to hardware.
What to Practice Next
- Design a benchmark that places the same relevant fact at three positions in a long context (beginning, middle, end) and measures model accuracy at each position.
- Implement a sliding window chunker that respects token budgets and places the highest-similarity chunk first in the context; measure whether it improves answer accuracy on your eval set.
- Profile peak GPU memory at context lengths of 4K, 16K, 64K, and 128K for a model you deploy; plot the curve and identify the point where memory becomes the bottleneck.
Stay in the loop
Get new ML/AI lessons in your inbox.
No account needed. We will send curriculum updates, launch notes, and practical learning resources.
Related Posts
More postsFine-Tuning and Post-Training: LoRA, SFT, DPO, and Reasoning RL
What actually happens after pretraining, and when you should do any of it yourself. Parameter-efficient fine-tuning with LoRA, supervised fine-tuning data, preference optimization, and the reinforcement learning recipe behind reasoning models, with a decision framework and a project you can run on one GPU.
Common ML Architectures Reference: CNN, RNN, Transformer, MoE
A concise technical reference for the neural network architectures that power modern ML - what each one does, how it works, when to use it, and what to watch out for.
Building a Streaming API With LLMs
Streaming transforms LLM user experience - users see the first token in under a second instead of waiting for full generation. This post covers the implementation patterns for both server and client.