This page demonstrates using RAGStack and an vector-enabled {db-serverless} database to perform vector search with the Maximal Marginal Relevance (MMR) algorithm.
Instead of selecting the top k stored documents most relevant to the provided query, MMR first identifies a larger pool of relevant results, and then retrieves top k from this pool. MMR algorithms return results with more diverse information.
-
You will need an vector-enabled {db-serverless} database.
-
Create an Astra vector database.
-
Within your database, create an Astra DB Access Token with Database Administrator permissions.
-
Copy the {db-serverless} API Endpoint for your {db-serverless} database.
-
-
Set the following environment variables in a
.env
file in the root of your project:ASTRA_DB_API_ENDPOINT=https://... ASTRA_DB_APPLICATION_TOKEN=AstraCS:... ASTRA_DB_KEYSPACE=default_keyspace #optional OPENAI_API_KEY=sk-...
-
Install the following dependencies:
pip install -qU ragstack-ai python-dotenv
See the Prerequisites page for more details.
-
Import dependencies and load environment variables.
import os from dotenv import load_dotenv from langchain.chains.qa_with_sources.retrieval import RetrievalQAWithSourcesChain from langchain_openai import OpenAI, OpenAIEmbeddings from langchain.indexes.vectorstore import VectorStoreIndexWrapper from langchain_astradb import AstraDBVectorStore load_dotenv()
-
Initialize the OpenAI model and embeddings.
llm = OpenAI(temperature=0) myEmbedding = OpenAIEmbeddings()
-
Initialize the vector store.
myAstraDBVStore = AstraDBVectorStore( embedding=myEmbedding, api_endpoint=os.environ["ASTRA_DB_API_ENDPOINT"], token=os.environ["ASTRA_DB_APPLICATION_TOKEN"], namespace=os.environ.get("ASTRA_DB_KEYSPACE"), # this is optional collection_name="mmr_test", ) index = VectorStoreIndexWrapper(vectorstore=myAstraDBVStore)
-
Create a list of sentences, with their sources stored as metadata. Note that the last sentence’s content is considerably different from the others.
# declare data BASE_SENTENCE_0 = ("The frogs and the toads were meeting in the night " "for a party under the moon.") BASE_SENTENCE_1 = ("There was a party under the moon, that all toads, " "with the frogs, decided to throw that night.") BASE_SENTENCE_2 = ("And the frogs and the toads said: \"Let us have a party " "tonight, as the moon is shining\".") BASE_SENTENCE_3 = ("I remember that night... toads, along with frogs, " "were all busy planning a moonlit celebration.") DIFFERENT_SENTENCE = ("For the party, frogs and toads set a rule: " "everyone was to wear a purple hat.") # insert into index texts = [ BASE_SENTENCE_0, BASE_SENTENCE_1, BASE_SENTENCE_2, BASE_SENTENCE_3, DIFFERENT_SENTENCE, ] metadatas = [ {"source": "Barney's story at the pub"}, {"source": "Barney's story at the pub"}, {"source": "Barney's story at the pub"}, {"source": "Barney's story at the pub"}, {"source": "The chronicles at the village library"}, ]
-
Load the sentences into the vector store and print their IDs.
ids = myAstraDBVStore.add_texts( texts, metadatas=metadatas, ) print("\n".join(ids))
Create one retriever with similarity search, and another retriever with MMR search.
Both will return the top 2 results with the source metadata included. Ask them a question, and see how the MMR response differs from the similarity response.
-
Set the question.
QUESTION = "Tell me about the party that night."
-
Create a retriever with similarity search.
retrieverSim = myAstraDBVStore.as_retriever( search_type="similarity", search_kwargs={ "k": 2, }, ) chainSimSrc = RetrievalQAWithSourcesChain.from_chain_type( llm, retriever=retrieverSim, ) responseSimSrc = chainSimSrc.invoke({chainSimSrc.question_key: QUESTION}) print("Similarity-based chain:") print(f" ANSWER : {responseSimSrc['answer'].strip()}") print(f" SOURCES: {responseSimSrc['sources'].strip()}")
-
Create a retriever with MMR search.
retrieverMMR = myAstraDBVStore.as_retriever( search_type="mmr", search_kwargs={ "k": 2, }, ) chainMMRSrc = RetrievalQAWithSourcesChain.from_chain_type( llm, retriever=retrieverMMR, ) responseMMRSrc = chainMMRSrc.invoke({chainMMRSrc.question_key: QUESTION}) print("MMR-based chain:") print(f" ANSWER : {responseMMRSrc['answer'].strip()}") print(f" SOURCES: {responseMMRSrc['sources'].strip()}")
-
Run the code and observe the differences in the responses.
Similarity search returns only the most similar sentence. MMR returns the
DIFFERENT_SENTENCE
, which was considerably different from the others.Similarity-based chain: ANSWER : The party was thrown by all the toads and frogs under the moon that night. SOURCES: Barney's story at the pub MMR-based chain: ANSWER : The party that night was thrown by the frogs and toads, and the rule was for everyone to wear a purple hat. SOURCES: Barney's story at the pub, The chronicles at the village library