一个具体问题:答案明明在文档里,模型却答错了
假设你负责维护一个企业知识库问答系统,用户上传了一份 200 页的产品手册,然后提问:“TS-999 错误码的解决方法是什么?”你把这本手册全文塞进模型的上下文窗口,模型却给出了一个泛泛而谈的错误码排查建议,完全没有引用手册中明确写着的“重置网络配置”步骤。你检查了手册,答案确实在第 120 页。问题出在哪里?
一个常见的直觉是:只要上下文窗口足够大,模型就能“看到”所有信息。但实际表现并非如此。斯坦福大学等机构的研究者在 2023 年发表的一篇论文中,系统性地分析了语言模型在长上下文中的表现,发现了一个反直觉的现象:当相关信息位于输入上下文的中间位置时,模型的表现会显著下降,即使这些模型专门为长上下文设计。这篇论文就是后来广为人知的“Lost in the Middle”(迷失在中间)。
这个现象对工程实践有直接影响。在 RAG(检索增强生成)流水线中,我们通常会把检索到的多个文档片段拼接后放入提示词,而相关片段的位置往往取决于检索排序和拼接顺序。如果位置偏置导致模型忽略中间片段,那么即使检索召回正确,最终答案也可能错误。本文将以长文档问答为贯穿场景,解释位置偏置的成因、缓解策略以及工程取舍。
基线方案:把上下文全部塞给模型
在讨论位置偏置之前,先看一个最直接的基线方案:不做什么检索,直接把整个知识库或文档放入提示词。Anthropic 在 2024 年的一篇技术博客中提到,如果知识库小于 20 万 token(约 500 页材料),可以直接把整个知识库放进提示词,配合提示词缓存,可以显著降低延迟和成本。这个方案简单直接,但有两个限制:一是知识库规模受限,二是它同样受位置偏置影响——如果答案恰好在文档中间,模型可能仍然找不到。
更常见的方案是 RAG。RAG 的基本流程是:先把文档切分成小块(chunk),通常不超过几百个 token;然后用嵌入模型把每个块转换成向量;运行时,根据用户查询的语义相似度检索出最相关的几个块,拼接到提示词中。这个流程看似合理,但有两个隐患:第一,切块会破坏上下文,导致块本身缺乏必要的背景信息;第二,拼接顺序决定了相关块在提示词中的位置,而位置偏置可能让模型忽略中间的块。
位置偏置:开头和结尾表现好,中间表现差
“Lost in the Middle”论文(Liu 等,TACL 2024)通过两个任务验证了这一现象:多文档问答和键值检索。在多文档问答中,模型需要从多个文档中找出包含答案的文档并回答问题;在键值检索中,模型需要从上下文中找到某个键对应的值。研究者把相关信息放在上下文的不同位置(开头、中间、结尾),观察模型的表现。
结果发现,模型的准确率呈现出明显的 U 形曲线:当相关信息位于开头或结尾时,准确率最高;位于中间时,准确率显著下降。这个现象在多个模型上都有体现,包括那些专门为长上下文设计的模型。也就是说,即使模型声称支持很长的上下文,它对中间信息的利用仍然不稳健。
这个发现对工程实践意味着什么?在 RAG 流水线中,检索结果通常按相关性排序,最相关的块放在最前面,但拼接时可能会把多个块按顺序排列,相关块可能落在中间。如果模型对中间位置不敏感,那么即使检索正确,也可能因为位置不佳而回答错误。
成因一:注意力分布的不均衡
为什么模型会忽略中间信息?一个直接的解释是注意力机制。Transformer 模型通过自注意力计算每个 token 与其他 token 的相关性,但注意力权重并不是均匀分布的。在长上下文中,模型往往对开头和结尾的 token 给予更高的注意力权重,而对中间的 token 关注较少。
具体来说,位置编码(positional encoding)会影响注意力计算。模型在训练时,通常接触的序列长度有限,位置编码在训练长度内可能表现良好,但超出训练长度后,位置编码的泛化能力下降,导致模型对远距离位置的注意力权重不稳定。此外,训练数据中,文档的开头和结尾往往包含更重要的信息(如标题、摘要、结论),模型可能学会了这种统计规律,从而在推理时优先关注两端。
这种注意力分布的不均衡,可以理解为模型的一种“偏见”,它并非显式设计,而是从训练数据中习得的。在长文档问答中,如果答案位于中间,模型可能根本没有“注意到”它,就像人眼在阅读长文时容易忽略中间段落一样。
成因二:训练数据截断与长度外推
另一个重要成因是训练数据的截断。在训练大模型时,由于计算资源和显存限制,通常会对训练序列进行截断,只保留前 N 个 token。例如,如果训练时最大序列长度为 4096,那么超过 4096 的 token 根本不会被模型看到。这导致模型在训练时很少接触“中间”位置的信息,因为截断往往是从开头截取,中间和结尾的信息可能被丢弃。
这种训练方式导致模型对上下文中间位置的信息利用能力较弱。当推理时输入超过训练长度的上下文时,模型需要外推到未见过的长度,而位置编码的外推能力有限,进一步加剧了位置偏置。
值得注意的是,即使模型在训练时使用了较长的序列,如果训练数据中长序列的比例较低,模型对长上下文的利用能力也可能不足。这解释了为什么“显式长上下文模型”也会出现“Lost in the Middle”现象——它们可能只是扩展了上下文窗口,但并未从根本上改变对中间信息的处理方式。
缓解策略一:截断与重排
既然模型对中间位置不敏感,一个自然的思路是调整信息的摆放位置。最简单的方法是截断:只保留上下文开头和结尾的部分,把中间内容丢弃。但截断会丢失信息,如果答案在中间,截断后答案就没了,因此截断只适用于信息冗余的场景。
更实用的方法是重排(reordering):把最重要的信息放在开头或结尾。在 RAG 流水线中,我们可以根据检索得分对块进行排序,把最相关的块放在最前面(开头),次相关的放在后面(结尾),不相关的放在中间。这样可以利用模型对两端位置的偏好,提高答案的准确性。
重排的代价是额外的排序计算,但通常可以接受。然而,重排并不能完全解决问题,因为如果多个相关块都位于中间,重排后它们可能仍然被模型忽略。此外,重排可能会改变文档的逻辑顺序,影响模型对整体结构的理解。
缓解策略二:检索增强与上下文压缩
另一种思路是减少送入模型的上下文长度,只保留最相关的部分。这就是 RAG 的核心思想:通过检索,把长文档压缩成几个相关的块。但传统 RAG 有一个问题:切块时破坏了上下文,导致块本身缺乏背景信息。Anthropic 提出的“上下文检索”(Contextual Retrieval)方法,在切块后为每个块补充一段解释性上下文,再送入嵌入模型和 BM25 索引。例如,对于块“公司营收较上季度增长 3%”,补充上下文为“本块来自 ACME 公司 2023 年第二季度的 SEC 文件;上季度营收为 3.14 亿美元”。这样,检索时就能更准确地匹配查询,减少因缺乏上下文导致的检索失败。
上下文检索通过减少检索失败,间接缓解了位置偏置:因为检索到的块更精准,相关块的数量更少,更容易被放在开头或结尾。Anthropic 报告称,上下文检索可以将检索失败率降低 49%,结合重排序可降低 67%。这些数字来自 Anthropic 的博客,具体实验条件未完全公开,但可以作为参考。
另一种思路是上下文压缩:在送入模型前,用一个小模型对检索到的块进行摘要或提取关键信息,减少 token 数量。这样,即使位置偏置存在,模型也能从压缩后的短上下文中找到答案。但压缩可能会丢失细节,需要权衡。
缓解策略三:位置校准与训练改进
除了在推理时调整输入,还可以从模型本身入手。ACL 2024 上有一篇论文“Found in the middle: Calibrating Positional Attention Bias Improves Long Context Utilization”,提出通过校准位置注意力偏置来改善长上下文利用。具体来说,通过调整注意力权重或位置编码,使模型对中间位置的注意力增加,从而减轻位置偏置。
这种方法需要修改模型内部结构,通常需要微调或重新训练,成本较高,但可能从根本上解决问题。另一种训练改进是改变训练数据的采样方式,增加长序列和中间位置信息的比例,让模型在训练时更多地接触中间位置。这需要重新训练模型,成本更高。
对于大多数工程团队,修改模型内部结构并不现实,因此更实际的做法是在推理侧进行优化,如重排、上下文压缩或检索增强。
工程取舍:在 RAG 流水线中如何选择
在 RAG 流水线中,位置偏置的缓解策略需要根据场景权衡。下面是一个对比表格,总结了不同策略的优缺点:
| 策略 | 实现复杂度 | 对位置偏置的缓解效果 | 额外延迟 | 适用场景 |
|---|---|---|---|---|
| 截断 | 低 | 中(可能丢失信息) | 低 | 信息冗余,答案在两端 |
| 重排 | 低 | 中(依赖排序质量) | 低 | 检索结果多,需调整顺序 |
| 上下文压缩 | 中 | 中(可能丢失细节) | 中 | 上下文过长,需精简 |
| 上下文检索 | 中 | 高(减少检索失败) | 中 | 知识库大,切块上下文缺失 |
| 位置校准 | 高 | 高(需修改模型) | 无(推理时) | 模型可微调,追求根本解决 |
这个表格是定性比较,具体效果取决于模型和场景。在实际工程中,通常组合使用多种策略。例如,先使用上下文检索提高召回质量,再对检索结果进行重排,把最相关的块放在开头,最后送入模型。
贯穿场景:一个 RAG 流水线的改造
让我们回到开头的产品手册问答场景。假设我们有一个 RAG 流水线,流程如下:
flowchart TD
A[用户查询] --> B[向量检索]
A --> C[BM25检索]
B --> D[融合排序]
C --> D
D --> E[取Top-K块]
E --> F[拼接上下文]
F --> G[生成回答]
在这个流程中,融合排序后取 Top-K 块,然后拼接。如果 K 较大(比如 10),相关块可能位于中间。改造方案是:在拼接前,对 Top-K 块进行重排,把最相关的块放在开头,次相关的放在结尾,其余放中间。同时,对每个块补充上下文(如产品名称、章节标题),提高检索准确性。
改造后的流程如下:
flowchart TD
A[用户查询] --> B[向量检索]
A --> C[BM25检索]
B --> D[融合排序]
C --> D
D --> E[取Top-K块]
E --> F[补充上下文]
F --> G[重排: 相关块放两端]
G --> H[拼接上下文]
H --> I[生成回答]
重排的具体实现可以是:根据融合排序得分,把得分最高的块放在开头,得分次高的块放在结尾,其余按得分降序放在中间。这样,模型最可能关注的开头和结尾包含了最相关的信息。
可观测性与失败模式
在部署 RAG 系统时,需要监控位置偏置的影响。一个简单的方法是记录每次查询中答案所在块的位置,统计答案在开头、中间、结尾的分布。如果发现答案在中间时正确率明显低于两端,说明位置偏置严重,需要调整重排策略。
另一个可观测指标是检索命中率:检查检索到的块是否包含正确答案。如果检索失败,位置偏置无从谈起。Anthropic 的上下文检索方法就是为了提高检索命中率。
常见的失败模式包括:
- 检索结果中相关块排在后面,重排后仍然位于中间,模型忽略。
- 上下文压缩丢失关键细节,导致答案不完整。
- 位置校准方法在特定模型上不适用,因为模型结构不支持。
尚未解决的问题
位置偏置的根源尚未完全明确,注意力分布和训练数据截断是主要假设,但具体机制仍需进一步研究。此外,不同模型的位置偏置程度不同,目前没有统一的评估标准。对于工程实践,位置偏置提醒我们:上下文窗口大不等于利用得好,需要主动设计输入布局。
在 RAG 流水线中,位置偏置是众多权衡之一。重排、上下文检索、压缩等方法各有代价,需要根据业务场景选择。未来,随着模型训练方法的改进,位置偏置可能得到缓解,但在那之前,工程上仍需通过输入优化来应对。