{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "fc0db1bc",
   "metadata": {},
   "source": [
    "# How to reorder retrieved results to mitigate the \"lost in the middle\" effect\n",
    "\n",
    "Substantial performance degradations in [RAG](/docs/tutorials/rag) applications have been [documented](https://arxiv.org/abs/2307.03172) as the number of retrieved documents grows (e.g., beyond ten). In brief: models are liable to miss relevant information in the middle of long contexts.\n",
    "\n",
    "By contrast, queries against vector stores will typically return documents in descending order of relevance (e.g., as measured by cosine similarity of [embeddings](/docs/concepts/#embedding-models)).\n",
    "\n",
    "To mitigate the [\"lost in the middle\"](https://arxiv.org/abs/2307.03172) effect, you can re-order documents after retrieval such that the most relevant documents are positioned at extrema (e.g., the first and last pieces of context), and the least relevant documents are positioned in the middle. In some cases this can help surface the most relevant information to LLMs.\n",
    "\n",
    "The [LongContextReorder](https://api.python.langchain.com/en/latest/document_transformers/langchain_community.document_transformers.long_context_reorder.LongContextReorder.html) document transformer implements this re-ordering procedure. Below we demonstrate an example."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2074fdaa-edff-468a-970f-6f5f26e93d4a",
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install --upgrade --quiet  sentence-transformers langchain-chroma langchain langchain-openai langchain-huggingface > /dev/null"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c97eaaf2-34b7-4770-9949-e1abc4ca5226",
   "metadata": {},
   "source": [
    "First we embed some artificial documents and index them in an (in-memory) [Chroma](/docs/integrations/providers/chroma/) vector store. We will use [Hugging Face](/docs/integrations/text_embedding/huggingfacehub/) embeddings, but any LangChain vector store or embeddings model will suffice."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "49cbcd8e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Document(page_content='This is a document about the Boston Celtics'),\n",
       " Document(page_content='The Celtics are my favourite team.'),\n",
       " Document(page_content='L. Kornet is one of the best Celtics players.'),\n",
       " Document(page_content='The Boston Celtics won the game by 20 points'),\n",
       " Document(page_content='Larry Bird was an iconic NBA player.'),\n",
       " Document(page_content='Elden Ring is one of the best games in the last 15 years.'),\n",
       " Document(page_content='Basquetball is a great sport.'),\n",
       " Document(page_content='I simply love going to the movies'),\n",
       " Document(page_content='Fly me to the moon is one of my favourite songs.'),\n",
       " Document(page_content='This is just a random text.')]"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_chroma import Chroma\n",
    "from langchain_huggingface import HuggingFaceEmbeddings\n",
    "\n",
    "# Get embeddings.\n",
    "embeddings = HuggingFaceEmbeddings(model_name=\"all-MiniLM-L6-v2\")\n",
    "\n",
    "texts = [\n",
    "    \"Basquetball is a great sport.\",\n",
    "    \"Fly me to the moon is one of my favourite songs.\",\n",
    "    \"The Celtics are my favourite team.\",\n",
    "    \"This is a document about the Boston Celtics\",\n",
    "    \"I simply love going to the movies\",\n",
    "    \"The Boston Celtics won the game by 20 points\",\n",
    "    \"This is just a random text.\",\n",
    "    \"Elden Ring is one of the best games in the last 15 years.\",\n",
    "    \"L. Kornet is one of the best Celtics players.\",\n",
    "    \"Larry Bird was an iconic NBA player.\",\n",
    "]\n",
    "\n",
    "# Create a retriever\n",
    "retriever = Chroma.from_texts(texts, embedding=embeddings).as_retriever(\n",
    "    search_kwargs={\"k\": 10}\n",
    ")\n",
    "query = \"What can you tell me about the Celtics?\"\n",
    "\n",
    "# Get relevant documents ordered by relevance score\n",
    "docs = retriever.invoke(query)\n",
    "docs"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "175d031a-43fa-42f4-93c4-2ba52c3c3ee5",
   "metadata": {},
   "source": [
    "Note that documents are returned in descending order of relevance to the query. The `LongContextReorder` document transformer will implement the re-ordering described above:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "9a1181f2-a3dc-4614-9233-2196ab65939e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Document(page_content='The Celtics are my favourite team.'),\n",
       " Document(page_content='The Boston Celtics won the game by 20 points'),\n",
       " Document(page_content='Elden Ring is one of the best games in the last 15 years.'),\n",
       " Document(page_content='I simply love going to the movies'),\n",
       " Document(page_content='This is just a random text.'),\n",
       " Document(page_content='Fly me to the moon is one of my favourite songs.'),\n",
       " Document(page_content='Basquetball is a great sport.'),\n",
       " Document(page_content='Larry Bird was an iconic NBA player.'),\n",
       " Document(page_content='L. Kornet is one of the best Celtics players.'),\n",
       " Document(page_content='This is a document about the Boston Celtics')]"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_community.document_transformers import LongContextReorder\n",
    "\n",
    "# Reorder the documents:\n",
    "# Less relevant document will be at the middle of the list and more\n",
    "# relevant elements at beginning / end.\n",
    "reordering = LongContextReorder()\n",
    "reordered_docs = reordering.transform_documents(docs)\n",
    "\n",
    "# Confirm that the 4 relevant documents are at beginning and end.\n",
    "reordered_docs"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a8d2ef0c-c397-4d8d-8118-3f7acf86d241",
   "metadata": {},
   "source": [
    "Below, we show how to incorporate the re-ordered documents into a simple question-answering chain:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "8bbea705-d5b9-4ed5-9957-e12547283622",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "The Celtics are a professional basketball team and one of the most iconic franchises in the NBA. They are highly regarded and have a large fan base. The team has had many successful seasons and is often considered one of the top teams in the league. They have a strong history and have produced many great players, such as Larry Bird and L. Kornet. The team is based in Boston and is often referred to as the Boston Celtics.\n"
     ]
    }
   ],
   "source": [
    "from langchain.chains.combine_documents import create_stuff_documents_chain\n",
    "from langchain_core.prompts import PromptTemplate\n",
    "from langchain_openai import OpenAI\n",
    "\n",
    "llm = OpenAI()\n",
    "\n",
    "prompt_template = \"\"\"\n",
    "Given these texts:\n",
    "-----\n",
    "{context}\n",
    "-----\n",
    "Please answer the following question:\n",
    "{query}\n",
    "\"\"\"\n",
    "\n",
    "prompt = PromptTemplate(\n",
    "    template=prompt_template,\n",
    "    input_variables=[\"context\", \"query\"],\n",
    ")\n",
    "\n",
    "# Create and invoke the chain:\n",
    "chain = create_stuff_documents_chain(llm, prompt)\n",
    "response = chain.invoke({\"context\": reordered_docs, \"query\": query})\n",
    "print(response)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}