LeetLLM
My PlanLearnGlossaryTracksPracticeBlog
LeetLLM

Your go-to resource for mastering AI & LLM systems.

Product

  • Learn
  • Glossary
  • Tracks
  • Practice
  • Blog
  • RSS

Legal

  • Terms of Service
  • Privacy Policy

© 2026 LeetLLM. All rights reserved.

All Topics
Your Progress
0%

0 of 158 articles completed

🛠️Computing Foundations0/9
Git, Shell, Linux for AIDocker for Reproducible AIPython for AI EngineeringNumPy and Tensor ShapesCUDA for ML TrainingMPS & Metal for ML on MacData Structures for AISQL and Data ModelingAlgorithms for ML Engineers
📊Math & Statistics0/8
Gradients and BackpropVectors, Matrices & TensorsLinear Algebra for MLAdam, Momentum, SchedulersProbability for Machine LearningStatistics and UncertaintyDistributions and SamplingHypothesis Tests, Intervals, and pass@k
📚Preparation & Prerequisites0/13
Neural Networks from ScratchCNNs from ScratchTraining & BackpropagationSoftmax, Cross-Entropy & OptimizationRNNs, LSTMs, GRUs, and Sequence ModelingAutoencoders and VAEsThe Transformer Architecture End-to-EndLanguage Modeling & Next TokensFrom GPT to Modern LLMsPrompt Engineering FundamentalsCalling LLM APIs in ProductionFirst AI App End-to-EndThe LLM Lifecycle
🧮ML Algorithms & Evaluation0/11
Linear Regression from ScratchLogistic Regression and MetricsDecision Trees, Forests, and BoostingReinforcement Learning BasicsValidation and LeakageClustering and PCACore Retrieval AlgorithmsDecoding AlgorithmsExperiment Design and A/B TestingPyTorch Training LoopsDataset Pipelines and Data Quality
📦Production ML Systems0/6
Feature Engineering for Production MLBatch and Streaming Feature PipelinesGradient Boosted Trees in ProductionRanking and Recommendation SystemsForecasting and Anomaly DetectionMonitoring Predictive Models
🧪Core LLM Foundations0/8
The Bitter Lesson & ComputeBPE, WordPiece, and SentencePieceStatic to Contextual EmbeddingsPerplexity & Model EvaluationFile Ingestion for AIChunking StrategiesLLM Benchmarks & LimitationsInstruction Tuning & Chat Templates
🧰Applied LLM Engineering0/24
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsContext EngineeringPrompt Injection DefenseResponsible AI GovernanceData Labeling and Human FeedbackEvaluating AI AgentsProduction RAG PipelinesHybrid Search: Dense + SparseReranking and Cross-Encoders for RAGRAG Evaluation for Reliable AnswersLLM-as-a-Judge EvaluationBias & Fairness in LLMsHallucination Detection & MitigationLLM Observability & MonitoringExperiment Tracking with MLflow and W&BPrompt Optimization with DSPyModel Versioning & DeploymentSemantic Caching & Cost OptimizationLLM Cost Engineering & Token EconomicsModel Gateways, Routing, and FallbacksDesign an Automated Support Agent
🎓Portfolio Capstones0/8
Capstone: Delivery ETA PredictionCapstone: Product RankingCapstone: Demand ForecastingCapstone: Image Damage ClassifierCapstone: Production ML PipelineCapstone: Document QACapstone: Eval DashboardCapstone: Fine-Tuned Classifier
🧠Transformer Deep Dives0/8
Sentence Embeddings & Contrastive LossEmbedding Similarity & QuantizationScaled Dot-Product AttentionVision Transformers and Image EncodersPositional Encoding: RoPE & ALiBiLayer Normalization: Pre-LN vs Post-LNMechanistic InterpretabilityDecoding Strategies: Greedy to Nucleus
🧬Advanced Training & Adaptation0/15
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineMixed Precision TrainingDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight Interpolation
🤖Advanced Agents & Retrieval0/16
Vector DB Internals: HNSW & IVFAdvanced RAG: HyDE & Self-RAGGraphRAG & Knowledge GraphsRAG Security & Access ControlStructured Output GenerationReAct & Plan-and-ExecuteGuardrails & Safety FiltersCode Generation & SandboxingComputer-Use / GUI / Browser AgentsHuman-in-the-Loop Agent ArchitectureAI Coding Workflow with AgentsAgent Memory & PersistenceAgent Failure & RecoveryRecursive Language Models (RLM)Multi-Agent OrchestrationCapstone: Production Agent
⚡Inference & Production Scale0/19
Inference: TTFT, TPS & KV CacheMulti-Query & Grouped-Query AttentionKV Cache & PagedAttentionPrefix Caching and Prompt CachingFlashAttention & Memory EfficiencyContinuous Batching & SchedulingScaling LLM InferenceModel Parallelism for LLM InferenceModel Quantization: GPTQ, AWQ & GGUFLocal LLM DeploymentSLM Specialization & Edge DeploymentSpeculative DecodingLong Context Window ManagementMixture of Experts ArchitectureMamba & State Space ModelsReasoning & Test-Time ComputeAdvanced MLOps & DevOps for AIGPU Serving & AutoscalingA/B Testing for LLMs
🏗️System Design Capstones0/9
Content Moderation SystemCode Completion SystemMulti-Tenant LLM PlatformLLM-Powered Search EngineVision-Language Models & CLIPMultimodal LLM ArchitectureDiffusion Models: Images & TextReal-Time Voice AI AgentReasoning & Test-Time Compute
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
Back to Topics
LearnInference & Production ScaleLong Context Window Management
🚀HardInference Optimization

Long Context Window Management

Master long-context LLM engineering: KV-cache math, prefill-vs-decode bottlenecks, RoPE scaling, lost-in-the-middle behavior, and long-context vs. RAG trade-offs.

37 min read
Learning path
Step 139 of 158 in the full curriculum
Speculative DecodingMixture of Experts Architecture

Speculative decoding showed how decode latency can improve when you avoid paying a full target-model pass for every emitted token. Long context pushes the same serving stack in a different direction: the model accepts far more input, but prefill work, KV-cache memory, and evidence placement become the bottlenecks.

Long context window management is the discipline of deciding what text enters a model, in what order, and with what compression. Larger windows still need careful evidence selection and evaluation.

Finding one failed-canary note inside a year's worth of service traces requires reading broadly because the answer could be anywhere. That's how a long-context model works when you hand it a massive document. The problem isn't just reading fast; it's holding the whole log in memory and still finding the detail that matters. Modern systems can accept far longer prompts than early 4K or 8K models, but fitting text into memory doesn't mean the model truly understands or uses all of it. The gap between advertised capacity and effective utilization is one of the biggest challenges in AI engineering today.

Why is extending context so hard? Because the attention mechanism that powers standard transformers compares every token to every other token during prompt ingestion, creating compute and memory costs that grow quickly with sequence length. Innovations like FlashAttention[1]Reference 1FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness.https://arxiv.org/abs/2205.14135 and efficient KV cache management[2]Reference 2Efficient Memory Management for Large Language Model Serving with PagedAttention.https://arxiv.org/abs/2309.06180 help, but the fundamental bottlenecks remain.

Three maps compare full attention, sliding-window attention, and retrieval packing over the same evidence stream. Three maps compare full attention, sliding-window attention, and retrieval packing over the same evidence stream.
Full attention exposes every position to the query. A sliding window limits visibility to a local band. Retrieval selects a smaller evidence set before generation, so reachability depends on the retriever.

Compare the three lanes. Full attention sees everything but pays the steepest memory and prefill cost. Sliding-window attention is cheaper but can't connect far-apart facts directly. Retrieval keeps the prompt small by selecting evidence before generation.

Why a longer window is harder than it looks

The context window is the total number of tokens a Large Language Model (LLM) can process in a single forward pass. This includes the system prompt, conversation history, retrieved documents, and the generated response.

The quadratic bottleneck

Standard full attention forms O(n2)O(n^2)O(n2) token-pair scores in sequence length nnn. In Big-O notation, that means doubling the number of events quadruples the number of pairwise checks. Extending a model's context from 4K to 128K therefore creates roughly 1,024x as many raw attention-score pairs during prefill. Optimized kernels reduce memory traffic and wall time; they don't remove that full-attention scaling law.

That all-pairs pattern is the first bill. The second bill arrives during decoding, when every generated token reads from the cached prefix. A long prompt is therefore both a compute problem and a GPU-memory scheduling problem.

Long-context prefill and KV-cache cost curve showing attention work and cache memory rising with sequence length. Long-context prefill and KV-cache cost curve showing attention work and cache memory rising with sequence length.
Longer prompts create two separate bills: prefill attention work rises fast, and the surviving KV cache keeps consuming memory and bandwidth during decode.
  • Compute: Prefill attention requires O(n2)O(n^2)O(n2) score computations per layer.
  • Memory: During decoding, the KV cache stores prior key/value vectors so the model doesn't recompute them every step.
  • Training and adaptation: Extending usable context usually requires continued training, careful RoPE scaling, or both. It's rarely just one config knob.

Memory in concrete numbers

Start with the scale before the formula. Consider an 80-layer decoder with 8 KV heads, 128-dimensional heads, BF16 KV tensors, and a 128K-token prompt. In BF16, each cached element takes 2 bytes.

Working through the numbers:

  • With GQA (8 KV heads): 2×80×8×128×131,072×22 \times 80 \times 8 \times 128 \times 131{,}072 \times 22×80×8×128×131,072×2 = 40 GiB per request
  • With full MHA (64 KV heads): 8x more KV heads means 320 GiB per request

Those are properties of this illustrative model configuration, not universal per-request numbers. A 40 GiB cache alone can consume a large serving memory budget before weights, activations, runtime buffers, or concurrent requests are accounted for.

The general formula that produced those numbers is:

KV cache size=2×num_layers×num_kv_heads×head_dim×seq_len×bytes_per_element\begin{aligned} \text{KV cache size} &= 2 \times \text{num\_layers} \times \text{num\_kv\_heads} \\ &\quad \times \text{head\_dim} \times \text{seq\_len} \times \text{bytes\_per\_element} \end{aligned}KV cache size​=2×num_layers×num_kv_heads×head_dim×seq_len×bytes_per_element​

That equation is per active sequence. To estimate the full working-set memory on a GPU, multiply again by the number of concurrent requests that are decoding at the same time.

kv-cache-capacity-budget.py
1def kv_cache_gib( 2 layers: int, 3 kv_heads: int, 4 head_dim: int, 5 sequence_tokens: int, 6 bytes_per_element: int, 7) -> float: 8 bytes_used = ( 9 2 * layers * kv_heads * head_dim * sequence_tokens * bytes_per_element 10 ) 11 return bytes_used / (1024**3) 12 13for label, heads, dtype_bytes in [ 14 ("GQA BF16", 8, 2), 15 ("GQA FP8", 8, 1), 16 ("MHA BF16", 64, 2), 17]: 18 cache = kv_cache_gib(80, heads, 128, 131_072, dtype_bytes) 19 print(f"{label}: {cache:.0f} GiB per active 128K sequence")
Output
1GQA BF16: 40 GiB per active 128K sequence 2GQA FP8: 20 GiB per active 128K sequence 3MHA BF16: 320 GiB per active 128K sequence

Prefill vs. decode: two different bottlenecks

Long-context serving hurts in two different phases.[2]Reference 2Efficient Memory Management for Large Language Model Serving with PagedAttention.https://arxiv.org/abs/2309.06180

  • Prefill: the model ingests the prompt. For full attention over long prompts, the quadratic attention pattern is a major cost.
  • Decode: the model generates new tokens. The KV cache avoids recomputing old projections, but each new token still attends to cached prefix state, so memory traffic and latency pressure grow with context length.

That split matters in production. FlashAttention directly reduces attention-kernel IO cost, with especially important impact on large prefills and time to first token (TTFT). PagedAttention, GQA, and KV-cache quantization address cache allocation or bytes stored per token. Prefix reuse can avoid repeated prefill for matching prefixes. Which change improves end-to-end latency or concurrency is a workload benchmark, not a label.

Attention variants that cut long-context cost

Another path is to change the attention pattern itself. Mistral 7B pairs GQA with sliding window attention (SWA), where each token attends only to a fixed local window instead of the entire prefix.[3]Reference 3Mistral 7B.https://arxiv.org/abs/2310.06825 If the window size is www, attention cost drops from O(n2)O(n^2)O(n2) to O(n×w)O(n \times w)O(n×w).

That trade-off is useful when dependencies are mostly local, such as code completion or document continuation. It's much weaker when the answer depends on direct access to far-away evidence anywhere in the prompt. Earlier sparse-attention designs explored similar local-plus-global patterns, but SWA is the easiest modern mental model: cheaper than full attention, not a full replacement for it.

A pure sliding window has a sharp failure mode worth knowing. Once the generated sequence grows past the cache size and earliest tokens are evicted, quality can collapse. Xiao et al. attributed this in their evaluated models to attention sinks: models place disproportionate attention on initial tokens, so removing them destabilizes generation.[4]Reference 4Efficient Streaming Language Models with Attention Sinkshttps://arxiv.org/abs/2309.17453 In their StreamingLLM experiments, retaining a small number of initial KV tokens alongside a recent window enabled stable long generation without fine-tuning. Treat sink count and quality as model-specific validation targets, not a fixed production constant.

When the input doesn't fit: truncation and compaction

Attention variants change how the model reads a window. The other half of management is deciding what to keep when the raw input is larger than the window at all. This is the daily reality of multi-turn chat and agent loops, where history grows every turn.

  • Truncation (sliding the buffer): drop the oldest turns until the prompt fits, while protecting the system prompt and the latest user message. This is cheap and predictable, but it throws away early facts permanently. Truncate by token count, never by character or message count, because token density varies wildly between text and code.
  • Summarization and compaction: instead of deleting old turns, replace them with a model-written summary. Compaction is the agent-loop version: when the running transcript nears a budget, fold the older steps into a compact state note and continue from there. This preserves more meaning per token than raw history but costs an extra model call and can lose details the summarizer judged unimportant.

The token-budgeting logic is the same either way: reserve room for the system prompt and the expected output, then fill the remainder from newest to oldest.

Diagram showing Reserve system + output budget, Newest turns fit?, yes, and Send packed prompt. Diagram showing Reserve system + output budget, Newest turns fit?, yes, and Send packed prompt.
Reserve system + output budget, Newest turns fit?, yes, and Send packed prompt.

Start by reserving non-negotiable space. If the remaining history doesn't fit, the value of the older turns decides the route: delete disposable turns, or compact still-relevant state before repacking the prompt.

when-the-input-simply-does-not-fit-truncation-and.py
1def fit_history( 2 messages: list[dict], 3 token_budget: int, 4 count_tokens, 5) -> list[dict]: 6 """Keep the system prompt plus the newest turns that fit the budget.""" 7 system = [m for m in messages if m["role"] == "system"] 8 turns = [m for m in messages if m["role"] != "system"] 9 10 used = sum(count_tokens(m["content"]) for m in system) 11 kept: list[dict] = [] 12 # Walk newest to oldest so recent context survives truncation. 13 for msg in reversed(turns): 14 cost = count_tokens(msg["content"]) 15 if used + cost > token_budget: 16 break 17 kept.insert(0, msg) 18 used += cost 19 20 return system + kept 21 22# Concrete example: a tiny word-count stand-in for a real tokenizer. 23def count_tokens(text: str) -> int: 24 return len(text.split()) 25 26history = [ 27 {"role": "system", "content": "You are an incident assistant."}, 28 {"role": "user", "content": "incident one with a fairly long trace summary"}, 29 {"role": "assistant", "content": "triaged incident one"}, 30 {"role": "user", "content": "what failed in canary"}, 31] 32 33kept = fit_history(history, token_budget=10, count_tokens=count_tokens) 34print([m["role"] for m in kept])
Output
1['system', 'user']

The older turns are dropped, but the system prompt and the most recent user message survive. When dropped turns still matter, swap the hard cut for a summarizer that compacts older turns into a short state note before they fall out of the budget.

How models keep track of position as sequences stretch

Transformers need a way to know where each word appears in a sequence, because their core attention mechanism processes all words simultaneously without any inherent sense of order (see our positional encoding article for the full treatment). Naively extending those position encodings beyond the training range usually degrades badly. Modern approaches use Rotary Position Embeddings (RoPE)[5]Reference 5RoFormer: Enhanced Transformer with Rotary Position Embedding.https://arxiv.org/abs/2104.09864 with various extension methods to push past this limit.

RoPE basics

RoPE behaves like a combination lock with multiple dials. Each dial rotates at a different speed. A token's position isn't one number; it's a specific combination of angles across many dimensions. To define a position twice as far away, the model rotates those existing dials farther. That rotational property lets attention represent relative distance rather than absolute position alone.

RoPE encodes position as rotations in 2D subspaces of the embedding dimension:

RoPE(xm,m)d=eimθd⋅xd\text{RoPE}(x_m, m)_d = e^{i m \theta_d} \cdot x_dRoPE(xm​,m)d​=eimθd​⋅xd​

Reading the formula

Each token's position mmm is encoded by rotating its embedding vector by an angle proportional to mmm. Different dimensions rotate at different frequencies θ\thetaθ: fast-rotating dimensions capture nearby relationships, while slow-rotating ones capture long-range dependencies. The advantage of this is that the relative distance between two positions becomes the rotation angle between them, making attention naturally distance-aware.

Position interpolation and NTK-aware scaling

Naively increasing the maximum position at inference time pushes RoPE angles far outside the range seen during training. The simplest fix is position interpolation: rescale positions so a target length LtargetL_{\text{target}}Ltarget​ is mapped back into the original training range LtrainL_{\text{train}}Ltrain​:

m′=m×LtrainLtargetm' = m \times \frac{L_{\text{train}}}{L_{\text{target}}}m′=m×Ltarget​Ltrain​​

That works surprisingly well, but it compresses every frequency band equally. NTK-aware (Neural Tangent Kernel) scaling is a refinement: it stretches the low-frequency dimensions more aggressively while keeping high-frequency dimensions closer to their original behavior. That preserves short-range precision better than uniform interpolation while still extending the usable context.

position-interpolation-budget.py
1def interpolate_position(position: int, trained_window: int, target_window: int) -> float: 2 """Map an extended position into the original coordinate range.""" 3 return position * trained_window / target_window 4 5trained_window = 8_192 6target_window = 32_768 7for position in [0, 8_192, 16_384, 32_767]: 8 mapped = interpolate_position(position, trained_window, target_window) 9 print(f"extended position {position:>5} -> trained coordinate {mapped:7.2f}")
Output
1extended position 0 -> trained coordinate 0.00 2extended position 8192 -> trained coordinate 2048.00 3extended position 16384 -> trained coordinate 4096.00 4extended position 32767 -> trained coordinate 8191.75

In practice, modern libraries usually expose these variants as configuration rather than handwritten trigonometric kernels. In Hugging Face Transformers, rope_parameters selects the scaling family, and the exact fields depend on rope_type. dynamic is the NTK-style option.[6]Reference 6Utilities for Rotary Embeddinghttps://huggingface.co/docs/transformers/main/internal/rope_utils

position-interpolation-and-ntk-aware-scaling.py
1from transformers import LlamaConfig 2 3config = LlamaConfig() 4config.rope_parameters = { 5 "rope_type": "dynamic", 6 "rope_theta": 10000.0, 7 "factor": 4.0, 8}

If you switch rope_type to "yarn", the config also carries YaRN-specific fields such as original_max_position_embeddings and, optionally, attention_factor.[6]Reference 6Utilities for Rotary Embeddinghttps://huggingface.co/docs/transformers/main/internal/rope_utils

RoPE frequency scaling diagram showing position rotations stretched beyond the original training range. RoPE frequency scaling diagram showing position rotations stretched beyond the original training range.
RoPE scaling remaps positions so longer contexts stay closer to the frequency patterns the model learned during training.

YaRN (Yet another RoPE extensioN)

YaRN combines NTK scaling with a temperature factor applied to attention logits and a smooth ramp function that treats different frequency bands differently.[7]Reference 7YaRN: Efficient Context Window Extension of Large Language Models.https://arxiv.org/abs/2309.00071

  • High-frequency dimensions: no interpolation (to preserve local position resolution).
  • Low-frequency dimensions: full interpolation (to extend range).
  • Middle frequencies: a smooth ramp between the two.

In the YaRN evaluation, this selective frequency treatment improved long-context perplexity over plain interpolation at aggressive extension ratios.[7]Reference 7YaRN: Efficient Context Window Extension of Large Language Models.https://arxiv.org/abs/2309.00071 New model families still need their own recall and loss evaluation.

Why the middle of a long prompt is hardest to remember

Liu et al. found that long-context retrieval accuracy was not uniform across positions in their evaluated tasks and models.[8]Reference 8Lost in the Middle: How Language Models Use Long Contextshttps://arxiv.org/abs/2307.03172 Relevant evidence often scored better near the beginning or end of a prompt than when buried in its middle.

It's like reviewing a very long incident timeline. The opening summary and closing decision are easy to remember, but events buried in the middle blur together. Long-context models often behave the same way: evidence at the edges is easier to recover than evidence buried in the middle. That's why important facts should sit near the beginning or end, not in the center alone.

What the curve looks like

Liu et al. report the same trend across many evaluations, even though the exact accuracy numbers vary by model and task:[8]Reference 8Lost in the Middle: How Language Models Use Long Contextshttps://arxiv.org/abs/2307.03172

PlacementTypical Pattern
Beginning of contextOften among the strongest positions
Middle of contextMost failure-prone
End of contextUsually recovers relative to the middle

Mitigation strategies

Strategic information placement

When a depth sweep shows middle-position misses, strategic evidence placement is one mitigation to test. Suppose you have five retrieved chunks about a failed deployment: two mention the first canary error, one is a generic runbook clause, one is a noisy log excerpt, and one is the final rollback approval. You want to test the canary evidence and rollback approval at the edges, with weaker details in the middle.

This Python function constructs an edge-packed candidate by placing the highest-ranked retrieved documents at the beginning and end, where the depth sweep suggests they may be easier to recover:

strategic-information-placement.py
1from dataclasses import dataclass 2 3@dataclass 4class Document: 5 text: str 6 relevance: float 7 8def arrange_context( 9 system_prompt: str, 10 retrieved_docs: list[Document], 11 user_query: str, 12 edge_budget: int = 4, 13) -> str: 14 """Construct an edge-packed candidate prompt for evaluation.""" 15 ranked_docs = sorted(retrieved_docs, key=lambda d: d.relevance, reverse=True) 16 17 # Keep the strongest few chunks near the edges, not buried in the middle. 18 edge_docs = ranked_docs[:edge_budget] 19 middle_docs = ranked_docs[edge_budget:] 20 head_docs = edge_docs[::2] 21 tail_docs = edge_docs[1::2] 22 23 context = [system_prompt] 24 context.extend(d.text for d in head_docs) 25 context.extend(d.text for d in middle_docs) 26 context.extend(d.text for d in reversed(tail_docs)) 27 context.append(user_query) 28 29 return "\n\n".join(context) 30 31# Concrete example 32docs = [ 33 Document("Rollback approved on 2024-03-15 by incident lead #42.", 0.95), 34 Document("Original canary error: auth callback returned 500.", 0.92), 35 Document("Deploy owner requested a staged rollback.", 0.88), 36 Document("Noisy log excerpt: cache warmed successfully.", 0.45), 37 Document("Generic rollback runbook clause 7B.", 0.30), 38] 39 40prompt = arrange_context( 41 system_prompt="You are an incident assistant. Answer using only the evidence below.", 42 retrieved_docs=docs, 43 user_query="Was the rollback approved?", 44) 45print(prompt)
Output
1You are an incident assistant. Answer using only the evidence below. 2 3Rollback approved on 2024-03-15 by incident lead #42. 4 5Deploy owner requested a staged rollback. 6 7Generic rollback runbook clause 7B. 8 9Noisy log excerpt: cache warmed successfully. 10 11Original canary error: auth callback returned 500. 12 13Was the rollback approved?

The generated candidate places high-relevance approval and canary notes at the head and tail, while the generic runbook clause stays in the middle. Compare this against an unchanged baseline prompt on the same evaluation set before adopting it.

Repeated key information

Include essential instructions or facts in both the system prompt (beginning) and just before the query (end).

Chunked processing

Process long documents in chunks and aggregate results rather than stuffing everything into one context.

Prompt packing visual: rank evidence, place strongest facts at head and tail, then probe recall and repack if needed. Prompt packing visual: rank evidence, place strongest facts at head and tail, then probe recall and repack if needed.
Use head and tail for highest-value evidence. Treat middle as weakest zone and test whether repacking improves recall.

The prompt is built like a sandwich. The strongest evidence touches the head and tail, while lower-priority support sits in the middle. If evaluation shows missed middle evidence, repack the prompt instead of assuming the model "saw" everything.

Long context vs. RAG: when to read everything and when to retrieve

The decision starts before prompting. Ask whether the evidence fits comfortably, whether it needs freshness or citations, whether queries repeat, and whether the answer requires reasoning over most of the selected evidence.

Decision guide for choosing long context, RAG, or a hybrid context strategy. Decision guide for choosing long context, RAG, or a hybrid context strategy.
Long context is a candidate when selected evidence fits and needs joint reasoning. Retrieval becomes a stronger candidate when freshness, citations, repetition, or corpus scale matter.

An important production decision is choosing between a large context window and retrieval-augmented generation (RAG).

You are choosing between selected-packet scanning and targeted section lookup. Long context passes the packed evidence to generation together, which can help joint reasoning but increases prefill input. RAG finds candidate pages first, which can shrink generation input but adds retriever failure modes and latency. For a single question about a short stable policy, long context can be the simplest baseline. For repeated questions, fresh data, or targeted lookup across a large archive, retrieval is a baseline worth measuring.

FactorLong ContextRAG
LatencyOne generation call, but large prefills can dominateRetrieval adds a stage, while smaller prompts can reduce generation cost
CostPays for packed input on each uncached requestPays for indexing/retrieval plus selected chunks
Failure modeEvidence is present but may be missed by position or distractorsNeeded evidence may never be retrieved
Corpus scaleBounded by usable prompt budgetSearches corpora larger than one prompt, subject to retrieval quality
Operational workPacking, caching, and context evaluationChunking, indexing, ranking, and retrieval evaluation

Repeated queries over the same large prefix are a special case. Even if the corpus fits, re-sending all of it on every turn is wasteful. That's where hybrid designs win: cache or retrieve reusable evidence first, then spend the long-context budget on the part that needs joint reasoning.

A concrete decision example

Suppose you have 200,000 tokens of service traces and a 128K context limit. You need to answer: "Which service emitted the most timeout errors in March?" That question requires scanning many March records, so a top-k retriever might omit counts. On the other hand, stuffing the whole log into one prompt exceeds the limit. A strong candidate is a hybrid: first filter or retrieve the March entries into a bounded subset, then aggregate over that packed subset and validate against known totals.

This Python function provides a decision framework for choosing between long context and RAG based on your specific constraints:

a-concrete-decision-example.py
1def choose_strategy( 2 corpus_size_tokens: int, 3 model_context_limit: int, 4 requires_global_reasoning: bool, 5 needs_freshness: bool, 6 repeated_queries: bool, 7) -> str: 8 """Choose between long context, RAG, and a hybrid pipeline.""" 9 10 fits_in_context = corpus_size_tokens <= model_context_limit 11 12 if needs_freshness: 13 return "hybrid" if requires_global_reasoning else "rag" 14 15 if not fits_in_context: 16 return "hybrid" if requires_global_reasoning else "rag" 17 18 if repeated_queries: 19 return "hybrid" if requires_global_reasoning else "rag" 20 21 return "long_context" 22 23# Concrete example 24strategy = choose_strategy( 25 corpus_size_tokens=200_000, 26 model_context_limit=131_072, 27 requires_global_reasoning=True, 28 needs_freshness=False, 29 repeated_queries=False, 30) 31print(strategy)
Output
1hybrid

This example returns hybrid. In this framing, hybrid means you first retrieve or cache the reusable evidence, then spend the long-context budget on the packed subset that still needs joint reasoning.

Cutting memory so long contexts fit on real GPUs

Long-context serving is bottlenecked by KV-cache memory.

Grouped query attention (GQA)

GQA (Grouped-Query Attention)[9]Reference 9GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints.https://arxiv.org/abs/2305.13245 lowers KV-cache bytes relative to otherwise comparable MHA by sharing key/value heads across query groups. Whether those saved bytes become a larger batch or lower latency depends on the serving bottleneck. It sits between two extremes:

  • MHA (Multi-Head Attention): each query head has its own dedicated key/value heads. That's the original Transformer design but requires storing a full KV-cache for every query head, which becomes prohibitively expensive at long contexts.
  • GQA: key/value heads are shared across groups of query heads. If an otherwise comparable architecture has 8x fewer KV heads than query heads, its KV-cache bytes fall by 8x; quality is a model-training and evaluation question.
  • MQA (Multi-Query Attention): a single set of key/value heads is shared across all query heads. This produces the smallest KV-cache among these three patterns, with quality trade-offs to evaluate.

See our MQA/GQA deep-dive for the full architecture details.

Architectures using GQA can materially reduce cache bytes; don't infer a quality result or supported concurrency from the head ratio alone.

kv-head-sharing-ratio.py
1def relative_kv_bytes(query_heads: int, kv_heads: int) -> float: 2 return kv_heads / query_heads 3 4query_heads = 64 5for label, kv_heads in [("MHA", 64), ("GQA", 8), ("MQA", 1)]: 6 fraction = relative_kv_bytes(query_heads, kv_heads) 7 print(f"{label}: {fraction:.3f}x MHA KV bytes ({1 / fraction:.0f}x smaller)")
Output
1MHA: 1.000x MHA KV bytes (1x smaller) 2GQA: 0.125x MHA KV bytes (8x smaller) 3MQA: 0.016x MHA KV bytes (64x smaller)

Quantized KV-cache

Storing Key and Value tensors in BF16 or FP16 is memory-intensive. One candidate, when your serving engine and model support it, is FP8 KV-cache quantization. Because each cached element drops from 2 bytes to 1 byte, the KV-cache footprint is roughly cut in half. Using the 40 GiB example above, the same 128K request would drop to about 20 GiB. Validate calibrated KV scales and quality on long-depth tasks rather than assuming a default scaling choice is adequate.

Cache dtypeBytes per cached elementRelative KV size
BF16 / FP162 bytes1.0x
FP81 byte~0.5x

The code snippet below shows vLLM configuration documented for FP8 KV cache. When checkpoint scales aren't available, calculate_kv_scales=True asks vLLM to estimate them during model warmup using random tokens. The current vLLM docs recommend dataset calibration through llm-compressor for highest quality; saved scales are loaded from the checkpoint when provided.[10]Reference 10Quantized KV Cachehttps://docs.vllm.ai/en/latest/features/quantization/quantized_kvcache/ Confirm support for your runtime version, model, and accelerator.

quantized-kv-cache.py
1from vllm import LLM 2 3llm = LLM( 4 model="your-org/your-model", 5 kv_cache_dtype="fp8", 6 calculate_kv_scales=True, 7)
kv-cache-admission-budget.py
1def admitted_sequences(memory_budget_gib: float, kv_per_request_gib: float) -> int: 2 return int(memory_budget_gib // kv_per_request_gib) 3 4cache_budget = 64.0 # example budget after reserving weights and runtime memory 5for dtype, kv_gib in [("BF16", 40.0), ("FP8 candidate", 20.0)]: 6 slots = admitted_sequences(cache_budget, kv_gib) 7 print(f"{dtype}: at most {slots} full-length request(s) in cache budget")
Output
1BF16: at most 1 full-length request(s) in cache budget 2FP8 candidate: at most 3 full-length request(s) in cache budget

PagedAttention (vLLM)

Contiguous reservation strategies can over-reserve memory or fragment it as requests grow and finish. PagedAttention manages the KV cache in non-contiguous blocks or "pages," much like an operating system manages virtual memory (see our KV cache and PagedAttention deep-dive for the full architecture). In the vLLM paper's evaluated design, allocation waste stayed below 4%.[2]Reference 2Efficient Memory Management for Large Language Model Serving with PagedAttention.https://arxiv.org/abs/2309.06180 That memory layout:

  • Reduces reservation and fragmentation waste by allocating fixed-size blocks on demand.
  • Enables memory sharing across requests with common prefixes.
  • Improves memory utilization, but it does not change the total KV bytes implied by model size and sequence length.
  • Enabled higher throughput in the vLLM paper's evaluated serving workloads.[2]Reference 2Efficient Memory Management for Large Language Model Serving with PagedAttention.https://arxiv.org/abs/2309.06180

Prefix reuse and prompt caching

Long-context workloads often resend the same static prefix: system instructions, repository guidelines, tool schemas, or long runbooks. Prefix sharing lets serving stacks reuse previously materialized prompt blocks across requests with common prefixes instead of recomputing every token from scratch.[2]Reference 2Efficient Memory Management for Large Language Model Serving with PagedAttention.https://arxiv.org/abs/2309.06180[11]Reference 11Automatic Prefix Cachinghttps://docs.vllm.ai/en/latest/features/automatic_prefix_caching/

This doesn't increase model quality or the true context limit. It cuts repeated prefill cost. When users ask many questions over the same large context, that often decides whether the long-context path is practical.

prefix-reuse-accounting.py
1def prefill_tokens_without_reuse(shared_prefix: int, unique_suffixes: list[int]) -> int: 2 return sum(shared_prefix + suffix for suffix in unique_suffixes) 3 4def prefill_tokens_with_reuse(shared_prefix: int, unique_suffixes: list[int]) -> int: 5 return shared_prefix + sum(unique_suffixes) 6 7shared_prefix = 48_000 8questions = [800, 1_200, 600] 9uncached = prefill_tokens_without_reuse(shared_prefix, questions) 10reused = prefill_tokens_with_reuse(shared_prefix, questions) 11print(f"uncached input tokens processed: {uncached:,}") 12print(f"with reusable prefix candidate: {reused:,}") 13print(f"avoided repeated prefix tokens: {uncached - reused:,}")
Output
1uncached input tokens processed: 146,600 2with reusable prefix candidate: 50,600 3avoided repeated prefix tokens: 96,000

Ring attention across multiple GPUs

PagedAttention helps use each device's KV allocation efficiently. It doesn't by itself solve the case where one request can't fit on one device. Ring Attention partitions blockwise attention across multiple devices and overlaps KV-block communication with blockwise attention computation. Its paper reports context scaling with additional devices in evaluated setups; communication and implementation overhead remain deployment constraints.[12]Reference 12Ring Attention with Blockwise Transformers for Near-Infinite Context.https://arxiv.org/abs/2310.01889

Testing whether a model truly uses its full window

One common stress test for effective context utilization is the NIAH (Needle-in-a-Haystack) evaluation.[13]Reference 13Needle In A Haystack: Pressure Testing LLMshttps://github.com/gkamradt/LLMTest_NeedleInAHaystack This test hides a specific fact ("the needle") at various positions ("depths") within a large amount of filler text ("the haystack") and asks the model to retrieve it.

By running this test across different context lengths (e.g., 4K to 128K) and different depths (0% to 100%), engineers generate a heatmap of model performance. A model that retrieves every tested needle produces a solid green heatmap. A position-sensitive model may show weaker middle-depth cells as context length increases. This visual is an illustrative failure surface, not a claimed score for a named model.

Illustrative needle-in-a-haystack heatmap showing miss rate increasing at middle depths as context length grows. Illustrative needle-in-a-haystack heatmap showing miss rate increasing at middle depths as context length grows.
A NIAH heatmap exposes whether the model can retrieve facts from every depth of the context window, not the beginning and end alone.

While NIAH is a good baseline, it's simplistic. Production long-context tasks require more than retrieving a single fact. Benchmarks like RULER[14]Reference 14RULER: What's the Real Context Size of Your Long-Context Language Models?https://arxiv.org/abs/2404.06654 expand the evaluation into longer synthetic tasks that test:

  1. Multi-needle retrieval: Finding multiple scattered facts.
  2. Multi-hop tracing: Synthesizing information from different parts of the context.
  3. Aggregation and question answering: Combining information across many retrieved facts before answering.

Another useful check is perplexity or next-token loss versus sequence length. If a long-context extension is healthy, loss should stay roughly stable instead of spiking as soon as you move beyond the original training window. Sharp jumps after RoPE or cache changes usually point to a configuration bug or distribution shift, rather than a harder benchmark alone.

A broader 2025 Chroma report tested 18 models and reported reliability degradation as input length grew, including on retrieval and copying tasks; it called this pattern context rot.[15]Reference 15Context Rot: How Increasing Input Tokens Impacts LLM Performancehttps://research.trychroma.com/context-rot The report also found worse results with distractors and less explicit query-answer relationships. Treat it as a reason to evaluate your chosen model and workload, not as one fixed accuracy curve. A bigger window permits more input; it doesn't prove that every added token helps.

depth-sweep-summary.py
1results = { 2 4_096: {0: True, 50: True, 100: True}, 3 131_072: {0: True, 50: False, 100: True}, 4} 5 6def weakest_depths(depth_results: dict[int, bool]) -> list[int]: 7 return [depth for depth, found in depth_results.items() if not found] 8 9for length, depth_results in results.items(): 10 misses = weakest_depths(depth_results) 11 print(f"{length:>6} tokens: missed depths={misses or 'none'}")
Output
14096 tokens: missed depths=none 2131072 tokens: missed depths=[50]

This Python code runs a basic Needle-in-a-Haystack evaluation. It tests whether the model can find a specific piece of information (the "needle") hidden at various positions within a large document:

testing-whether-a-model-truly-uses-its-full.py
1import torch 2from transformers import PreTrainedModel, PreTrainedTokenizerBase 3 4def build_token_budget_ids( 5 tokenizer: PreTrainedTokenizerBase, 6 filler: str, 7 token_budget: int, 8) -> list[int]: 9 """Repeat filler until token list reaches target budget.""" 10 filler_ids = tokenizer.encode(filler, add_special_tokens=False) 11 repeats = max(1, (token_budget // len(filler_ids)) + 1) 12 return (filler_ids * repeats)[:token_budget] 13 14@torch.inference_mode() 15def generate_answer( 16 model: PreTrainedModel, 17 tokenizer: PreTrainedTokenizerBase, 18 model_inputs: dict[str, torch.Tensor], 19 max_new_tokens: int = 32, 20) -> str: 21 """Run deterministic generation and return only the completion text.""" 22 inputs = {name: tensor.to(model.device) for name, tensor in model_inputs.items()} 23 output_ids = model.generate( 24 **inputs, 25 max_new_tokens=max_new_tokens, 26 do_sampling=False, 27 ) 28 completion_ids = output_ids[0, inputs["input_ids"].shape[1]:] 29 return tokenizer.decode(completion_ids, skip_special_tokens=True) 30 31def build_niah_inputs( 32 tokenizer: PreTrainedTokenizerBase, 33 instruction: str, 34 filler: str, 35 needle: str, 36 context_limit: int, 37 requested_depth: float, 38 max_new_tokens: int, 39) -> tuple[dict[str, torch.Tensor], float]: 40 """Build one exact token sequence inside the total context limit.""" 41 instruction_ids = tokenizer.encode(instruction, add_special_tokens=False) 42 needle_ids = tokenizer.encode(needle, add_special_tokens=False) 43 special_tokens = tokenizer.num_special_tokens_to_add(pair=False) 44 document_budget = ( 45 context_limit 46 - max_new_tokens 47 - len(instruction_ids) 48 - special_tokens 49 ) 50 if document_budget < len(needle_ids): 51 raise ValueError("context limit is too small for instruction, needle, and output") 52 53 haystack_ids = build_token_budget_ids( 54 tokenizer, 55 filler=filler, 56 token_budget=document_budget - len(needle_ids), 57 ) 58 insert_idx = int(len(haystack_ids) * requested_depth) 59 document_ids = ( 60 haystack_ids[:insert_idx] 61 + needle_ids 62 + haystack_ids[insert_idx:] 63 ) 64 combined_ids = instruction_ids + document_ids 65 model_inputs = tokenizer.prepare_for_model( 66 combined_ids, 67 add_special_tokens=True, 68 return_tensors="pt", 69 ) 70 71 input_tokens = model_inputs["input_ids"].shape[1] 72 assert input_tokens + max_new_tokens <= context_limit 73 actual_depth = insert_idx / max(len(haystack_ids), 1) 74 return model_inputs, actual_depth 75 76def needle_in_haystack_eval( 77 model: PreTrainedModel, 78 tokenizer: PreTrainedTokenizerBase, 79 context_lengths: list[int], 80 positions: list[float], 81) -> list[dict[str, object]]: 82 """Evaluate retrieval accuracy as needle depth and context length vary.""" 83 results = [] 84 needle = "The secret code is: RAINBOW-42" 85 filler = "Service trace log: span started, dependency called, status recorded." 86 instruction = "Read the document and return only the secret code.\n\n" 87 max_new_tokens = 32 88 89 for ctx_len in context_lengths: # total input-plus-generation limit 90 for requested_depth in positions: 91 model_inputs, actual_depth = build_niah_inputs( 92 tokenizer=tokenizer, 93 instruction=instruction, 94 filler=filler, 95 needle=needle, 96 context_limit=ctx_len, 97 requested_depth=requested_depth, 98 max_new_tokens=max_new_tokens, 99 ) 100 response = generate_answer( 101 model, 102 tokenizer, 103 model_inputs, 104 max_new_tokens=max_new_tokens, 105 ) 106 107 results.append( 108 { 109 "context_length": ctx_len, 110 "input_tokens": model_inputs["input_ids"].shape[1], 111 "requested_depth": requested_depth, 112 "actual_depth": actual_depth, 113 "found": "RAINBOW-42" in response, 114 } 115 ) 116 117 return results 118 119# Example run and sample output table 120sample_results = [ 121 {"context_length": 4096, "position": 0.0, "found": True}, 122 {"context_length": 4096, "position": 0.5, "found": True}, 123 {"context_length": 4096, "position": 1.0, "found": True}, 124 {"context_length": 131072, "position": 0.0, "found": True}, 125 {"context_length": 131072, "position": 0.5, "found": False}, # lost in the middle 126 {"context_length": 131072, "position": 1.0, "found": True}, 127] 128 129for r in sample_results: 130 status = "FOUND" if r["found"] else "MISS" 131 print(f"Length {r['context_length']}, depth {r['position']}: {status}")

Real evaluation harnesses usually sweep multiple filler templates, multiple needles, and multiple random seeds because exact distractor text still matters.

long-context-release-gate.py
1def approve_long_context_change( 2 baseline_middle_recall: float, 3 candidate_middle_recall: float, 4 p95_latency_ratio: float, 5 memory_ratio: float, 6) -> bool: 7 recall_ok = candidate_middle_recall >= baseline_middle_recall 8 latency_ok = p95_latency_ratio <= 1.10 9 memory_ok = memory_ratio <= 1.05 10 return recall_ok and latency_ok and memory_ok 11 12approved = approve_long_context_change( 13 baseline_middle_recall=0.86, 14 candidate_middle_recall=0.89, 15 p95_latency_ratio=1.06, 16 memory_ratio=1.02, 17) 18print(f"long-context candidate approved: {approved}")
Output
1long-context candidate approved: True

Mastery check

Check that you can:

  • Explain why extending context length is harder than only increasing a configuration limit.
  • Explain when sliding-window attention is a better fit than full attention, when it loses important far-away evidence, and why attention sinks keep windowed generation stable.
  • Decide between truncating and summarizing or compacting history when the raw input is larger than the window.
  • Describe the lost-in-the-middle effect and translate it into prompt-packing decisions.
  • Compare RoPE extension methods such as position interpolation, NTK-aware scaling, and YaRN.
  • Choose between long-context ingestion, RAG, and hybrid retrieval-plus-long-context reasoning for a production task.
  • Calculate KV-cache memory and map GQA, FP8 KV cache, PagedAttention, prefix reuse, and Ring Attention to the bottlenecks they address.

What strong answers show

  • Needs work: You treat advertised context length as proof the model can use every token, and you can't separate prefill cost from decode memory cost.
  • Developing: You can explain one bottleneck, such as lost-in-the-middle or KV-cache growth, but not how it changes prompt layout or serving design.
  • Solid: You can choose between long context, RAG, and hybrid retrieval for a concrete task and defend the choice with fit, freshness, and reuse constraints.
  • Strong: You can estimate KV-cache pressure, explain which optimizations help prefill versus decode, and design a prompt-packing fix for middle-position failures.
  • Excellent: You can propose an end-to-end validation plan that covers depth sweeps, multi-hop recall, latency, memory, and concurrency before approving a long-context product path.

Follow-up questions

A policy packet fits in 128K. Should you skip retrieval?

Not automatically. Use one packed prompt only when the answer depends on relationships across most of that packet and the source is stable enough to resend. If freshness, citations, or repeated queries matter, retrieval or a hybrid path is usually better even when the raw text technically fits.

Your model misses a rollback constraint that sits halfway through the prompt. What should you change first?

Treat it as a layout problem before you blame weights or temperature. Move the constraint to the head or tail, compress weaker middle evidence, and rerun the same question. If recall recovers, you were looking at lost-in-the-middle, not a lack of knowledge.

In the worked 80-layer configuration, a single 128K request uses about 40 GiB of BF16 KV cache. Why is that a product problem?

Because that memory is per active sequence. One long request can consume so much HBM that concurrency collapses even if single-request latency looks acceptable. Long-context serving is therefore capacity planning, admission control, and batching strategy, not model quality alone.

You turned on FP8 KV cache and cache capacity improved, but answer quality got worse at long depth. What should you verify next?

Check calibrated KV scales, long-depth retrieval, and multi-hop reasoning near the original window limit and beyond it. A smaller cache is only a win if the model still recovers the right evidence and supported kernels are active on your serving stack.[10]Reference 10Quantized KV Cachehttps://docs.vllm.ai/en/latest/features/quantization/quantized_kvcache/

How do you know a larger advertised window is truly usable?

You need a sweep, not one happy-path prompt. Run Needle-in-a-Haystack across multiple depths and lengths, then add multi-needle and synthesis tasks such as RULER so you can see whether the window still works when retrieval, aggregation, and distractors get harder.[14]Reference 14RULER: What's the Real Context Size of Your Long-Context Language Models?https://arxiv.org/abs/2404.06654

When long-context paths break down

  • Symptom: The model ignores instructions that sit halfway through a long prompt.

  • Cause: Important guidance was buried in the middle, where recall is weaker.

  • Fix: Move must-keep instructions to the head or tail, duplicate high-value facts near both edges, and rerun a depth-sensitive evaluation.

  • Symptom: A 128K request fits once, but throughput collapses when more users arrive.

  • Cause: KV-cache math was treated like a latency detail instead of a concurrency limit.

  • Fix: Estimate per-request cache bytes up front, then use GQA, FP8 KV cache, smaller batches, or shorter prompts before you promise capacity.

  • Symptom: A window extension appears to work on short demos, then produces gibberish at long depth.

  • Cause: RoPE scaling was changed without evaluating beyond the original training range.

  • Fix: Run perplexity and retrieval sweeps near and past the old limit, and prefer tested schemes such as NTK-aware scaling or YaRN over naive extrapolation.

  • Symptom: Sliding-window attention looks fast in benchmarks but misses far-away evidence in production.

  • Cause: Local attention was used for a task that needs global reasoning across distant spans.

  • Fix: Reserve sliding windows for mostly local dependencies, or switch to retrieval, hybrid packing, or full attention when far-apart facts must meet.

  • Symptom: Prompt truncation silently drops details that later turns still need.

  • Cause: History was trimmed by message count or characters instead of token budget and task importance.

  • Fix: Truncate by tokens, protect system instructions and recent turns, and compact older but still-relevant state into a summary before eviction.

What to carry forward

  1. Context window isn't effective context: A model can accept long input yet miss relevant information at some depths or under distractors. Test with depth sweeps and synthesis tasks before relying on a long-context path.

  2. RoPE scaling is controlled interpolation: position interpolation, NTK-aware scaling, and YaRN all try to extend range without destroying local resolution.

  3. Lost-in-the-middle is a production layout problem: place important information at the start and end of the context, not buried only in the middle.

  4. Long context and RAG solve different evidence problems: choose based on fit, freshness, query patterns, citation needs, and whether the task requires joint reasoning.

  5. Serving long context is both a prefill and decode problem: GQA, sliding-window attention, FP8 KV caches, PagedAttention, prefix reuse, and distributed attention are candidates to benchmark against your latency, quality, and capacity gates.

Long context window management sits between algorithms and systems engineering. RoPE scaling extends the model's positional range, but NIAH-style evaluations show whether the model uses that range reliably. KV-cache math then decides whether the result can run at acceptable latency and concurrency. The practical skill is connecting all three: position extension, evidence layout, and serving cost.

Complete the lesson

Mastery Check

Answer every question, then check your score. Score above 75% to mark this lesson complete.

1.A model accepts a 128K prompt without truncation. In a needle-in-a-haystack sweep, it finds the needle at 0% and 100% depth but misses the same needle at 50% depth as context grows. What conclusion should drive the next prompt design?
2.A full-attention model moves from a 4K-token prompt to a 128K-token prompt with the same architecture. Ignoring constant-factor kernel improvements, how do raw prefill attention-score pairs change?
3.For an 80-layer decoder with 8 KV heads, head_dim 128, BF16 cache elements, and seq_len 131,072, use KV bytes = 2 x layers x kv_heads x head_dim x seq_len x bytes_per_element. What serving implication follows?
4.A service repeatedly receives questions with the same 48K policy prefix. It also admits too few simultaneous decodes because KV cache fills HBM. Which interventions map to these problems?
5.You are considering sliding-window attention with a fixed local window. Which workload and risk assessment is accurate?
6.You have 200,000 tokens of service traces, a 128K model limit, and the question, 'Which service emitted the most timeout errors in March?' A naive top-k retriever may omit records needed for counts. Which strategy is most appropriate?
7.A model trained with an 8,192-token RoPE window is extended to 32,768 tokens by uniform position interpolation. What trained-coordinate does extended position 16,384 map to, and why might NTK-aware or YaRN-style scaling be preferred?
8.A chat prompt is nearing its token limit. The system prompt and latest user turn are mandatory, and early turns contain facts needed later. What packing plan should be used?
9.A serving system has fragmented KV-cache capacity on each GPU. Separately, one ultra-long request cannot fit its attention work on a single GPU. Which mapping addresses the two problems?
10.A team enables RoPE extension and FP8 KV cache, and short demonstration prompts still work. Which release evaluation can establish whether the change is safe for production?

10 questions remaining.

Next Step
Continue to Mixture of Experts Architecture

Long-context serving exposed how memory, communication, and request shape constrain dense models. Mixture-of-experts models add sparse routing and expert-capacity constraints, creating a different compute-versus-memory trade-off to measure.

PreviousSpeculative Decoding
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness.

Dao, T., Fu, D. Y., Ermon, S., Rudra, A., & Ré, C. · 2022 · NeurIPS 2022

Efficient Memory Management for Large Language Model Serving with PagedAttention.

Kwon, W., et al. · 2023 · SOSP 2023

Mistral 7B.

Jiang, A. Q., et al. · 2023

Efficient Streaming Language Models with Attention Sinks

Xiao, G., Tian, Y., Chen, B., Han, S., Lewis, M. · 2023 · ICLR 2024

RoFormer: Enhanced Transformer with Rotary Position Embedding.

Su, J., et al. · 2021

Utilities for Rotary Embedding

Hugging Face · 2026

YaRN: Efficient Context Window Extension of Large Language Models.

Peng, B., et al. · 2023

Lost in the Middle: How Language Models Use Long Contexts

Liu, N.F., et al. · 2023 · TACL 2023

GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints.

Ainslie, J., et al. · 2023 · EMNLP 2023

Quantized KV Cache

vLLM Team · 2026 · vLLM Documentation

Automatic Prefix Caching

vLLM · 2026

Ring Attention with Blockwise Transformers for Near-Infinite Context.

Liu, H., et al. · 2024 · arXiv preprint

Needle In A Haystack: Pressure Testing LLMs

Kamradt, G. · 2023

RULER: What's the Real Context Size of Your Long-Context Language Models?

Hsieh, C.-Y., et al. · 2024

Context Rot: How Increasing Input Tokens Impacts LLM Performance

Hong, K., Troynikov, A., & Huber, J. · 2025

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.