理解上下文及RAG中的上下文检索
Source: Towards Data Science
混合搜索 + RAG:为何重要
在我最近的文章 RAG with Hybrid Search – How Does Keyword Search Work? 中,我解释了将关键词搜索组件(例如 BM25)添加到检索增强生成(RAG)流水线中如何显著提升其效果。
- 仅语义搜索 – 在嵌入上表现良好,使我们能够从自己的文档中获取 AI 驱动的洞察。
- 问题 – 在大型知识库中,纯语义搜索可能错过源材料中实际存在的精确短语匹配。
- 混合搜索 – 将语义嵌入与关键词匹配相结合,提供更全面的结果,并为 RAG 系统带来显著的性能提升。

基于块的检索中的上下文丢失问题
即使使用混合搜索,RAG 仍可能忽视散布在文档中的关键信息。这发生的原因包括:
- 块化会移除周围文本 – 当文档被拆分成更小的片段时,赋予每个块意义的上下文可能会丢失。
- 复杂的、相互关联的内容受影响 – 对跨多个章节的表格、图形或概念的引用(例如,“如表中所示,利润增长了 6%”)在去除周围上下文后会变得模糊。
- 导致检索错误 – 可能检索到不相关的块,进而产生偏离主题或不正确的模型响应。
常见(但不足的)补救措施
| 方法 | 功能 | 缺点 |
|---|---|---|
| 增大块大小 | 在每个片段中保留更多的周围文本。 | 削弱语义焦点;检索精度下降。 |
| 增大块重叠 | 在相邻块之间重复文本片段。 | 存储和计算成本更高;仍然无法捕捉跨块关系。 |
| 假设文档嵌入(HyDE) | 为每个查询生成合成的“理想”文档,然后对其进行嵌入。 | 略微提升召回率,但未能彻底解决上下文丢失问题。 |
| 文档摘要索引 | 存储每篇文档的简明摘要,以加快检索。 | 摘要可能省略实现准确答案所需的细微关联。 |
虽然这些技术有所帮助,但它们并未完全解决根本原因:失去将各块联系在一起的更广阔叙事。
真正的解决方案:上下文检索
上下文检索 – 由 Anthropic 于 2024 年提出 – 在检索步骤中保留每个块的周围上下文,显著提升 RAG 的准确性。
阅读原始论文: Anthropic – Contextual Retrieval (2024)
工作原理
- 块级上下文窗口 – 当检索到一个块时,系统还会获取可配置数量的前后文本。
- 动态上下文拼接 – 重叠的窗口在运行时合并,重建检索段落周围的原始叙述。
- 选择性扩展 – 仅添加最相关的上下文,保持 token 使用高效,同时为模型提供必要的背景。
好处
- 更高的相关性 – 模型能够看到完整的故事,减少幻觉和跑题回答。
- 比全文检索更低的延迟 – 只添加所需的上下文,而不是整个文档。
- 兼容混合搜索 – 可无缝配合语义嵌入和基于关键词的 BM25 分数。
TL;DR
- Hybrid search (semantic + keyword) 已经提升了 RAG,但分块仍然会丢失关键上下文。
- 传统的解决方案(更大的块、重叠、HyDE、摘要索引)只能带来有限的提升。
- Contextual retrieval 在查询时恢复周围文本,为 LLM 提供完整的上下文,从而生成准确、可靠的回答。
实现 Contextual retrieval 是当前克服上下文丢失问题、释放 RAG 流水线全部潜力的最有效方法。
Source: …
上下文是什么?
在深入探讨 上下文检索 之前,让我们先退一步,澄清一下对大型语言模型(LLM)而言 上下文 实际指的是什么。
我们都听说过“上下文窗口”,但这个术语具体指什么?
定义
上下文 = 在 LLM 预测下一个 token 时可用的所有 token。
实际上,这包括:
- 用户提示
- 系统提示
- 指令、技能或任何其他影响模型输出的指南
- 模型已经生成的自身响应的那一部分(每个新 token 都是基于之前的所有内容生成的)
由于 LLM 是一次生成一个 token,整个对话历史都会成为上下文的一部分。
为什么上下文重要
上下文的细微变化可能导致截然不同的完成结果:
| 提示片段 | 可能的续写 |
|---|---|
| “我去一家餐厅点了” | 披萨。 |
| “我去药店买了” | 药。 |
上下文窗口的限制
上下文窗口 是指 LLM 在单次请求中能够考虑的最大 token 数量。
- 早期模型:仅约 8 k token
- 现代前沿模型:数十万 token
例如,Claude Opus 4.6(200 k token 窗口)一次性可以处理大约 500–600 页文本。如果你需要的所有信息都在此限制之内,只需直接喂给模型,即可期待得到强有力的答案。
当知识库大于窗口时
大多数实际应用场景的知识库远大于任何上下文窗口(例如法律库、设备手册)。由于无法把所有内容都传递给模型,我们必须 挑选 最相关的信息片段纳入。这个挑选过程是 检索增强生成(RAG) 的核心,也常被称为 上下文工程:
在受限的上下文窗口内识别并放入最佳信息子集,使模型能够产生尽可能好的响应。
— LangChain Context Engineering docs
RAG 中的检索步骤
RAG 系统最关键的部分是确保正确的信息被检索并送入 LLM。检索可以通过以下方式实现:
- 语义搜索 – 找到意义相近的片段
- 关键词搜索 – 找到精确匹配的词汇
即使结合了两种方法,仍可能 遗漏一些重要信息。
可能遗漏哪些信息?
考虑两篇不同领域的文档中出现相同的表述:
“慢慢加热混合物。”
- 在 食谱书 中,这指的是烹饪。
- 在 化工手册 中,这指的是工业工艺。
语义意义(加热的动作)相同,但 上下文(烹饪 vs. 化工工程)不同。保留周围的上下文对于准确检索至关重要。
上下文检索
上下文检索 旨在保留每个文本片段的周边含义,确保模型不仅获得相关句子,还能得到能够消歧的领域特定上下文。

Source: …
关于上下文检索?
上下文检索是一种在检索增强生成(RAG)中使用的方法,用于保留每个块的上下文。当检索到一个块并将其传递给大型语言模型(LLM)时,我们希望尽可能保留其原始含义——语义、关键词以及周围的上下文。
工作原理
- 为每个块生成辅助文本——上下文文本——将该块置于其来源文档中。
- 提示 LLM 通过提供完整文档和特定块来生成此上下文文本。
- 将返回的上下文文本与原始块合并;该对随后被视为不可分割的单元进行索引和检索。
提示示例
下面是一个可以发送给 LLM 的提示,用于获取来自 意大利食谱 的块的上下文文本:
[块所在的完整意大利食谱文档]
这里是我们想要放入完整文档上下文中的块。
[实际块内容]
提供一个简短的上下文,说明该块在整体文档中的位置,以提升检索效果。仅返回简洁的上下文,不要包含其他内容。
预期的 LLM 响应
LLM 返回一段简短的上下文描述,我们将其前置于块前:
Context: Recipe step for simmering homemade tomato pasta sauce.
Chunk: Heat the mixture slowly and stir occasionally to prevent it from sticking.
现在检索系统能够准确知道 “the mixture” 指的是什么,消除了番茄酱与实验室淀粉溶液之间的歧义。
索引
从此以后,上下文 + 块 对被视为一个单元:
- 为合并后的文本生成 嵌入向量 并存入向量库。
- 在同一合并文本上构建 BM25(或其他词汇索引)。
因此,稠密索引和稀疏索引都包含了上下文信息,显著提升了相关性。
影响
据 Anthropic 称,上下文检索可以将检索准确率提升约 35 %【1】。
使用提示缓存降低成本
我听到你在问,“这不会花费巨资吗?”。令人惊讶的是,答案是否定的。
直观上,我们知道这种设置会显著增加 RAG 流水线的摄取成本——基本上会翻倍,甚至更多。毕竟,我们为每个块额外调用了一次 LLM,对吧?
这在某种程度上是对的:对于每个块,我们现在会额外调用一次 LLM,以便在其源文档中定位并检索上下文文本。
为什么额外成本仅在摄取阶段产生
- 一次性支出 – 额外的 LLM 调用 仅在文档摄取期间 发生。
- 运行时无额外开销 – 与在查询时保留上下文的技术(例如 Hypothetical Document Embeddings、HyDE)不同,上下文检索在前期完成繁重工作。
- 可扩展性 – 运行时方法需要对 每一次用户查询 进行额外的 LLM 调用,快速导致延迟上升和运营成本增加。
通过将计算移到摄取阶段,我们能够在 运行时没有任何额外开销 的情况下获得更高的检索质量。
进一步的成本降低措施
- 提示缓存 – 文档摘要 只生成一次,然后缓存。每个块可以基于缓存的摘要进行定位,而无需重新生成。
- 批处理 – 在调用 LLM 时将块进行分组,以利用某些提供商提供的 token 级别折扣。
- 选择性缓存 – 只缓存访问频率最高的文档或检索重要性较高的文档。
总之,虽然上下文检索会带来一些前期成本,但通过策略性地使用提示缓存和其他优化手段,可以保持整体费用低廉,并消除额外的运行时费用。
心中所想
上下文检索是对传统 RAG 系统的一个简单却强大的改进。通过为每个块添加上下文文本——明确其在源文档中的语义位置——我们显著降低了每个块的歧义性,并提升了传递给 LLM 的信息质量。结合混合搜索,这一技术让我们能够同时保留语义、关键词和上下文。
喜欢这篇文章?让我们成为朋友吧!关注我:
- 📰 Substack
- 💌 Medium
- ☕ Buy me a coffee
所有图片均为作者本人提供,除非另有说明。