Skip to main content
Contextual Retrieval is a chunk augmentation technique that uses an LLM to enhance each chunk.
Here’s an overview of how it works.

Contextual RAG:

  1. For every chunk - prepend an explanatory context snippet that situates the chunk within the rest of the document. -> Get a small cost effective LLM to do this.
  2. Hybrid Search: Embed the chunk using both sparse (keyword) and dense(semantic) embeddings.
  3. Perform rank fusion using an algorithm like Reciprocal Rank Fusion(RRF).
  4. Retrieve top 150 chunks and pass those to a Reranker to obtain top 20 chunks.
  5. Pass top 20 chunks to LLM to generate an answer.
Below we implement each step in this process using Open Source models. To break down the concept further we break down the process into a one-time indexing step and a query time step. Data Ingestion Phase:
  1. Data processing and chunking
  2. Context generation using Qwen3.5-9B
  3. Vector Embedding and Index Generation
  4. BM25 Keyword Index Generation
At Query Time:
  1. Perform retrieval using both indices and combine them using RRF
  2. Reranker to improve retrieval quality
  3. Generation with Llama3.1 405B

Install Libraries

Data Processing and Chunking

We will RAG over Paul Graham’s latest essay titled Founder Mode.
Python
This will give us the essay, we still need to chunk the essay, so let’s implement a function and use it:
Python
We get the following chunked content:

Generating Contextual Chunks

This part contains the main intuition behind Contextual Retrieval. We will make an LLM call for each chunk to add much needed relevant context to the chunk. In order to do this we pass in the ENTIRE document per LLM call. It may seem that passing in the entire document per chunk and making an LLM call per chunk is quite inefficient, this is true and there very well might be more efficient techniques to accomplish the same end goal. But in keeping with implementing the current technique at hand let’s do it. Additionally using quantized small 1-3B models (here we will use Llama 3.2 3B) along with prompt caching does make this more feasible. Prompt caching allows key and value matrices corresponding to the document to be cached for future LLM calls. We will use the following prompt to generate context for each chunk:
Python
Now we can prep each chunk into these prompt template and generate the context:
Python
We can now use the functions above to generate context for each chunk and append it to the chunk itself:
Python
Now we can embed each chunk into a vector index.

Vector Index

We will now use multilingual-e5-large-instruct to embed the augmented chunks above into a vector index.
Python
Next we need to write a function that can retrieve the top matching chunks from this index given a query:
Python
We now have a way to retrieve from the vector index given a query.

BM25 Index

Let’s build a keyword index that allows us to use BM25 to perform lexical search based on the words present in the query and the contextual chunks. For this we will use the bm25s python library:
Python
Which can be queried as follows:
Python
Similar to the function above which produces vector results from the vector index we can write a function that produces keyword search results from the BM25 index:
Python

Everything below this point will happen at query time!

Once a user submits a query we are going to use both functions above to perform Vector and BM25 retrieval and then fuse the ranks using the RRF algorithm implemented below.
Python
The Reciprocal Rank Fusion algorithm takes two ranked list of objects and combines them:
Python
We can use the RRF function above as follows:
Python

Reranker To improve Quality

Now we add a retrieval quality improvement step here to make sure only the highest and most semantically similar chunks get sent to our LLM.
Rerank models like Mxbai-Rerank-Large-V2 are only available with dedicated model inference. You can bring up a dedicated endpoint to use reranking in your applications.
Python
This will produce the following three chunks from our essay:

Call Generative Model - Llama 3.1 405B

We will pass the finalized 3 chunks into an LLM to get our final answer.
Python
Which produces the following response:
Above we implemented Contextual Retrieval as discussed in Anthropic’s blog using fully open source models! If you want to learn more about how to best use open models refer to our docs here!