第9章 上下文管理与压缩

39 阅读45分钟

随着大语言模型(LLM)上下文窗口的不断扩展,从早期的4K token到如今的百万级token,如何有效管理和利用这些上下文资源已成为RAG系统设计的核心挑战。上下文管理不仅关乎检索结果的质量,更直接影响模型的推理能力和最终输出的准确性。本章将深入探讨上下文管理的各项技术,从长上下文处理的本质挑战出发,系统性地介绍上下文压缩、选择性上下文、动态调整、长文档RAG解决方案以及新兴的Context Engineering范式,为企业级RAG系统的架构设计提供全面的技术指南。

 

9.1 长上下文处理的挑战

在RAG系统中,检索器从知识库中召回的相关文档片段通常需要与用户的查询一起输入到大语言模型中进行处理。然而,随着检索范围的扩大和文档数量的增加,输入上下文的规模迅速膨胀,给模型带来了前所未有的处理压力。研究表明,即使是最先进的大语言模型,在面对超长上下文时也会表现出显著的性能衰减,这一现象被称为"Lost in the Middle"。

Liu等人在2023年发表的研究(arXiv:2307.03172)首次系统性地揭示了这一现象。他们发现,当相关信息位于输入序列的中间位置时,模型的检索准确率会显著下降,降幅可超过20%。这一发现对RAG系统的设计具有深远影响:简单地增加检索到的文档数量并不能保证更好的回答质量,反而可能因为关键信息被淹没在长上下文的"中间地带"而导致性能下降。

"Lost in the Middle"现象的产生源于Transformer架构中自注意力机制的内在特性。注意力机制在处理长序列时,每个token需要与序列中的所有其他token计算注意力分数,这导致计算复杂度随序列长度呈平方级增长。更重要的是,研究表明模型对位置信息存在固有的偏差——模型倾向于更加关注序列的开头和结尾部分,而对中间位置的信息关注度相对较低。这种位置偏差在RAG场景中尤为致命,因为关键的证据信息可能来自检索结果中的任何位置。

与"Lost in the Middle"密切相关的是Context Rot(上下文腐烂)现象。Chroma Research在2025年的研究中指出,随着对话轮次的增加和上下文的累积,早期引入的信息会逐渐"腐烂",即模型对这部分信息的利用效率持续下降。这一现象在多轮对话RAG和长期记忆系统中表现得尤为明显。上下文腐烂不仅降低了系统的回答质量,还可能导致模型产生幻觉或给出自相矛盾的答案。

注意力预算的有限性是另一个关键挑战。尽管现代LLM的上下文窗口不断扩展,但模型的"注意力预算"——即能够有效关注和处理的信息量——并没有同步增长。研究表明,即使上下文窗口扩展到100万token,模型实际能够有效利用的信息量仍然有限。这意味着在RAG系统中,我们需要更加智能地选择和组织输入给模型的上下文内容,而不是简单地堆砌所有检索到的文档。

计算成本与延迟的线性增长也是长上下文处理面临的重要挑战。虽然注意力机制的计算复杂度理论上是O(n²),但在实际部署中,随着上下文长度的增加,推理延迟和计算成本都呈现近似线性的增长趋势。对于需要实时响应的RAG应用,过长的上下文会显著增加用户等待时间,影响用户体验。此外,API调用的成本通常与输入token数量成正比,这意味着不加控制的上下文长度会直接导致运营成本的上升。

除了上述挑战,KV Cache的内存占用问题也不容忽视。在Transformer推理过程中,模型需要缓存每一层的Key和Value矩阵以避免重复计算,这就是KV Cache。随着上下文长度的增加,KV Cache的内存占用呈线性增长,成为限制批处理大小和并发能力的主要瓶颈。最新的研究提出了多种KV Cache压缩技术,包括量化、剪枝和分页管理,但这些技术都增加了系统的复杂性。

表9-1 长上下文处理的主要挑战

挑战类型具体表现影响程度应对策略方向
Lost in the Middle中间位置信息检索准确率下降>20%重排序、信息压缩
Context Rot早期信息随时间衰减中高动态更新、记忆机制
注意力预算有限有效处理信息量存在上限选择性注意力、上下文过滤
位置偏差模型偏向序列首尾信息位置编码优化、重排序
计算成本增长延迟与成本随长度线性增加上下文压缩、分层处理
内存占用KV Cache随长度线性增长KV Cache压缩、分页技术

 

表9-1a 不同上下文长度下的"Lost in the Middle"效应

上下文长度开头准确率中间准确率结尾准确率平均衰减
4K tokens95%88%94%7%
8K tokens93%82%92%11%
16K tokens90%75%89%15%
32K tokens87%68%86%19%
64K tokens83%62%84%21%
128K tokens80%58%82%22%

 

9.2 上下文压缩技术

面对长上下文带来的诸多挑战,上下文压缩技术应运而生。这类技术的核心目标是在保留关键语义信息的前提下,显著减少输入token的数量,从而降低计算成本、缩短推理延迟,并缓解"Lost in the Middle"现象。上下文压缩技术的发展经历了从简单的截断策略到基于深度学习的智能压缩的演进过程。

LLMLingua是由微软亚洲研究院Jiang等人于2023年提出的开创性工作(arXiv:2310.05736,EMNLP 2023)。该方法采用基于困惑度(Perplexity)的粗到细提示压缩策略,通过一个小型语言模型(如GPT-2或LLaMA-7B)来识别和移除提示中的冗余信息。LLMLingua的核心洞察是:在保留关键信息的前提下,可以安全地移除大量不影响模型理解的token。实验表明,LLMLingua能够实现最高20倍的压缩比,同时在多种任务上保持与原始提示相近的性能。

LLMLingua的压缩过程分为三个阶段:首先是粗粒度压缩,通过困惑度评估识别并移除低信息量的token;然后是细粒度压缩,利用条件概率进一步筛选关键token;最后是预算控制,根据预设的压缩比例动态调整压缩策略。这种分层压缩策略确保了在最大化压缩率的同时,尽可能保留对任务完成至关重要的信息。

LLMLingua-2是LLMLingua的后续工作,由Pan等人于2024年提出(arXiv:2403.12968,Findings of ACL 2024)。与第一代方法不同,LLMLingua-2采用基于数据蒸馏的任务无关压缩策略。研究者通过从大型语言模型中蒸馏压缩知识,训练了一个专门的token分类器,能够以极快的速度完成提示压缩。实验结果显示,LLMLingua-2的压缩速度比第一代提升了3-6倍,同时保持了相当的压缩质量。这一改进使得LLMLingua-2更适合实时RAG系统的部署需求。

LongLLMLingua是专门针对长上下文RAG场景优化的压缩方法(arXiv:2310.06839,ACL 2024)。该方法在LLMLingua的基础上引入了问题感知的压缩策略,通过分析问题与文档之间的关系,优先保留与问题最相关的信息。在LongBench等长上下文基准测试上,LongLLMLingua相比基线方法取得了21.4%的性能提升。这一成果证明了在压缩过程中融入任务相关信息的重要性。

Selective Context是另一种重要的上下文压缩方法,它基于自信息量(Self-Information)进行内容过滤。该方法通过计算每个token或短语的自信息量,识别并移除低信息量的内容。与基于困惑度的方法相比,Selective Context更加关注信息论意义上的内容重要性,在某些场景下能够取得更好的压缩效果。此外,Selective Context还支持多种粒度(token级、短语级、句子级)的压缩,为不同应用场景提供了灵活的选择。

综合来看,现有的提示压缩方法可以根据压缩依据、压缩粒度和是否任务相关进行分类。从压缩依据来看,主要包括基于困惑度、基于自信息量、基于嵌入相似度和基于学习的方法;从压缩粒度来看,包括token级、短语级、句子级和段落级压缩;从任务相关性来看,包括任务无关的通用压缩和任务感知的定向压缩。理解这一分类体系有助于在实际应用中选择最适合的压缩策略。

在实际应用中,选择合适的压缩方法需要综合考虑多个因素。对于实时性要求高的场景,LLMLingua-2等快速压缩方法更为适合;对于需要深度理解的长文档场景,LongLLMLingua的问题感知压缩能够带来更好的效果;而对于信息密度较低的文档,Selective Context的自信息量方法可能更加有效。此外,压缩率的选择也需要权衡——过高的压缩率可能导致关键信息丢失,而过低的压缩率则无法充分发挥压缩技术的优势。实验表明,20%-50%的压缩率(即保留50%-80%的原始token)通常能够在性能和效率之间取得较好的平衡。

表9-2 主要上下文压缩方法对比

方法名称核心机制压缩依据最大压缩比速度优势适用场景
LLMLingua困惑度评估+粗到细压缩困惑度20x中等通用RAG场景
LLMLingua-2数据蒸馏的token分类学习得到的策略20x3-6x更快实时RAG系统
LongLLMLingua问题感知压缩问题相关性15x中等长文档RAG
Selective Context自信息量过滤自信息量10x信息密集型文档
Gist学习gist token任务嵌入5x重复查询场景
ICAE自编码器压缩重构损失4x中等长上下文建模

 

表9-2a LLMLingua系列方法性能对比(LongBench基准)

方法平均压缩率QA任务保留率Summ任务保留率处理速度(tokens/s)
原始提示100%100%100%N/A
Random Drop50%72%68%10000+
Truncation50%78%75%10000+
Selective Context50%85%82%5000
LLMLingua50%91%88%2000
LLMLingua-250%93%90%12000
LongLLMLingua50%95%92%1800

 

代码示例9-1:使用LLMLingua进行提示压缩


from llmlingua import PromptCompressor  
  
# 初始化压缩器  
compressor = PromptCompressor(  
    model_name="microsoft/llmlingua-2-xlm-roberta-large-meetingbank",  
    use_llmlingua2=True  
)  
  
# 原始长上下文  
context = """  
[此处为检索到的多个长文档片段,总长度可能达到数万token]  
文档1:关于人工智能发展的历史...  
文档2:机器学习基础理论介绍...  
文档3:深度学习在计算机视觉中的应用...  
"""  
  
# 用户查询  
question = "深度学习在图像识别中的最新进展是什么?"  
  
# 执行压缩  
compressed_prompt = compressor.compress_prompt(  
    context=context,  
    question=question,  
    rate=0.5,  # 压缩率目标:保留50%的token  
    force_tokens=['深度学习', '图像识别', 'CNN', 'Transformer'],  
    drop_consecutive=True  
)  
  
print(f"原始长度: {compressed_prompt['origin_tokens']} tokens")  
print(f"压缩后长度: {compressed_prompt['compressed_tokens']} tokens")  
print(f"压缩比: {compressed_prompt['rate']:.2f}x")  
print(f"压缩后内容: {compressed_prompt['compressed_prompt'][:500]}...")

9.3 选择性上下文:只保留最相关的信息

选择性上下文(Selective Context)代表了一类与压缩技术互补但侧重点不同的上下文管理策略。与压缩技术关注如何"压缩"信息不同,选择性上下文更关注"选择"——从大量候选内容中筛选出最相关、最有价值的信息呈现给模型。这一策略的核心理念是:质量优于数量,精心选择的少量高质量上下文往往比大量低相关性的内容更能帮助模型生成准确的回答。

基于信息熵的选择性过滤是选择性上下文的基础方法。信息熵作为信息论中的核心概念,量化了信息的不确定性。在上下文选择的场景中,高信息熵的内容通常意味着更高的信息量和更低的可预测性,因此更有可能包含有价值的知识。通过计算每个文档片段或句子的信息熵,我们可以对候选内容进行排序,优先选择信息熵较高的内容。

问题感知的上下文选择(Question-Aware Selection)是一种更高级的选择策略。这种方法不仅考虑内容本身的信息量,还考虑内容与用户问题的相关性。具体实现时,系统会计算每个候选文档片段与问题之间的语义相似度,通常使用预训练的嵌入模型(如BERT、Sentence-BERT或专门的RAG嵌入模型)将文本映射到向量空间,然后通过余弦相似度或其他距离度量评估相关性。与问题最相关的片段将被优先选择。

Relevancy-Based过滤与重排序是RAG系统中常用的选择性策略。在标准的RAG流程中,检索器首先基于向量相似度召回Top-K个候选文档。然而,向量相似度并不总是与任务相关性完全一致。因此,许多系统引入了重排序(Reranking)阶段,使用更精确的交叉编码器(Cross-Encoder)模型对候选文档进行精细的相关性评分,然后基于这些评分进行过滤和排序。这种方法能够显著提升检索结果的质量。

上下文嵌入(Contextual Embeddings)为选择性上下文提供了更丰富的语义表示。传统的句子级嵌入可能无法捕捉长文档中的复杂语义结构和细粒度的主题信息。上下文嵌入技术通过考虑文档的全局结构和局部上下文,生成更加语义丰富的表示。例如,一些方法使用分层嵌入策略,同时编码文档级、段落级和句子级的信息;另一些方法则利用图神经网络建模文档内部的结构关系。这些丰富的嵌入表示支持更精细的选择策略。

动态上下文选择策略代表了选择性上下文的最新发展方向。与静态的选择策略(如固定选择Top-K个片段)不同,动态策略根据查询的复杂度、可用上下文的特性以及模型的能力自适应地调整选择行为。例如,对于简单的事实性问题,可能只需要选择1-2个最相关的片段;而对于复杂的推理问题,则可能需要选择更多片段以提供充分的上下文支持。一些先进的系统还会根据中间推理结果动态调整后续的选择策略,实现真正的交互式上下文管理。

在实际系统设计中,选择性上下文策略的实施需要考虑计算效率与选择精度的权衡。高精度的选择方法(如基于交叉编码器的重排序)虽然能够提供更准确的相关性评估,但计算开销较大,可能成为系统瓶颈。因此,生产级系统通常采用多阶段选择策略:首先使用轻量级的向量相似度进行粗筛,快速过滤掉明显不相关的内容;然后对剩余的候选内容应用更精确但计算密集的方法进行细筛。这种级联式的选择架构能够在保证选择质量的同时,控制整体的计算成本。

表9-3 选择性上下文策略对比

策略类型选择依据实现复杂度优势局限性
信息熵过滤内容的信息量无需监督,通用性强可能选择无关但复杂的内容
问题感知选择与问题的语义相似度直接优化任务相关性依赖嵌入质量
重排序过滤交叉编码器评分精度高,可解释性好计算开销较大
上下文嵌入多层次语义表示捕捉复杂语义关系需要大量训练数据
动态选择自适应策略调整灵活适应不同场景策略设计复杂

 

表9-3a 主流重排序模型性能对比

模型参数量MS MARCO MRR@10Latency(ms)适用场景
BGE-Reranker-Base110M38.515轻量级应用
BGE-Reranker-Large560M42.135通用场景
Cohere RerankAPI45.2API延迟企业级应用
Jina Reranker110M40.312实时应用
bce-reranker-base110M39.814中文优化
Cross-Encoder/ms-marco110M37.218英文场景

 

9.4 上下文窗口的动态调整

上下文窗口作为大语言模型处理信息的核心资源,其有效管理直接影响RAG系统的性能和成本。将上下文窗口视为有限资源进行认知和管理,是现代RAG系统设计的重要范式转变。这一认知要求我们在系统设计的各个环节都考虑到上下文预算的约束,从检索策略到内容组织,从压缩算法到模型选择,都需要在有限的上下文预算内做出最优决策。

Token预算分配策略是上下文窗口管理的核心问题。在一个典型的RAG系统中,有限的上下文窗口需要容纳系统提示(System Prompt)、对话历史(Conversation History)、检索到的文档(Retrieved Documents)和用户查询(User Query)等多个部分。合理的预算分配需要综合考虑各部分的重要性和对最终输出的贡献。例如,系统提示通常包含关键的指令和约束信息,应保证足够的预算;检索文档的预算则可以根据查询复杂度动态调整。

上下文压缩(Compaction)是一种主动管理上下文窗口的技术。与被动的截断不同,压缩技术通过语义理解和信息提取,将大量内容浓缩为更紧凑的表示。例如,对于对话历史,可以使用摘要技术将多轮对话压缩为关键信息摘要;对于检索文档,可以使用前述的LLMLingua等方法进行压缩。压缩的目标是保留语义等价性的同时减少token占用,从而为新的信息腾出空间。

上下文修剪(Context Trimming)是另一种重要的窗口管理策略。当上下文接近或超过窗口限制时,系统需要决定哪些内容可以被移除。简单的策略包括FIFO(先进先出)和基于相关性的移除。更高级的策略则考虑信息的时效性、重要性和冗余度。例如,在多轮对话中,早期的对话内容可能随着时间推移而相关性下降;在检索结果中,与当前查询相关性较低的片段可以被优先移除。

长上下文模型的快速发展为上下文窗口管理带来了新的可能性。2024-2025年间,各大模型厂商纷纷推出了支持超长上下文的模型:Google的Gemini 1.5 Pro支持200万token的上下文窗口,OpenAI的GPT-4.1支持100万token,而Meta的Llama 4更是将这一数字推向了1000万token。这些长上下文模型从根本上改变了RAG系统的架构选择,使得"上下文即检索"(Context as Retrieval)成为可能——直接将大量文档加载到上下文中,让模型自行检索相关信息。

然而,长上下文模型并不意味着上下文管理问题的终结。首先,长上下文的推理成本仍然显著高于短上下文;其次,"Lost in the Middle"现象在长上下文中依然存在;最后,即使窗口足够大,模型能够有效利用的信息量仍然有限。因此,即使在长上下文时代,智能的上下文管理仍然是构建高效RAG系统的关键。未来的趋势可能是短上下文RAG与长上下文模型的有机结合——使用RAG进行初步筛选,然后将精选内容输入长上下文模型进行深度推理。

上下文窗口的动态调整策略还需要考虑不同应用场景的特殊需求。在客服对话场景中,对话历史的保留策略需要特别关注用户情绪的连贯性和问题解决的连续性;在法律文档分析场景中,文档的章节结构和引用关系需要被特别保留;在代码生成场景中,相关代码片段的完整性和语法正确性需要得到保证。这些场景化的调整策略要求RAG系统具备灵活的配置能力和可插拔的组件设计,以便根据不同需求快速调整上下文管理策略。

表9-4 主流长上下文模型对比(2024-2025)

模型上下文窗口发布机构关键特性适用场景
Gemini 1.5 Pro2,000,000 tokensGoogle多模态,高效注意力视频分析,大规模文档
GPT-4.11,000,000 tokensOpenAI指令遵循强,代码能力复杂推理,代码生成
Claude 3.5 Sonnet200,000 tokensAnthropic推理能力强,安全性高分析任务,敏感应用
Llama 4 Scout10,000,000 tokensMeta开源,本地部署隐私敏感场景
Kimi K1.52,000,000 tokensMoonshot中文优化,长文档处理中文长文档RAG
GLM-4-9B1,000,000 tokens智谱AI中文理解强,开源中文企业应用

 

表9-4a KV Cache压缩技术对比

技术名称压缩方法压缩率性能损失实现复杂度适用场景
KV Cache QuantizationINT8/INT4量化2x-4x<1%通用推理加速
H2OHeavy Hitter保留5x-10x2-3%长文本生成
StreamingLLM注意力汇聚点10x+<2%无限长文本
SnapKV池化选择重要KV4x-8x1-2%长文档推理
PyramidKV分层KV缓存3x-6x<1%多层次注意力
LoRA-FA低秩近似2x-4x2-4%内存受限场景

 

表9-5 Token预算分配策略示例(32K窗口)

组件简单查询标准查询复杂查询说明
系统提示1K1K1K固定开销,包含指令和约束
对话历史2K4K8K随对话轮次增加
检索文档8K16K20K根据复杂度调整
用户查询0.5K1K2K包含当前问题和上下文
预留空间2K2K2K模型输出和系统缓冲
总计13.5K24K33K复杂查询可能需要更大窗口

 

表9-5a 长上下文模型推理成本对比(每1K tokens)

模型上下文窗口输入成本($)输出成本($)1M上下文完整推理成本($)
GPT-4o128K0.00250.01~2.5
GPT-4.11M0.0020.008~20
Claude 3.5 Sonnet200K0.0030.015~6
Gemini 1.5 Pro2M0.001250.005~25
Llama 4 Scout10M本地部署本地部署硬件成本
Kimi K1.52M0.0010.003~20

 

9.5 长文档RAG的解决方案

长文档RAG是RAG技术面临的最具挑战性的场景之一。与处理短文档或片段不同,长文档(如书籍、研究报告、法律文件)通常包含复杂的结构、跨章节的引用关系和渐进展开的主题。传统的基于片段的检索方法在处理这类文档时往往力不从心,因为关键信息可能分散在文档的多个部分,简单的片段检索无法捕捉这些长距离依赖关系。

RAPTOR(Recursive Abstractive Processing for Tree-Organized Retrieval)是斯坦福大学Sarthi等人于2024年提出的创新解决方案(arXiv:2401.18059,ICLR 2024)。RAPTOR的核心思想是通过递归摘要构建一棵层次化的树形结构,将长文档组织成从具体到抽象的多层表示。在树的底层是原始的文本片段;向上每一层都是下一层的语义摘要,直到根节点代表整个文档的核心主题。在检索时,RAPTOR可以灵活地在不同层级进行检索,既能获取具体细节,也能把握全局主题。实验表明,RAPTOR在QASper和NarrativeQA等长文档问答基准上取得了显著改进,使用GPT-4时性能提升达20%。

RAPTOR的构建过程包括三个关键步骤:首先是文本分割和嵌入,将长文档切分为适当大小的片段并生成向量表示;然后是聚类和摘要,使用软聚类将语义相似的片段分组,并为每组生成摘要;最后是递归构建,将生成的摘要作为新的文本单元,重复聚类和摘要过程,直到达到预定的树深度或节点数量。这种自底向上的构建方式确保了树中的每个节点都代表了其子树内容的语义抽象。

Contextual Retrieval是Anthropic于2024年9月提出的另一种长文档RAG方案。该方法的核心洞察是:在将文档切分为片段进行索引时,每个片段都缺乏其在原文档中的上下文信息,这可能导致检索和理解的困难。Contextual Retrieval通过在索引阶段为每个片段添加上下文信息来解决这一问题。具体而言,系统使用LLM为每个片段生成一段上下文描述,说明该片段在文档中的位置和作用,然后将这段描述与原始片段一起进行索引。实验表明,这一简单的改进可以将失败率降低49-67%。

长上下文与RAG的架构决策是当前RAG系统设计中的核心问题。随着长上下文模型的出现,一些从业者开始质疑传统RAG架构的必要性——既然模型可以直接处理百万级token的上下文,为什么还要使用复杂的检索系统?然而,实际情况更为复杂。长上下文模型虽然能够处理大量文本,但成本和延迟仍然是需要考虑的因素;此外,RAG不仅解决了上下文长度问题,还提供了知识更新、来源追溯和权限控制等额外价值。因此,更务实的做法是考虑两者的结合:使用RAG进行粗粒度的文档筛选,然后将筛选出的相关文档输入长上下文模型进行细粒度的理解和推理。

分层检索(Hierarchical Retrieval)是结合RAG与长上下文优势的有效策略。该方法将检索过程分为多个层次:首先在高层进行粗粒度检索,识别出最相关的文档或章节;然后在低层进行细粒度检索,从这些文档中提取具体的片段。这种分层策略既利用了检索系统的高效性,又保留了长上下文模型的深度理解能力。在实践中,分层检索可以显著减少需要处理的内容量,同时保证检索的精度和召回率。

长文档RAG的评估是一个专门的研究领域。传统的RAG评估指标(如召回率、精确率)难以全面反映长文档场景下的系统性能。NIAH(Needle In A Haystack)基准是评估长上下文能力的重要工具,它测试模型在大量无关内容中定位特定信息的能力。此外,针对长文档问答的专门基准(如QASper、NarrativeQA、BookSum)为长文档RAG系统提供了更贴近实际应用的评估标准。这些基准不仅测试检索的准确性,还测试系统整合分散信息、理解长距离依赖和生成连贯回答的能力。

在实际部署长文档RAG系统时,还需要考虑索引构建的成本和效率问题。RAPTOR等方法虽然能够显著提升检索质量,但其索引构建过程需要大量的LLM调用,成本较高且耗时较长。因此,这些方法更适合于相对静态的知识库,对于频繁更新的内容可能需要采用增量更新策略或混合方案。Contextual Retrieval的索引开销相对较低,更适合于需要频繁更新的场景。系统设计者需要根据知识库的更新频率、查询延迟要求和预算约束,选择最合适的方案或组合多种方案。

表9-6 长文档RAG解决方案对比

方案名称核心思想索引开销检索方式性能提升适用场景
RAPTOR递归摘要构建树形结构高(需多轮LLM调用)树形层次检索GPT-4提升20%层次化长文档
Contextual Retrieval片段添加上下文描述中(单次LLM调用)标准向量检索失败率降低49-67%一般长文档
分层检索多粒度分层处理分层级联检索延迟降低50%+超大规模文档库
长上下文+轻量RAG大窗口+简单过滤粗粒度筛选简化架构预算充足场景
HyDE假设文档嵌入生成式检索零样本场景提升查询表达困难场景

 

表9-6a 长文档RAG方法在NarrativeQA上的性能对比

方法F1分数Rouge-LBLEU-1平均响应时间(s)
Baseline RAG42.338.525.21.2
+ 重排序45.141.227.82.1
+ 上下文压缩44.840.827.51.5
RAPTOR52.648.333.13.2
Contextual Retrieval50.246.131.51.4
RAPTOR + Contextual54.850.235.43.5
长上下文模型(128K)48.544.229.88.5

 

代码示例9-2:RAPTOR树形索引构建(简化版)

import numpy as np  
from sklearn.cluster import KMeans  
from typing import List, Dict, Any  
  
class RAPTORIndex:  
    """RAPTOR递归抽象处理树形索引"""  
      
    def __init__(self, embedding_model, summarization_model, max_depth=3):  
        self.embedding_model = embedding_model  
        self.summarization_model = summarization_model  
        self.max_depth = max_depth  
        self.tree = {}  
          
    def build_tree(self, documents: List[str], layer=0, parent_id="root"):  
        """递归构建RAPTOR树"""  
        if layer >= self.max_depth or len(documents) <= 3:  
            return {"documents": documents, "layer": layer, "type": "leaf"}  
          
        # 1. 生成文档嵌入  
        embeddings = self.embedding_model.encode(documents)  
          
        # 2. 软聚类(使用KMeans作为简化示例)  
        n_clusters = max(2, len(documents) // 5)  
        kmeans = KMeans(n_clusters=n_clusters, random_state=42)  
        labels = kmeans.fit_predict(embeddings)  
          
        # 3. 为每个聚类生成摘要  
        clusters = {}  
        for i in range(n_clusters):  
            cluster_docs = [doc for doc, label in zip(documents, labels) if label == i]  
            if cluster_docs:  
                summary = self.summarization_model.summarize(  
                    " ".join(cluster_docs),  
                    max_length=200  
                )  
                cluster_id = f"{parent_id}_L{layer}_C{i}"  
                clusters[cluster_id] = {  
                    "summary": summary,  
                    "children": cluster_docs,  
                    "layer": layer,  
                    "embedding": self.embedding_model.encode([summary])[0]  
                }  
          
        # 4. 递归处理下一层  
        summaries = [c["summary"] for c in clusters.values()]  
        next_layer = self.build_tree(summaries, layer + 1, parent_id)  
          
        return {  
            "clusters": clusters,  
            "next_layer": next_layer,  
            "layer": layer,  
            "type": "internal"  
        }  
      
    def retrieve(self, query: str, top_k: int = 5, layer_weights=None):  
        """分层检索"""  
        query_embedding = self.embedding_model.encode([query])[0]  
          
        results = []  
        # 从顶层开始检索,逐层深入  
        def search_layer(node, depth=0):  
            if node.get("type") == "leaf":  
                # 叶子节点:计算与原始文档的相似度  
                for doc in node.get("documents", []):  
                    doc_emb = self.embedding_model.encode([doc])[0]  
                    sim = np.dot(query_embedding, doc_emb)  
                    results.append((doc, sim, depth))  
            else:  
                # 内部节点:在聚类摘要中检索  
                clusters = node.get("clusters", {})  
                cluster_sims = []  
                for cid, cdata in clusters.items():  
                    sim = np.dot(query_embedding, cdata["embedding"])  
                    cluster_sims.append((cid, sim, cdata))  
                  
                # 选择最相关的聚类深入  
                cluster_sims.sort(key=lambda x: x[1], reverse=True)  
                for cid, sim, cdata in cluster_sims[:2]:  # Top-2聚类  
                    # 递归检索子节点或返回子文档  
                    if "children" in cdata:  
                        for child_doc in cdata["children"]:  
                            child_emb = self.embedding_model.encode([child_doc])[0]  
                            child_sim = np.dot(query_embedding, child_emb)  
                            results.append((child_doc, child_sim, depth))  
          
        search_layer(self.tree)  
        results.sort(key=lambda x: x[1], reverse=True)  
        return results[:top_k]  
  
# 使用示例  
raptor = RAPTORIndex(embedding_model, summarization_model)  
raptor.tree = raptor.build_tree(long_documents)  
relevant_docs = raptor.retrieve("查询问题", top_k=5)

代码示例9-3:Contextual Retrieval实现

import openai  
from typing import List, Dict  
  
class ContextualRetrieval:  
    """Anthropic Contextual Retrieval实现"""  
      
    def __init__(self, llm_client, embedding_model):  
        self.llm_client = llm_client  
        self.embedding_model = embedding_model  
          
    def generate_context(self, chunk: str, document: str) -> str:  
        """为文档片段生成上下文描述"""  
        prompt = f"""<document>  
{document}  
</document>  
  
Here is the chunk we want to situate within the whole document:  
<chunk>  
{chunk}  
</chunk>  
  
Please give a short succinct context to situate this chunk within the overall document for the purposes of improving search retrieval of the chunk. Answer only with the succinct context and nothing else."""  
          
        response = self.llm_client.chat.completions.create(  
            model="gpt-4o-mini",  
            messages=[{"role": "user", "content": prompt}],  
            temperature=0  
        )  
        return response.choices[0].message.content.strip()  
      
    def index_document(self, document: str, chunk_size: int = 800,  
                       chunk_overlap: int = 200) -> List[Dict]:  
        """为文档构建带上下文的索引"""  
        # 1. 切分文档  
        chunks = self._chunk_document(document, chunk_size, chunk_overlap)  
          
        indexed_chunks = []  
        for chunk in chunks:  
            # 2. 生成上下文  
            context = self.generate_context(chunk, document)  
              
            # 3. 构建带上下文的文本  
            contextualized_text = f"{context}  
  
{chunk}"  
              
            # 4. 生成嵌入  
            embedding = self.embedding_model.encode(contextualized_text)  
              
            indexed_chunks.append({  
                "original_chunk": chunk,  
                "context": context,  
                "contextualized_text": contextualized_text,  
                "embedding": embedding  
            })  
          
        return indexed_chunks  
      
    def _chunk_document(self, document: str, chunk_size: int,  
                        chunk_overlap: int) -> List[str]:  
        """简单的文档切分"""  
        chunks = []  
        start = 0  
        while start < len(document):  
            end = start + chunk_size  
            chunk = document[start:end]  
            chunks.append(chunk)  
            start = end - chunk_overlap  
        return chunks  
  
# 使用示例  
retrieval = ContextualRetrieval(openai_client, embedding_model)  
indexed = retrieval.index_document(long_document)  
  
# 检索时  
query_embedding = embedding_model.encode(query)  
results = vector_search(query_embedding, indexed, top_k=5)

9.6 上下文工程(Context Engineering):RAG设计的新范式

Context Engineering(上下文工程)是2024-2025年间兴起的一个新概念,代表了RAG系统设计范式的重大转变。传统上,RAG系统的设计主要关注检索组件的优化——如何更好地从知识库中找到相关信息。而Context Engineering则将视角扩展到整个"检索-上下文组装-模型推理"的端到端链路,强调通过系统性的上下文设计来最大化模型的推理能力。

9.6.1 从RAG到Context Engine的演进

Context Engineering的概念最早由Andrej Karpathy在2024年提出,并在Anthropic 2025年9月的技术博客中得到进一步阐述。Karpathy将Context Engineering定义为:"精心设计和优化提供给AI模型的上下文,以最大化其推理和生成能力的艺术与科学"。这一定义将上下文提升到了与模型本身同等重要的地位——即使使用相同的模型,不同的上下文设计也可能产生截然不同的输出质量。

从RAG到Context Engine的演进反映了AI应用开发的成熟度提升。早期的RAG系统主要关注"有没有"——能否从知识库中检索到相关信息;而Context Engineering则关注"好不好"——如何组织、呈现和优化上下文,使模型能够发挥最佳性能。这一转变类似于软件工程从"能运行"到"好维护"的演进,标志着RAG技术从原型验证走向生产级应用的成熟阶段。

Context Engine的核心特征包括:系统性(Systematic)——将上下文管理视为一个系统工程问题,而非孤立的优化点;端到端(End-to-end)——关注从用户输入到模型输出的完整链路;自适应(Adaptive)——根据查询特性、模型能力和任务要求动态调整上下文策略;可观测(Observable)——建立上下文质量的度量和监控体系。这些特征共同构成了Context Engineering的方法论基础。

从架构演进的角度来看,Context Engine代表了从"模型中心"向"上下文中心"的设计范式转变。在传统的模型中心范式中,开发者主要关注选择和微调模型本身,上下文被视为固定的输入;而在上下文中心范式中,模型被视为相对稳定的组件,而上下文则成为主要的优化对象和差异化来源。这一转变的意义在于:随着基础模型能力的快速提升和API化服务的普及,模型本身的差距正在缩小,而如何有效利用模型能力则成为决定应用质量的关键因素。Context Engineering正是这一趋势的技术体现。

9.6.2 上下文组装的策略与优化

LangChain在2025年7月的技术博客中提出了Context Engineering的四大核心策略:Write(写入)、Select(选择)、Compress(压缩)和Isolate(隔离)。这四大策略涵盖了上下文管理的完整生命周期,为实践者提供了系统性的指导框架。

Write策略关注如何生成高质量的上下文内容。这不仅包括从知识库中检索的信息,还包括系统提示、工具描述、示例(Few-shot examples)等。高质量的Write策略需要考虑内容的准确性、时效性、相关性和结构化程度。例如,在系统提示中明确说明模型的角色、任务要求和输出格式,可以显著提升模型的表现;精心设计的Few-shot示例可以帮助模型更好地理解任务模式。

Select策略关注从大量候选内容中选择最有价值的部分。这与前文讨论的选择性上下文密切相关,但更强调选择的系统性和策略性。有效的Select策略需要权衡多个因素:相关性与多样性的平衡——既要选择最相关的内容,也要保证信息的多样性以避免偏见;粒度与连贯性的平衡——选择合适的切分粒度,既要保证检索精度,也要维护内容的连贯性;静态与动态的平衡——确定哪些内容可以预计算和缓存,哪些需要实时计算。

Compress策略关注如何在保留关键信息的前提下减少上下文规模。前文介绍的LLMLingua等压缩技术是实现Compress策略的重要工具,但Compress策略的范畴更广。除了token级的压缩,还包括语义级的压缩——如使用摘要替代原文、使用结构化表示(如表格、图谱)替代非结构化文本等。选择何种压缩方式取决于信息的性质和任务的要求。

Isolate策略关注如何将不同来源、不同性质的信息进行有效隔离,避免相互干扰。在多源RAG场景中,信息可能来自文档、数据库、API调用等不同渠道,这些信息的质量、格式和可信度各不相同。Isolate策略通过明确的边界和标识,帮助模型区分不同来源的信息,并在推理时给予适当的权重。例如,可以使用XML标签、特殊分隔符或元数据标注来区分不同来源的内容。

这四大策略并非孤立存在,而是相互关联、协同作用的。Write策略决定了初始上下文的质量基础;Select策略确保只有最相关的内容进入后续流程;Compress策略在必要时减少上下文规模以适应约束;Isolate策略则维护不同信息源的清晰边界。在实际系统设计中,需要根据具体需求和约束条件,灵活组合和调整这些策略的应用顺序和强度。例如,在多轮对话场景中,可能需要先Isolate隔离历史对话与新检索内容,然后Select选择最相关的历史轮次,再Compress压缩过长的历史,最后Write生成结构化的上下文呈现给模型。

表9-7 Context Engineering四大策略详解

策略核心目标关键技术应用场景注意事项
Write生成高质量上下文提示工程,Few-shot设计系统初始化,任务定义保持简洁明确
Select选择最相关信息重排序,多样性采样检索后处理避免选择偏差
Compress减少上下文规模LLMLingua,摘要生成长上下文场景保留关键信息
Isolate隔离不同信息源结构化标记,元数据多源RAG明确来源标识

 

表9-7a Context Engineering能力成熟度模型

成熟度等级特征描述Write能力Select能力Compress能力Isolate能力
Level 1 初始级无系统化管理硬编码提示固定Top-K简单截断无隔离
Level 2 可重复级基础配置化模板化提示向量相似度基础压缩简单分隔
Level 3 定义级标准化流程动态提示生成多阶段选择智能压缩结构化标记
Level 4 管理级量化与优化A/B测试优化自适应选择自适应压缩语义隔离
Level 5 优化级持续演进自动提示优化预测性选择端到端优化智能路由

 

9.6.3 "检索-上下文组装-模型推理"端到端链路的系统性设计

Context Engineering的最终目标是实现"检索-上下文组装-模型推理"端到端链路的系统性优化。传统的RAG系统往往将这三个阶段视为独立的组件分别优化,而Context Engineering则强调它们之间的紧密耦合和协同优化。检索策略必须考虑后续组装和推理的需求;组装策略必须适应检索结果的特点和模型的能力;推理策略则需要在给定的上下文约束下最大化输出质量。

端到端优化的一个关键方面是建立反馈机制。模型推理的结果应该能够反馈到检索和组装阶段,指导后续查询的优化。例如,如果模型在推理时发现上下文信息不足或存在矛盾,系统应该能够触发补充检索或调整组装策略。这种迭代式的优化循环是高级RAG系统的重要特征,也是实现真正智能信息处理的关键。

另一个关键方面是建立度量和评估体系。Context Engineering需要可量化的指标来指导优化方向。这些指标不仅包括传统的检索指标(如召回率、精确率),还应该包括上下文质量的指标(如信息密度、相关性分布、冗余度)和端到端任务指标(如回答准确性、有用性)。通过系统性的评估,可以识别链路中的瓶颈并进行针对性的优化。

展望未来,Context Engineering将成为RAG系统设计的核心范式。随着模型能力的不断提升,上下文的质量和组织方式将成为决定系统性能的关键因素。同时,随着多模态RAG、Agentic RAG等新形态的出现,Context Engineering的范畴也将进一步扩展,涵盖图像、音频、视频等多种模态的上下文管理,以及Agent系统中的长期记忆和状态管理。掌握Context Engineering的原理和方法,将是每个RAG系统开发者的必备技能。

Context Engineering的实践还需要关注可解释性和可控性。在企业级应用中,用户和管理员需要理解为什么系统选择了特定的上下文内容,以及这些内容如何影响模型的输出。因此,Context Engine应该提供丰富的元数据和审计日志,记录上下文的来源、选择依据和处理过程。此外,系统还应该支持人工干预和规则覆盖,允许管理员根据业务需求调整上下文策略,确保系统行为符合组织的要求和合规标准。

在实践中实施Context Engineering时,建议采用渐进式的方法:首先建立基础的上下文管理流程和监控体系,然后针对系统中的关键瓶颈进行专项优化,最后逐步实现自适应和智能化的上下文策略。同时,应该建立跨职能的团队协作机制,将算法工程师、应用开发者和领域专家的知识结合起来,共同打造高质量的Context Engine。

代码示例9-4:Context Engine完整实现示例

class ContextEngine:  
    """上下文引擎:实现Write/Select/Compress/Isolate四大策略"""  
      
    def __init__(self, config):  
        self.config = config  
        self.retriever = config.get('retriever')  
        self.compressor = config.get('compressor')  
        self.embedding_model = config.get('embedding_model')  
          
    def write(self, system_prompt: str, tools: list = None,  
              examples: list = None) -> dict:  
        """Write策略:构建基础上下文"""  
        context = {  
            "system": system_prompt,  
            "tools": tools or [],  
            "examples": examples or [],  
            "retrieved": []  
        }  
        return context  
      
    def select(self, query: str, candidates: list,  
               strategy: str = "relevance") -> list:  
        """Select策略:选择最相关的上下文"""  
        if strategy == "relevance":  
            # 基于相关性排序  
            query_emb = self.embedding_model.encode([query])[0]  
            scored = []  
            for cand in candidates:  
                cand_emb = self.embedding_model.encode([cand['text']])[0]  
                score = cosine_similarity(query_emb, cand_emb)  
                scored.append((cand, score))  
            scored.sort(key=lambda x: x[1], reverse=True)  
            return [x[0] for x in scored[:self.config.get('top_k', 5)]]  
              
        elif strategy == "diversity":  
            # 多样性采样(MMR算法简化版)  
            selected = []  
            candidates = candidates.copy()  
            while len(selected) < self.config.get('top_k', 5) and candidates:  
                best_score = -1  
                best_cand = None  
                for cand in candidates:  
                    rel_score = cand.get('relevance', 0)  
                    div_score = max([cosine_similarity(  
                        cand['embedding'], s['embedding'])  
                        for s in selected] or [0])  
                    score = 0.7 * rel_score - 0.3 * div_score  
                    if score > best_score:  
                        best_score = score  
                        best_cand = cand  
                if best_cand:  
                    selected.append(best_cand)  
                    candidates.remove(best_cand)  
            return selected  
      
    def compress(self, context_items: list, budget: int) -> list:  
        """Compress策略:压缩上下文以符合预算"""  
        total_tokens = sum(item.get('tokens', 0) for item in context_items)  
          
        if total_tokens <= budget:  
            return context_items  
              
        # 使用LLMLingua进行压缩  
        compressed = []  
        for item in context_items:  
            if self.compressor:  
                result = self.compressor.compress_prompt(  
                    context=item['text'],  
                    rate=budget / total_tokens  
                )  
                item['text'] = result['compressed_prompt']  
                item['tokens'] = result['compressed_tokens']  
            compressed.append(item)  
        return compressed  
      
    def isolate(self, context_items: list, sources: list) -> str:  
        """Isolate策略:隔离不同来源的信息"""  
        formatted = []  
        for item in context_items:  
            source_tag = item.get('source', 'unknown')  
            formatted.append(  
                f"<{source_tag}>  
"  
                f"{item['text']}  
"  
                f"</{source_tag}>"  
            )  
        return "  
  
".join(formatted)  
      
    def assemble(self, query: str, base_context: dict,  
                 retrieved_docs: list) -> str:  
        """组装完整上下文"""  
        # 1. Select:选择相关文档  
        selected = self.select(query, retrieved_docs,  
                              strategy=self.config.get('select_strategy', 'relevance'))  
          
        # 2. Compress:压缩以符合预算  
        budget = self.config.get('context_budget', 8000)  
        system_budget = 1000  # 预留系统提示空间  
        available = budget - system_budget - len(query.split())  
        compressed = self.compress(selected, available)  
          
        # 3. Isolate:格式化隔离  
        isolated = self.isolate(compressed,  
                               sources=self.config.get('sources', []))  
          
        # 4. 组装最终提示  
        parts = []  
        if base_context.get('system'):  
            parts.append(f"System: {base_context['system']}")  
        if base_context.get('examples'):  
            parts.append("Examples:  
" + "  
".join(base_context['examples']))  
        parts.append(f"Context:  
{isolated}")  
        parts.append(f"Question: {query}")  
          
        return "  
  
".join(parts)  
  
# 使用示例  
engine = ContextEngine({  
    'retriever': retriever,  
    'compressor': PromptCompressor(),  
    'embedding_model': embedding_model,  
    'top_k': 5,  
    'context_budget': 8000,  
    'select_strategy': 'relevance'  
})  
  
base_ctx = engine.write(  
    system_prompt="你是一个专业的技术文档助手...",  
    examples=["示例1...", "示例2..."]  
)  
  
retrieved = retriever.search(query)  
final_prompt = engine.assemble(query, base_ctx, retrieved)

代码示例9-5:NIAH(大海捞针)基准测试实现

import random  
import numpy as np  
from typing import List, Tuple  
  
class NeedleInHaystackTest:  
    """NIAH基准测试:评估长上下文中的信息定位能力"""  
      
    def __init__(self, llm_client, max_context_length: int = 128000):  
        self.llm_client = llm_client  
        self.max_context_length = max_context_length  
          
    def generate_haystack(self, num_tokens: int,  
                         documents: List[str]) -> str:  
        """生成指定长度的干草堆(背景文本)"""  
        haystack = []  
        current_tokens = 0  
          
        while current_tokens < num_tokens:  
            doc = random.choice(documents)  
            haystack.append(doc)  
            # 简化的token计数(实际应使用tokenizer)  
            current_tokens += len(doc.split())  
          
        return " ".join(haystack)  
      
    def insert_needle(self, haystack: str, needle: str,  
                     position: float) -> Tuple[str, int]:  
        """在指定位置插入针(目标信息)  
          
        Args:  
            haystack: 背景文本  
            needle: 要插入的目标信息  
            position: 插入位置(0.0=开头,0.5=中间,1.0=末尾)  
          
        Returns:  
            (插入后的文本, 实际插入位置的token索引)  
        """  
        tokens = haystack.split()  
        insert_idx = int(len(tokens) * position)  
          
        needle_tokens = needle.split()  
        result_tokens = tokens[:insert_idx] + needle_tokens + tokens[insert_idx:]  
          
        return " ".join(result_tokens), insert_idx  
      
    def run_test(self, needle: str, haystack_docs: List[str],  
                context_lengths: List[int],  
                positions: List[float] = None) -> dict:  
        """运行NIAH测试  
          
        Args:  
            needle: 目标信息(如"The best thing to do in San Francisco is eat a sandwich and sit in Dolores Park on a sunny day.")  
            haystack_docs: 用于构建背景文档的文档池  
            context_lengths: 测试的不同上下文长度  
            positions: 测试的不同位置(默认为0.0, 0.25, 0.5, 0.75, 1.0)  
          
        Returns:  
            测试结果字典  
        """  
        if positions is None:  
            positions = [0.0, 0.25, 0.5, 0.75, 1.0]  
          
        results = {}  
          
        for ctx_len in context_lengths:  
            results[ctx_len] = {}  
              
            for pos in positions:  
                # 生成背景文本  
                haystack = self.generate_haystack(ctx_len, haystack_docs)  
                  
                # 插入目标信息  
                context, actual_pos = self.insert_needle(haystack, needle, pos)  
                  
                # 构建问题  
                question = "What is the best thing to do in San Francisco?"  
                  
                # 调用模型  
                prompt = f"Context: {context}\n\nQuestion: {question}\nAnswer:"  
                  
                try:  
                    response = self.llm_client.chat.completions.create(  
                        model="gpt-4",  
                        messages=[{"role": "user", "content": prompt}],  
                        temperature=0  
                    )  
                    answer = response.choices[0].message.content  
                      
                    # 检查答案是否包含关键信息  
                    key_phrases = ["sandwich", "Dolores Park"]  
                    is_correct = any(phrase.lower() in answer.lower()  
                                   for phrase in key_phrases)  
                      
                    results[ctx_len][pos] = {  
                        "correct": is_correct,  
                        "answer": answer,  
                        "actual_position": actual_pos  
                    }  
                except Exception as e:  
                    results[ctx_len][pos] = {  
                        "correct": False,  
                        "error": str(e)  
                    }  
          
        return results  
      
    def analyze_results(self, results: dict) -> dict:  
        """分析测试结果,计算不同长度和位置的准确率"""  
        analysis = {  
            "by_length": {},  
            "by_position": {},  
            "overall": 0.0  
        }  
          
        total_tests = 0  
        correct_tests = 0  
          
        # 按上下文长度统计  
        for ctx_len, pos_results in results.items():  
            correct = sum(1 for r in pos_results.values() if r.get("correct"))  
            total = len(pos_results)  
            analysis["by_length"][ctx_len] = {  
                "accuracy": correct / total if total > 0 else 0,  
                "correct": correct,  
                "total": total  
            }  
            total_tests += total  
            correct_tests += correct  
          
        # 按位置统计  
        all_positions = set()  
        for pos_results in results.values():  
            all_positions.update(pos_results.keys())  
          
        for pos in all_positions:  
            correct = sum(  
                1 for ctx_len in results  
                if pos in results[ctx_len] and results[ctx_len][pos].get("correct")  
            )  
            total = sum(1 for ctx_len in results if pos in results[ctx_len])  
            analysis["by_position"][pos] = {  
                "accuracy": correct / total if total > 0 else 0  
            }  
          
        analysis["overall"] = correct_tests / total_tests if total_tests > 0 else 0  
          
        return analysis  
  
# 使用示例  
niah_test = NeedleInHaystackTest(llm_client)  
  
results = niah_test.run_test(  
    needle="The best thing to do in San Francisco is eat a sandwich and sit in Dolores Park on a sunny day.",  
    haystack_docs=documents,  
    context_lengths=[4000, 8000, 16000, 32000, 64000, 128000],  
    positions=[0.0, 0.25, 0.5, 0.75, 1.0]  
)  
  
analysis = niah_test.analyze_results(results)  
print(f"Overall Accuracy: {analysis['overall']:.2%}")  
print(f"Accuracy by Position: {analysis['by_position']}")

本章小结

本章系统性地探讨了RAG系统中的上下文管理与压缩技术,从长上下文处理的本质挑战出发,深入分析了上下文压缩、选择性上下文、动态调整、长文档RAG解决方案以及Context Engineering新范式等核心主题。

· "Lost in the Middle"和Context Rot现象揭示了长上下文处理的内在挑战,需要在RAG系统设计中予以充分考虑。

· LLMLingua系列方法为上下文压缩提供了有效的技术路径,最高可实现20倍的压缩比。

· 选择性上下文策略通过智能筛选而非简单堆砌,能够显著提升上下文质量。

· 长上下文模型的发展为RAG架构带来了新的可能性,但并未消除智能上下文管理的必要性。

· RAPTOR和Contextual Retrieval等创新方案为长文档RAG提供了有效的解决思路。

· Context Engineering代表了RAG设计范式的重要演进,强调端到端的系统性优化。

· 有效的上下文管理需要综合考虑Write、Select、Compress、Isolate四大策略。

· 上下文窗口的动态调整策略应根据应用场景的特点进行定制化设计。

 

在下一章中,我们将探讨RAG系统的评估与优化方法,介绍如何建立全面的评估体系、识别系统瓶颈并进行针对性优化,帮助读者构建生产级的高性能RAG系统。

参考文献

[1] Gao Y, Xiong Y, Gao X, et al. Retrieval-Augmented Generation for Large Language Models: A Survey. arXiv:2312.10997, 2023.

[2] Liu N F, Lin K, Hewitt J, et al. Lost in the Middle: How Language Models Use Long Contexts. arXiv:2307.03172, TACL 2023.

[3] Jiang H, Wu Q, Lin C Y, et al. LLMLingua: Compressing Prompts for Accelerated Inference of Large Language Models. arXiv:2310.05736, EMNLP 2023.

[4] Pan Y, Zhou Y, Ravi S, et al. LLMLingua-2: Data Distillation for Efficient and Faithful Task-Agnostic Prompt Compression. arXiv:2403.12968, Findings of ACL 2024.

[5] Jiang H, Wu Q, Luo X, et al. LongLLMLingua: Accelerating and Enhancing LLMs in Long Context Scenarios via Prompt Compression. arXiv:2310.06839, ACL 2024.

[6] Sarthi P, Abdullah S, Tuli A, et al. RAPTOR: Recursive Abstractive Processing for Tree-Organized Retrieval. arXiv:2401.18059, ICLR 2024.

[7] Anthropic. Contextual Retrieval. www.anthropic.com/news/contex…, 2024.09.

[8] Anthropic. Effective context engineering for AI agents. www.anthropic.com/engineering…, 2025.09.

[9] LangChain Blog. Context Engineering. blog.langchain.com/context-eng…, 2025.07.

[10] Chroma Research. Context Rot: Understanding Information Decay in Long Conversations. www.trychroma.com/research/co…, 2025.07.

[11] Anthropic. Building effective agents. www.anthropic.com/research/bu…, 2024.12.

[12] Breunig D. How Contexts Fail and How to Fix Them. www.dbreunig.com/2025/06/con…, 2025.06.

[13] Wei J, Wang X, Schuurmans D, et al. Chain-of-Thought Prompting Elicits Reasoning in Large Language Models. NeurIPS 2022.

[14] Shinn N, Cassano F, Gopinath A, et al. Reflexion: Self-Reflective Agents with Verbal Reinforcement Learning. arXiv:2303.11366, 2023.

[15] Google. Gemini 1.5 Pro Technical Report. deepmind.google/technologie…, 2024.

[16] Kim S, Mangalam K, Li L, et al. Selective Context: Selective Context Comprehension for Large Language Models. arXiv:2310.06201, 2023.

[17] Muennighoff N. SGPT: GPT Sentence Embeddings for Semantic Search. arXiv:2202.08904, 2022.

[18] Neelakantan A, Xu T, Puri R, et al. Text and Code Embeddings by Contrastive Pre-Training. arXiv:2201.10005, 2022.

[19] Xiao C, Zhang P, Han C, et al. PPL-MCTS: Constrained Text Generation with Perturbation-aware MCTS. EMNLP 2023.

[20] Chevalier A, Wettig A, Ajith A, et al. Adapting Language Models to Compress Contexts. arXiv:2305.14788, 2023.

[21] Wang X, Zhang X, Zheng Z, et al. Efficient Long-Context Modeling for Large Language Models. arXiv:2402.03766, 2024.

[22] Ratner N, Levine Y, Belinkov Y, et al. Parallel Context Windows for Large Language Models. ACL 2023.

[23] OpenAI. GPT-4 Technical Report. arXiv:2303.08774, 2023.

[24] Meta AI. The Llama 4 herd: The beginning of a new era of natively multimodal AI innovation. ai.meta.com/blog/llama-…, 2025.