Course Content
Live Coding Interview Prep
7 sections · 50 lessons
Handle "lost in the middle" by reordering context chunks.
What you need to know
The 2023 paper Lost in the Middle (Liu et al.) placed the one passage containing the answer at different positions among many distractors. Accuracy was highest with the answer first or last and dropped when it was in the middle — a U-shaped curve.
The mitigation follows directly. If a retriever returns chunks ranked best first, [c0, c1, c2, c3, c4], reorder them so the best ones sit at the edges:
position: 1st 2nd 3rd 4th 5thchunk: c0 c2 c4 c3 c1c0 (best) is first, c1 (second best) is last, and the weakest, c4, is in the middle.
How much it matters today: newer long-context models are much better at using the middle than the models in that paper, but degradation with long, noisy contexts has not disappeared. Treat it as a cheap default and test it, rather than a law.
1from typing import TypeVar23T = TypeVar("T")45def reorder_for_position_bias(chunks: list[T]) -> list[T]:6 """chunks ranked best first -> best at both ends, weakest in the middle."""7 front, back = chunks[0::2], chunks[1::2] # ranks 0,2,4,... and 1,3,5,...8 return front + back[::-1]910def build_context(chunks: list) -> tuple[str, list]:11 """Reorder, then number the chunks in their new order for citations."""12 ordered = reorder_for_position_bias(chunks)13 text = "\n\n".join(f"[{n}] {c.text}" for n, c in enumerate(ordered, 1))14 return text, orderedThe tricky parts:
- Slices
[0::2]and[1::2]take every other element starting at 0 and at 1: the even and odd ranks. Reversing the odd list puts rank 1 at the very end. - Renumber after reordering.
build_contextreturns the reordered list too, so[n]in the answer maps toordered[n - 1]. Numbering by the original rank would make every citation point at the wrong chunk. - Generic types —
Tsays the function works for any list of chunks and returns the same kind of items.
Complexity: two slices, a reverse and a concatenation, so O(n) time and O(n) space. No model call.
A real-life example
1print(reorder_for_position_bias(["c0", "c1", "c2", "c3", "c4"]))2# ['c0', 'c2', 'c4', 'c3', 'c1']3print(reorder_for_position_bias(["c0", "c1", "c2", "c3"]))4# ['c0', 'c2', 'c3', 'c1']5print(reorder_for_position_bias(["c0"]), reorder_for_position_bias([]))6# ['c0'] []Trace for five chunks:
| step | value |
|---|---|
| front = ranks 0, 2, 4 | [c0, c2, c4] |
| back = ranks 1, 3 | [c1, c3] |
| back reversed | [c3, c1] |
| result | [c0, c2, c4, c3, c1] |
The rank of the item at each position is 0, 2, 4, 3, 1: highest at the ends, lowest in the middle.
A legal-research assistant that sends 20 retrieved case excerpts to the model uses this ordering so the two strongest precedents are not buried at positions 9 and 11.
Follow-up questions to expect
- "What helps more than reordering?" — Sending fewer chunks. Re-rank and keep the top 3–5; there is no middle to get lost in. Also repeat the question after the context, so the instruction sits at the end.
- "When should you not reorder?" — When order carries meaning: consecutive pages of a contract, steps of a procedure, messages in a thread. Reordering those breaks the reading.
- "How do you know it helps your model?" — A needle-in-a-haystack test: put the answer chunk at each position, measure accuracy per position with and without reordering. A flat curve means you do not need it.