资料馆/上下文工程
Anthropic阅读档案 · 非官方中文译文

上下文检索Introducing Contextual Retrieval

完整译文与原文逐段对应。图片、图注、表格和代码保留原文。A complete reading edition. Figures, captions, tables and code are preserved from the source.
中文译文ENGLISH ORIGINAL

AI 模型要在具体场景中发挥作用,往往需要获取背景知识。

For an AI model to be useful in specific contexts, it often needs access to background knowledge.

AI 模型要在具体场景中发挥作用,往往需要获取背景知识。例如,客服聊天机器人需要了解其服务的具体业务,法律分析机器人则需要了解大量既往案例。

For an AI model to be useful in specific contexts, it often needs access to background knowledge. For example, customer support chatbots need knowledge about the specific business they're being used for, and legal analyst bots need to know about a vast array of past cases.

开发者通常使用检索增强生成(RAG)来扩充 AI 模型的知识。RAG 从知识库中检索相关信息,并将其附加到用户提示词中,从而显著改善模型的回答。问题在于,传统 RAG 方案在编码信息时会剥离上下文,这往往导致系统无法从知识库中检索到相关信息。

Developers typically enhance an AI model's knowledge using Retrieval-Augmented Generation (RAG). RAG is a method that retrieves relevant information from a knowledge base and appends it to the user's prompt, significantly enhancing the model's response. The problem is that traditional RAG solutions remove context when encoding information, which often results in the system failing to retrieve the relevant information from the knowledge base.

本文介绍一种能够显著改善 RAG 检索环节的方法,称为“上下文检索”(Contextual Retrieval)。它由两项子技术组成:上下文嵌入(Contextual Embeddings)和上下文 BM25(Contextual BM25)。该方法可以将检索失败次数减少 49%,与重排序结合后,则可以减少 67%。检索准确性的这些显著提升,会直接转化为下游任务中更好的表现。

In this post, we outline a method that dramatically improves the retrieval step in RAG. The method is called “Contextual Retrieval” and uses two sub-techniques: Contextual Embeddings and Contextual BM25. This method can reduce the number of failed retrievals by 49% and, when combined with reranking, by 67%. These represent significant improvements in retrieval accuracy, which directly translates to better performance in downstream tasks.

借助我们的实用示例集,你可以轻松使用 Claude 部署自己的上下文检索方案。

You can easily deploy your own Contextual Retrieval solution with Claude with our cookbook.

关于直接使用更长提示词的说明

A note on simply using a longer prompt

有时,最简单的方案就是最好的。如果知识库小于 200,000 个 token,约相当于 500 页资料,你可以直接把整个知识库放进给模型的提示词中,无需使用 RAG 或类似方法。

Sometimes the simplest solution is the best. If your knowledge base is smaller than 200,000 tokens (about 500 pages of material), you can just include the entire knowledge base in the prompt that you give the model, with no need for RAG or similar methods.

几周前,我们为 Claude 推出了提示词缓存,让这种做法明显更快、更经济。开发者现在可以在多次 API 调用之间缓存经常使用的提示词,将时延降至原来的一半以下,成本最多降低 90%。你可以阅读提示词缓存实用示例,了解其工作方式。

A few weeks ago, we released prompt caching for Claude, which makes this approach significantly faster and more cost-effective. Developers can now cache frequently used prompts between API calls, reducing latency by > 2x and costs by up to 90% (you can see how it works by reading our prompt caching cookbook).

不过,随着知识库扩大,你需要一种更具扩展性的方案。这正是上下文检索发挥作用的地方。

However, as your knowledge base grows, you'll need a more scalable solution. That’s where Contextual Retrieval comes in.

RAG 入门:扩展到更大的知识库

A primer on RAG: scaling to larger knowledge bases

对于无法容纳在上下文窗口中的大型知识库,RAG 是常见的解决方案。它通过以下步骤预处理知识库:

For larger knowledge bases that don't fit within the context window, RAG is the typical solution. RAG works by preprocessing a knowledge base using the following steps:

  1. 将知识库,也就是文档“语料库”,拆分为较小的文本块,每块通常不超过几百个 token;
  2. 使用嵌入模型,将这些文本块转换成编码其含义的向量嵌入;
  3. 将嵌入存入支持语义相似性搜索的向量数据库。
  1. Break down the knowledge base (the “corpus” of documents) into smaller chunks of text, usually no more than a few hundred tokens;
  2. Use an embedding model to convert these chunks into vector embeddings that encode meaning;
  3. Store these embeddings in a vector database that allows for searching by semantic similarity.

运行时,用户向模型输入查询,系统便利用向量数据库,根据文本块与查询的语义相似性找出最相关的块。随后,将这些块加入发送给生成模型的提示词中。

At runtime, when a user inputs a query to the model, the vector database is used to find the most relevant chunks based on semantic similarity to the query. Then, the most relevant chunks are added to the prompt sent to the generative model.

嵌入模型虽然擅长捕捉语义关系,却可能漏掉关键的精确匹配。好在,有一种较早的技术能在这些情况下提供帮助。BM25(Best Matching 25)是一种排序函数,通过词汇匹配查找精确的词语或短语匹配。对于包含独特标识符或专业术语的查询,它尤其有效。

While embedding models excel at capturing semantic relationships, they can miss crucial exact matches. Fortunately, there’s an older technique that can assist in these situations. BM25 (Best Matching 25) is a ranking function that uses lexical matching to find precise word or phrase matches. It's particularly effective for queries that include unique identifiers or technical terms.

BM25 建立在 TF-IDF(词频—逆文档频率)的概念之上。TF-IDF 衡量一个词对于文档集合中某篇文档的重要性。BM25 在此基础上考虑文档长度,并对词频应用饱和函数,从而避免常见词主导结果。

BM25 works by building upon the TF-IDF (Term Frequency-Inverse Document Frequency) concept. TF-IDF measures how important a word is to a document in a collection. BM25 refines this by considering document length and applying a saturation function to term frequency, which helps prevent common words from dominating the results.

下面的例子说明,BM25 如何在语义嵌入失败的地方发挥作用:假设用户在技术支持数据库中查询“错误代码 TS-999”。嵌入模型可能找到一般性的错误代码内容,却漏掉与“TS-999”完全匹配的结果。BM25 则会查找这个特定字符串,定位相关文档。

Here’s how BM25 can succeed where semantic embeddings fail: Suppose a user queries "Error code TS-999" in a technical support database. An embedding model might find content about error codes in general, but could miss the exact "TS-999" match. BM25 looks for this specific text string to identify the relevant documentation.

RAG 方案可以通过以下步骤结合嵌入与 BM25,更准确地检索到最适用的文本块:

RAG solutions can more accurately retrieve the most applicable chunks by combining the embeddings and BM25 techniques using the following steps:

  1. 将知识库,也就是文档“语料库”,拆分成较小的文本块,每块通常不超过几百个 token;
  2. 为这些块生成 TF-IDF 编码和语义嵌入;
  3. 使用 BM25,基于精确匹配找出排名靠前的块;
  4. 使用嵌入,基于语义相似性找出排名靠前的块;
  5. 通过排名融合技术合并步骤(3)和(4)的结果,并去除重复项;
  6. 将排名前 K 的块加入提示词,生成回答。
  1. Break down the knowledge base (the "corpus" of documents) into smaller chunks of text, usually no more than a few hundred tokens;
  2. Create TF-IDF encodings and semantic embeddings for these chunks;
  3. Use BM25 to find top chunks based on exact matches;
  4. Use embeddings to find top chunks based on semantic similarity;
  5. Combine and deduplicate results from (3) and (4) using rank fusion techniques;
  6. Add the top-K chunks to the prompt to generate the response.

同时使用 BM25 和嵌入模型,传统 RAG 系统就能在精确词语匹配与更广泛的语义理解之间取得平衡,提供更全面、更准确的结果。

By leveraging both BM25 and embedding models, traditional RAG systems can provide more comprehensive and accurate results, balancing precise term matching with broader semantic understanding.

A Standard Retrieval-Augmented Generation (RAG) system that uses both embeddings and Best Match 25 (BM25) to retrieve information. TF-IDF (term frequency-inverse document frequency) measures word importance and forms the basis for BM25.

这种方法能够以经济的方式扩展到非常庞大的知识库,远超单条提示词能容纳的范围。但这些传统 RAG 系统有一个重大局限:它们往往会破坏上下文。

This approach allows you to cost-effectively scale to enormous knowledge bases, far beyond what could fit in a single prompt. But these traditional RAG systems have a significant limitation: they often destroy context.

传统 RAG 的上下文难题

The context conundrum in traditional RAG

在传统 RAG 中,文档通常被拆成较小的块,以提高检索效率。虽然这种方法适用于许多应用,但当单个块缺少足够上下文时,就可能出现问题。

In traditional RAG, documents are typically split into smaller chunks for efficient retrieval. While this approach works well for many applications, it can lead to problems when individual chunks lack sufficient context.

例如,假设知识库中嵌入了一批财务信息,如提交给美国证券交易委员会的申报文件,而你收到这样一个问题:“ACME 公司在 2023 年第二季度的营收增长率是多少?”

For example, imagine you had a collection of financial information (say, U.S. SEC filings) embedded in your knowledge base, and you received the following question: "What was the revenue growth for ACME Corp in Q2 2023?"

一个相关文本块可能写着:“该公司的营收比上一季度增长了 3%。”但单看这个块,无法知道它指的是哪家公司、哪个时期,因此难以检索到正确信息,也难以有效利用这些信息。

A relevant chunk might contain the text: "The company's revenue grew by 3% over the previous quarter." However, this chunk on its own doesn't specify which company it's referring to or the relevant time period, making it difficult to retrieve the right information or use the information effectively.

介绍上下文检索

Introducing Contextual Retrieval

上下文检索的解决方式是:在生成嵌入和建立 BM25 索引之前,为每个块前置一段针对该块的解释性上下文,分别形成“上下文嵌入”和“上下文 BM25”。

Contextual Retrieval solves this problem by prepending chunk-specific explanatory context to each chunk before embedding (“Contextual Embeddings”) and creating the BM25 index (“Contextual BM25”).

回到刚才那组 SEC 申报文件的例子。下面展示一个文本块可以如何转换:

Let’s return to our SEC filings collection example. Here's an example of how a chunk might be transformed:

original_chunk = "The company's revenue grew by 3% over the previous quarter."

contextualized_chunk = "This chunk is from an SEC filing on ACME corp's performance in Q2 2023; the previous quarter's revenue was $314 million. The company's revenue grew by 3% over the previous quarter."

此前也有人提出过其他利用上下文改善检索的方法,包括向文本块添加通用的文档摘要(我们试验过,收益非常有限)、假设文档嵌入,以及基于摘要的索引(我们评测后发现表现较差)。这些方法与本文提出的方法不同。

It is worth noting that other approaches to using context to improve retrieval have been proposed in the past. Other proposals include: adding generic document summaries to chunks (we experimented and saw very limited gains), hypothetical document embedding, and summary-based indexing (we evaluated and saw low performance). These methods differ from what is proposed in this post.

实现上下文检索

Implementing Contextual Retrieval

当然,手动为知识库中成千上万、甚至数百万个文本块添加注释,工作量会大得难以承受。因此,我们借助 Claude 实现上下文检索。我们编写了一段提示词,要求模型依据整篇文档的上下文,为每个块提供简洁且有针对性的背景说明。我们使用以下 Claude 3 Haiku 提示词,为每个块生成上下文:

Of course, it would be far too much work to manually annotate the thousands or even millions of chunks in a knowledge base. To implement Contextual Retrieval, we turn to Claude. We’ve written a prompt that instructs the model to provide concise, chunk-specific context that explains the chunk using the context of the overall document. We used the following Claude 3 Haiku prompt to generate context for each chunk:

<document> 
{{WHOLE_DOCUMENT}} 
</document> 
Here is the chunk we want to situate within the whole document 
<chunk> 
{{CHUNK_CONTENT}} 
</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. 

生成的上下文文本通常为 50—100 个 token,会在生成嵌入和建立 BM25 索引之前,添加到文本块前面。

The resulting contextual text, usually 50-100 tokens, is prepended to the chunk before embedding it and before creating the BM25 index.

实际的预处理流程如下:

Here’s what the preprocessing flow looks like in practice:

Contextual Retrieval is a preprocessing technique that improves retrieval accuracy.

如果你有兴趣使用上下文检索,可以从我们的实用示例集开始。

If you’re interested in using Contextual Retrieval, you can get started with our cookbook.

通过提示词缓存降低上下文检索成本

Using Prompt Caching to reduce the costs of Contextual Retrieval

得益于上面提到的专门提示词缓存功能,Claude 在低成本实现上下文检索方面具有独特优势。使用提示词缓存后,不必为每个块都传入参考文档。你只需将文档加载到缓存一次,之后引用已经缓存的内容即可。假设每块 800 个 token、每篇文档 8,000 个 token、上下文生成指令 50 个 token、每块生成的上下文 100 个 token,为每百万文档 token 生成带上下文的文本块,一次性成本为 1.02 美元。

Contextual Retrieval is uniquely possible at low cost with Claude, thanks to the special prompt caching feature we mentioned above. With prompt caching, you don’t need to pass in the reference document for every chunk. You simply load the document into the cache once and then reference the previously cached content. Assuming 800 token chunks, 8k token documents, 50 token context instructions, and 100 tokens of context per chunk, the one-time cost to generate contextualized chunks is $1.02 per million document tokens.

方法

Methodology

我们针对多种知识领域,包括代码库、小说、ArXiv 论文和科学论文,以及不同的嵌入模型、检索策略和评测指标开展了实验。附录 II列出了每个领域所用问题与答案的一些示例。

We experimented across various knowledge domains (codebases, fiction, ArXiv papers, Science Papers), embedding models, retrieval strategies, and evaluation metrics. We’ve included a few examples of the questions and answers we used for each domain in Appendix II.

下图展示了采用表现最佳的嵌入配置 Gemini Text 004、检索前 20 个文本块时,在所有知识领域上的平均表现。我们的评测指标是 1 减 recall@20,衡量相关文档未能出现在检索所得前 20 个块中的比例。完整结果见附录:在我们评估的每一种嵌入模型与数据来源组合中,加入上下文都改善了表现。

The graphs below show the average performance across all knowledge domains with the top-performing embedding configuration (Gemini Text 004) and retrieving the top-20-chunks. We use 1 minus recall@20 as our evaluation metric, which measures the percentage of relevant documents that fail to be retrieved within the top 20 chunks. You can see the full results in the appendix - contextualizing improves performance in every embedding-source combination we evaluated.

性能提升

Performance improvements

实验表明:

Our experiments showed that:

  • 上下文嵌入将前 20 个文本块的检索失败率降低了 35%(5.7% → 3.7%)。
  • 结合上下文嵌入与上下文 BM25,将前 20 个文本块的检索失败率降低了 49%(5.7% → 2.9%)。
  • Contextual Embeddings reduced the top-20-chunk retrieval failure rate by 35% (5.7% → 3.7%).
  • Combining Contextual Embeddings and Contextual BM25 reduced the top-20-chunk retrieval failure rate by 49% (5.7% → 2.9%).
Combining Contextual Embedding and Contextual BM25 reduce the top-20-chunk retrieval failure rate by 49%.

实现时的注意事项

Implementation considerations

实现上下文检索时,需要考虑以下几个方面:

When implementing Contextual Retrieval, there are a few considerations to keep in mind:

  1. 分块边界:考虑如何将文档拆分成块。块大小、边界以及块间重叠部分的选择,都会影响检索表现1。
  2. 嵌入模型:上下文检索改善了我们测试的所有嵌入模型的表现,但不同模型的受益程度可能不同。我们发现,Gemini 和 Voyage 的嵌入尤其有效。
  3. 定制上下文生成提示词:虽然我们提供的通用提示词效果很好,但针对具体领域或用例定制提示词,可能取得更好的结果。例如,可以加入关键术语表,其中一些术语可能只在知识库的其他文档中有定义。
  4. 文本块数量:向上下文窗口加入更多块,会增加覆盖相关信息的机会。但信息过多也可能分散模型注意力,因此存在上限。我们尝试了提供 5、10 和 20 个块,发现这几种方案中 20 个块的表现最好,比较结果见附录。不过,仍值得针对你的具体用例开展实验。
  1. Chunk boundaries: Consider how you split your documents into chunks. The choice of chunk size, chunk boundary, and chunk overlap can affect retrieval performance1.
  2. Embedding model: Whereas Contextual Retrieval improves performance across all embedding models we tested, some models may benefit more than others. We found Gemini and Voyage embeddings to be particularly effective.
  3. Custom contextualizer prompts: While the generic prompt we provided works well, you may be able to achieve even better results with prompts tailored to your specific domain or use case (for example, including a glossary of key terms that might only be defined in other documents in the knowledge base).
  4. Number of chunks: Adding more chunks into the context window increases the chances that you include the relevant information. However, more information can be distracting for models so there's a limit to this. We tried delivering 5, 10, and 20 chunks, and found using 20 to be the most performant of these options (see appendix for comparisons) but it’s worth experimenting on your use case.

始终运行评测:向模型提供带上下文的文本块,并区分哪些是补充上下文、哪些是块本身,可能改善回答生成效果。

Always run evals: Response generation may be improved by passing it the contextualized chunk and distinguishing between what is context and what is the chunk.

通过重排序进一步提升性能

Further boosting performance with Reranking

最后,我们还可以把上下文检索与另一项技术结合,进一步提升性能。在传统 RAG 中,AI 系统搜索知识库,查找可能相关的信息块。面对大型知识库,初次检索往往会返回许多块,有时甚至数百个,而它们的相关性和重要程度并不一致。

In a final step, we can combine Contextual Retrieval with another technique to give even more performance improvements. In traditional RAG, the AI system searches its knowledge base to find the potentially relevant information chunks. With large knowledge bases, this initial retrieval often returns a lot of chunks—sometimes hundreds—of varying relevance and importance.

重排序是一种常见的过滤技术,用来确保只有最相关的文本块被传给模型。由于模型需要处理的信息更少,重排序既能改善回答,也能降低成本和时延。关键步骤如下:

Reranking is a commonly used filtering technique to ensure that only the most relevant chunks are passed to the model. Reranking provides better responses and reduces cost and latency because the model is processing less information. The key steps are:

  1. 进行初次检索,获取排名靠前、可能相关的块,我们使用前 150 个;
  2. 将前 N 个块与用户查询一起传入重排序模型;
  3. 使用重排序模型,根据每个块对提示词的相关性和重要性评分,再选出前 K 个块,我们使用前 20 个;
  4. 将前 K 个块作为上下文传给模型,生成最终结果。
  1. Perform initial retrieval to get the top potentially relevant chunks (we used the top 150);
  2. Pass the top-N chunks, along with the user's query, through the reranking model;
  3. Using a reranking model, give each chunk a score based on its relevance and importance to the prompt, then select the top-K chunks (we used the top 20);
  4. Pass the top-K chunks into the model as context to generate the final result.
Combine Contextual Retrieva and Reranking to maximize retrieval accuracy.

性能提升

Performance improvements

市面上有多种重排序模型。我们的测试使用了 Cohere 重排序模型。Voyage 也提供了重排序模型,不过我们没有时间测试。实验表明,在不同领域中,增加重排序步骤都能进一步优化检索。

There are several reranking models on the market. We ran our tests with the Cohere reranker. Voyage also offers a reranker, though we did not have time to test it. Our experiments showed that, across various domains, adding a reranking step further optimizes retrieval.

具体而言,我们发现,对上下文嵌入与上下文 BM25 的检索结果进行重排序,可将前 20 个块的检索失败率降低 67%(5.7% → 1.9%)。

Specifically, we found that Reranked Contextual Embedding and Contextual BM25 reduced the top-20-chunk retrieval failure rate by 67% (5.7% → 1.9%).

Reranked Contextual Embedding and Contextual BM25 reduces the top-20-chunk retrieval failure rate by 67%.

成本与时延考量

Cost and latency considerations

使用重排序时,一个重要考量是它对时延与成本的影响,尤其是在对大量文本块重排序时。由于运行时增加了一个步骤,即使重排序模型并行为所有块评分,也不可避免地会引入少量延迟。对更多块进行重排序以获得更好表现,与对更少块重排序以降低时延和成本之间,存在固有的取舍。我们建议针对具体用例尝试不同设置,找到恰当的平衡。

One important consideration with reranking is the impact on latency and cost, especially when reranking a large number of chunks. Because reranking adds an extra step at runtime, it inevitably adds a small amount of latency, even though the reranker scores all the chunks in parallel. There is an inherent trade-off between reranking more chunks for better performance vs. reranking fewer for lower latency and cost. We recommend experimenting with different settings on your specific use case to find the right balance.

结语

Conclusion

我们在多种不同类型的数据集上进行了大量测试,比较了上述各种技术的不同组合,包括嵌入模型、是否使用 BM25、是否使用上下文检索、是否使用重排序模型,以及检索结果的 top-K 数量。主要发现如下:

We ran a large number of tests, comparing different combinations of all the techniques described above (embedding model, use of BM25, use of contextual retrieval, use of a reranker, and total # of top-K results retrieved), all across a variety of different dataset types. Here’s a summary of what we found:

  1. 嵌入与 BM25 结合,优于单独使用嵌入;
  2. 在我们测试的模型中,Voyage 和 Gemini 的嵌入表现最好;
  3. 向模型提供前 20 个文本块,比只提供前 10 个或前 5 个更有效;
  4. 为文本块添加上下文,可以大幅提高检索准确性;
  5. 进行重排序,优于不进行重排序;
  6. 这些收益可以叠加:要最大化性能提升,可以结合 Voyage 或 Gemini 的上下文嵌入与上下文 BM25,再加入重排序步骤,最后把 20 个块放入提示词。
  1. Embeddings+BM25 is better than embeddings on their own;
  2. Voyage and Gemini have the best embeddings of the ones we tested;
  3. Passing the top-20 chunks to the model is more effective than just the top-10 or top-5;
  4. Adding context to chunks improves retrieval accuracy a lot;
  5. Reranking is better than no reranking;
  6. All these benefits stack: to maximize performance improvements, we can combine contextual embeddings (from Voyage or Gemini) with contextual BM25, plus a reranking step, and adding the 20 chunks to the prompt.

我们鼓励所有使用知识库的开发者,借助我们的实用示例集尝试这些方法,实现更高水平的性能。

We encourage all developers working with knowledge bases to use our cookbook to experiment with these approaches to unlock new levels of performance.

附录 I

Appendix I

下表细分列出了 Retrievals @ 20 的结果,比较不同数据集、嵌入供应商、是否在嵌入之外使用 BM25、是否使用上下文检索,以及是否使用重排序。

Below is a breakdown of results across datasets, embedding providers, use of BM25 in addition to embeddings, use of contextual retrieval, and use of reranking for Retrievals @ 20.

Retrievals @ 10 和 @ 5 的细分结果,以及各数据集的问题与答案示例,请参见附录 II。

See Appendix II for the breakdowns for Retrievals @ 10 and @ 5 as well as example questions and answers for each dataset.

1 minus recall @ 20 results across data sets and embedding providers.

致谢

Acknowledgements

研究与撰写由 Daniel Ford 完成。感谢 Orowa Sikder、Gautam Mittal 和 Kenneth Lien 提供关键反馈,Samuel Flamini 实现实用示例,Lauren Polansky 协调项目,以及 Alex Albert、Susan Payne、Stuart Ritchie 和 Brad Abrams 对本文的打磨。

Research and writing by Daniel Ford. Thanks to Orowa Sikder, Gautam Mittal, and Kenneth Lien for critical feedback, Samuel Flamini for implementing the cookbooks, Lauren Polansky for project coordination and Alex Albert, Susan Payne, Stuart Ritchie, and Brad Abrams for shaping this blog post.

— 全文完 —

原文来自 Anthropic,中文为非官方学习译文。
查看原始出处 ↗

点击空白处或按 Esc 关闭