AI Engineering & LLMs (50 Qs)•Part 1: RAG Architecture, Chunking & Vector Search
Context Window Stuffing & The Lost-in-the-Middle Phenomenon
1. The "Lost in the Middle" Effect in Modern LLMs
Research by Liu et al. revealed that LLMs do not process long contexts uniformly. Even in models supporting 128k–1M context windows (GPT-4o, Claude 3.5 Sonnet, Gemini 1.5 Pro), retrieval accuracy degrades sharply when critical ground-truth facts are located in the middle of a massive context prompt:
shell
Attention Accuracy U-Curve:
100% ──┐ ┌── 100%
│ │
│ │
50% ──┤ ├── 50%
│ "Lost in the Middle" Valley │
0% ──┴───────────────────────▼─────────────────────┴── 0%
Prompt Start Prompt End
(High Attention) (Degraded Attention) (High Attention)
2. Root Causes of Attention Attenuation
- Rotary Position Embeddings (RoPE) Decay: Relative positional encodings prioritize tokens placed near the system prompt (beginning) or near the generation target (end).
- Causal Masking: Autoregressive transformers attend backwards; information placed immediately before the final generation request is fresher in working attention memory.
3. Architectural Mitigation Strategies
| Mitigation Technique | Implementation | Benefit |
|---|---|---|
| Primacy/Recency Rerank Sorting | Place the top #1 and #2 most relevant chunks at the very end and beginning of the context block; middle holds lower-scoring chunks. | Overcomes U-shaped attention valley. |
| Context Compression / Summarization | Run small summarizers (e.g., flash models) over chunks before injection. | Reduces total token volume by 60–80%. |
| Targeted Chunk Filtering | Use strict re-ranker thresholds (e.g., score $> 0.75$) to discard irrelevant candidates rather than stuffing up to token limits. | Maximizes signal-to-noise ratio. |
python
def arrange_chunks_avoid_lost_in_middle(chunks: list) -> list:
"""Sorts chunks alternating between the ends of the prompt to maximize attention."""
# Assumes chunks are sorted descending by relevance score
sorted_chunks = sorted(chunks, key=lambda x: x["score"], reverse=True)
reordered = [None] * len(sorted_chunks)
left, right = 0, len(sorted_chunks) - 1
for i, chunk in enumerate(sorted_chunks):
if i % 2 == 0:
reordered[right] = chunk
right -= 1
else:
reordered[left] = chunk
left += 1
return reordered