
摘要
“支持 128K 上下文”只说明模型能够接收这么长的输入,不说明它会同等利用每个位置。Liu 等人的 Lost in the Middle 把同一条答案证据依次放到长上下文的开头、中间和末尾,发现多类模型的表现常呈 U 形:首尾较好,中部较差。本文沿 TACL 论文与官方仓库,复现的不是某个动态模型分数,而是一套可审计协议:保持问题、答案证据、干扰文档集合与解码参数不变,只移动证据位置;同时扫描上下文长度,报告位置曲线、首尾—中部差值和最差位置。附带的标准库脚本验证数据构造与统计代码。它使用人为设定的命中概率,不是语言模型实验,不能外推为论文结果。
复现价值与目标:窗口长度不等于有效长度
长上下文评测最容易犯两个错误。第一,只把证据放在最后做一次 needle-in-a-haystack(大海捞针)测试,成功后便宣称“模型掌握全窗口”;第二,只报告所有样本的平均分,让首尾优势抵消中部失败。对于论文阅读、RAG 和代码仓库问答,关键证据的位置通常由检索排序、文档拼接和模板决定。如果移动同一证据就改变答案,系统测到的不只是知识或推理能力,还混入了位置敏感性。
本次目标有四个:读懂官方数据怎样保证恰有一个答案文档;建立长度与相对位置的二维扫描;把平均准确率和最差位置、位置差值一起报告;用平坦对照证明统计程序本身不会凭空画出 U 形。真正接入模型时,只替换 predict(),其余样本身份、排列、解析和聚合应保持冻结。
核心思想:把位置变成受控变量
设每个样本有问题 (q_i)、一个答案文档 (d_i^+) 和 (L-1) 个不含答案的干扰文档 (D_i^-)。在相对位置 (p\in[0,1]) 上,把答案文档放入索引
[ j=\operatorname{round}\bigl(p(L-1)\bigr),\qquad C_{i,L,p}=[d^-1,\ldots,d_i^+,\ldots,d^-{L-1}]. ]
(L) 是文档数,(j) 是从 0 开始的 gold index,(C_{i,L,p}) 是长度为 (L) 的文档序列。若 token 长度才是主变量,应先把每个文档裁到固定 token 预算,再记录 tokenizer、模板和实际输入长度;“20 篇文档”并不天然等于相同 token 数。
模型 (M_ heta) 在冻结提示与解码设置下输出 (hat y_{i,L,p})。对 (N) 个固定样本,位置准确率为
[ A(L,p)=\frac{1}{N}\sum_{i=1}^{N}\mathbf 1[\operatorname{norm}(\hat y_{i,L,p})\in Y_i], ]
其中 (Y_i) 是可接受答案集合,norm 是预注册的答案归一化。若一个 batch 同时包含 (B) 个样本、每个上下文有 (L) 篇文档,可把输入理解成文档张量 (X\in\mathbb{N}^{B\times L\times T}),(T) 是每篇裁剪后的 token 数;位置实验只改变 (L) 轴上的排列,不改变答案内容。
不要只给宏平均 (ar A_L=|P|^{-1}\sum_{p\in P}A(L,p))。还应报告
[ G_L=\frac{A(L,0)+A(L,1)}{2}-A(L,0.5),\qquad W_L=\min_p A(L,p), ]
(G_L) 是首尾均值相对中点的差,(W_L) 是最差位置。位置稳健模型应有较小 (G_L),而且随着 (L) 增大,(W_L) 不应突然坍塌。

论文与官方代码阅读路线
先读 TACL 2024 论文的任务设计,而不是先看模型排名。作者在多文档问答和键值检索两类任务中移动相关信息,观察开头、末尾与中间位置的差异。论文结论是其受测模型在位置改变时可能显著退化,常见模式为首尾高、中间低;这是特定模型、提示和 2023 年实验设置下的报告,不是所有新模型都必然如此。
再看官方仓库 README.md。qa_data/ 同时提供 oracle、10/20/30 文档设置;每条 ctxs 记录含 hasanswer、original_retrieval_index 和 isgold。生成脚本 make_qa_data_from_retrieval_results.py 先筛选不含标注答案的 distractor,再用 --gold-index 指定答案文档位置;README 给出的 20 文档示例扫描 0、4、9、14、19。这里最值得复用的不是某条命令,而是“同一检索候选集合只改变 gold index”的控制变量原则。
随后读预测与评分路径。EXPERIMENTS.md 把生成预测和 evaluate_qa_responses.py 分开;后者只取模型回答的第一行,调用 best_subspan_em,避免模型复制整段上下文投机命中。复现时应保存原始输出、解析后答案和逐样本分数;若只留下均值,无法区分模型没找到证据、生成了别名、还是解析器误判。
最后用 LongBench 和 RULER 扩展边界。LongBench覆盖问答、摘要、few-shot、代码等真实任务;RULER 在单针之外增加多针、变量追踪与聚合,并让长度和复杂度可配置。因此 Lost-in-the-Middle 是诊断切片,不是完整的长上下文能力定义:检索成功不等于跨证据推理成功,位置稳健也不等于事实忠实。
最小实验:先验证协议,不假装复现模型
运行:
python3 code/minimal_position_sweep.py
python3 code/minimal_position_sweep.py --check-only
脚本只用 Python 标准库,固定种子 62。对 20、40、80 篇文档和相对位置 0、0.25、0.5、0.75、1.0,各生成 800 个受控样本;每个上下文恰有一个 TARGET= 文档。u-shaped 模拟器以 SHA-256 派生确定性随机数,并人为令首尾命中率高、中间低、长度越长略降;flat-control 则令各位置概率近似相同。
本次 CPU smoke test 中,U 形模拟器在 20 文档的五个位置准确率为 0.955、0.675、0.574、0.680、0.931,宏平均 0.763,位置差 0.369;到 80 文档时分别为 0.887、0.630、0.465、0.630、0.856,宏平均 0.694,位置差 0.407。平坦对照在三种长度上的位置差绝对值均小于 0.02。断言同时检查唯一答案文档、索引映射、数值范围、U 形差值和长度退化。
这些结果只说明构造和聚合能检出“被写进模拟器”的位置效应。它们不是某个 LLM、NaturalQuestions、LongBench 或 RULER 的成绩。真正复现需锁定模型权重或 API 快照、tokenizer、chat template、精度、推理引擎、解码参数与样本文件哈希,并将真实输出接入同一评测表。
评测协议:二维扫描、配对比较、分层报告
第一步冻结样本。每个问题固定一组干扰文档,所有位置条件共享同一 example_id,这样可以做配对比较;不要为中间位置另抽一批更难的文档。答案字符串可能意外出现在干扰文档中,必须做规范化后的泄漏扫描。若真实检索结果本身含多个合理答案,应单列 ambiguous 子集,而不是把它伪装成单 gold。
第二步同时扫描位置与长度。位置至少覆盖首、四分之一、中点、四分之三、尾;长度应按实际 token 数分桶。每个单元格报告样本数、准确率或任务指标及置信区间,并给出配对 bootstrap 的 (G_L) 区间。若不同长度因截断丢失问题、指令或答案,这属于模板失败,不是位置效应。
第三步加入对照。oracle 仅给答案文档,closed-book 不给上下文,用来区分知识与检索;随机打乱干扰文档但保持 gold 相对位置,检查检索排序语义;把问题放在上下文前后各跑一次,测 instruction recency;保留答案内容不变但改写文档标题,测格式线索。所有对照必须在看结果前确定。
第四步分任务报告。精确键值检索适合 exact match,多文档问答需别名集合或 subspan 指标,摘要和跨文档推理应采用不同 rubric。总体均分不能证明每类任务稳健。成本也要记录:实际输入 token、输出 token、峰值显存、吞吐和失败重试次数;声明窗口长度时同时给出达到预设质量阈值的“有效长度”。
从协议模拟到真实模型:最小替换清单
接入开源模型时,先为每个条件导出 JSONL,而不是在推理循环里临时重排。每行至少保存 example_id、问题、答案集合、文档 ID 顺序、gold 文档 ID、gold 的文档索引、gold 的起止 token、总 token、模板版本和样本哈希。推理输出另存 raw_response、解析答案、终止原因、延迟与随机种子。这样同一个样本在五个位置的输出能一一配对,数据层、模型层和评分层也能独立重跑。
若使用 Hugging Face 模型,先打印 tokenizer 产生的最终张量形状,例如 input_ids.shape=[B,S];这里 (B) 是 batch 大小,(S) 是包含系统指令、文档和问题后的真实序列长度。检查 S 是否超过模型配置或推理引擎上限,并明确截断方向。对量化模型还要固定量化配置,因为精度变化可能与长度或位置交互。若使用 API,应记录可见模型快照、请求参数和响应元数据;无法冻结的服务只能标为“该日期的观测”。
最小真实实验不必一开始就追求 128K。可以先选一个本地可运行模型,在 4K、8K、16K 三档各取 100 个样本,五个位置一次性配对跑完;先人工审查每档十条,再扩大规模。预注册主要指标为 (G_L) 与 (W_L),宏平均作为辅助;若中点失败,抽取同一 example_id 的首、中、尾三份完整输入与输出做案例分析。只有重跑一致、解析无误且置信区间稳定后,才讨论模型机制或缓解方法。
结果目录也应可回放:保存配置文件、代码 commit、环境版本、输入哈希、逐样本预测和聚合脚本。不要只截图一条 U 形曲线。曲线必须能追溯到每个样本,失败案例必须能还原当时的完整 prompt;涉及私有文档时则保存脱敏后的结构等价样本和哈希,而不是泄露原文。
失败分析:先排协议错误,再谈注意力机制
若曲线异常锯齿,先查索引:相对位置映射是否取整一致,chat template 是否在某些长度触发截断,答案文档是否真的位于记录的 token 区间。文档序号不是 token 位置;前几篇更长时,“第 10 篇”可能并不在中点。应记录 gold 起止 token 和总 token,按相对 token 深度复画曲线。
若末尾特别强,可能来自 recency,也可能因为问题紧邻末尾文档;交换问题位置即可区分。若开头强而末尾弱,检查最大长度裁剪是否从尾部删除内容。若模型返回了正确长答案却 exact match 为零,抽查归一化、换行截断与别名集合。若中部退化只在真实问答出现、键值检索不出现,瓶颈可能是证据辨识或多步推理,而不是单纯“看不见中间”。
注意力热力图可以提出机制假设,但不能单独证明因果。Google Research 的 Found in the Middle 将位置偏差与注意力校准联系起来,是后续机制路线;对自己的模型仍需用位置干预、注意力或激活干预和下游指标共同验证。不要从一条 U 形性能曲线直接断言某层、某个位置编码就是原因。
后续科研问题
一是相对 token 深度、文档序号和语义检索排名,哪一个更能预测失败;二是多条相互支持或冲突的证据分布在不同位置时,位置效应如何交互;三是位置随机化训练能否改善最差位置而不损害首尾;四是 RAG 重排应优化相关性均值,还是优化长上下文模型的实际可用性;五是位置差 (G_L) 能否与校准、拒答和引用忠实度联合建模;六是“有效上下文长度”应按最差切片、平均切片还是任务风险定义。一个小而可靠的课题,是固定开源模型和多任务样本,对 gold token 深度、问题位置、证据数量做全因子实验,并公开逐样本输出。
总结
Lost-in-the-Middle 的核心不是“长上下文没用”,而是把“能接收”拆成“能稳定利用”。可靠复现要在同一批样本上只移动答案证据,扫描位置与长度,记录真实 token 深度,同时报告宏平均、最差位置和首尾—中部差。先用本文脚本检查数据与统计,再接真实模型;只有当位置、任务和复杂度切片都透明时,所谓长上下文能力才是可比较、可诊断的科研结论。
参考资料
检索日期:2026-09-04。以下均为论文、会议页面、研究机构页面或官方代码;动态模型、API 行为和榜单待人工核验。
- Nelson F. Liu 等,2024,Lost in the Middle: How Language Models Use Long Contexts(TACL)
- Nelson F. Liu 等,Lost in the Middle 官方仓库、实验命令、位置数据生成脚本与问答评分脚本
- Yushi Bai 等,2024,LongBench: A Bilingual, Multitask Benchmark for Long Context Understanding(ACL)与官方仓库
- Cheng-Ping Hsieh 等,2024,RULER: What's the Real Context Size of Your Long-Context Language Models?(COLM / arXiv)、官方仓库与
run.sh - Huiqiang Jiang 等,2024,Found in the Middle: Calibrating Positional Attention Bias Improves Long Context Utilization(Google Research)