Build a RAG system with Jina Embeddings and Qdrant

Create a RAG system with Jina Embeddings v2, Qdrant vector database, LlamaIndex, and Mistral LLM.

Promotional graphic with "EMBEDDINGS 2" and Drant logo separated by a red cross, symbolizing a partnership.

Retrieval-augmented generation is a rapidly growing group of techniques that were originally conceived as an extension to large language models (LLMs) but are increasingly seen as an alternative paradigm that re-imagines the role of AI models entirely.

We’ll show you how to make a basic RAG engine using the LlamaIndex framework, an open-source Mistral LLM, Jina Embeddings v2, and Qdrant’s AI-ready vector database.

RAG in Context

In a RAG system, the role of the AI model is still central but much more limited. Instead of answering prompts from its internal knowledge, derived from its training data, it’s presented with the relevant information in its prompt. The role of the model is then to understand and synthesize information into an output.

This plays to the strengths of AI models and minimizes its weaknesses.

For example, we might give the Mistral-Instruct model the following prompt:

Answer the query. Please be brief, concise, and complete.
Query: Why is Taylor Swift planning to attend the Superbowl?
Answer:

When I did that, the model responded with:

I don't have real-time information. However, as of my last update, 
Taylor Swift is not officially confirmed to attend or perform at 
the Superbowl. If there are any updates, I recommend checking the 
latest news sources.

Large language models are expensive to update and retrain, so their internal information can never be entirely up to date.

Furthermore, large language models are well known to “hallucinate,” i.e., confabulate plausible answers that may be partly or wholly incorrect and have to be verified.

Answer the query. Please be brief, concise, and complete.
Query: What was Weird Al Yankovic's first Taylor Swift parody?
Answer:

Weird Al Yankovic's first Taylor Swift parody was "TMZ," a spoof 
of Swift's song "Blank Space." The parody was released in 2014 
as part of Yankovic's album "Mandatory Fun." The song humorously 
addresses the obsession with celebrity gossip and scandals, as 
reported by the tabloid news website TMZ.

Weird Al Yankovic’s TMZ was released in 2011 on the album Alpocalypse and is a parody of Swift’s You Belong with Me.

The nature of neural networks makes hallucination difficult, if not impossible, to completely prevent and strongly undermines any plan to use AI models as information sources.

In the words of Sam Altman, CEO of OpenAI:

“I think people make a big mistake when they think of these models [LLMs] as a database. […] It will work, sort of. But it’s, like, the world’s most expensive, slowest, least accurate database.”

RAG minimizes reliance on an AI model’s internal knowledge of facts about the world and takes advantage of its biggest strengths: natural language understanding and fluent language generation.

Let’s take another example of a question Mistral-Instruct can’t answer:

Answer the query. Please be brief, concise, and complete.

Query: What is the title of Taylor Swift's next album?
Answer:

As of the time I am providing this answer, Taylor Swift has 
not yet announced the title of her next album. She has released 
several re-recorded albums, but the title of her next original 
album remains unknown. I recommend checking her official social 
media channels or website for the latest updates.

Now, a RAG system might have a database of recent news articles, or perhaps search the Internet for texts related to the title of Taylor Swift’s next album. Then, it would insert the texts it finds into the prompt.

Let’s assume it identifies this AP article as relevant to the query and constructs the following prompt:

Context information is below.
---------------------
February 6, 2024
LOS ANGELES (AP) — Forget her “Reputation.” Taylor Swift has a 
whole new album coming out.

Accepting the Grammy for best pop vocal album on Sunday night, 
Taylor said she’d been keeping a secret for two years.

“My brand-new album comes out April 19. It’s called ‘The Tortured 
Poets Department.’ I’m going to go and post the cover right now 
backstage,” she announced.

And so she did.

---------------------
Given the context information and not prior knowledge, answer the query. 
Please be brief, concise, and complete.
If the context information does not contain an answer to the query, 
respond with "No information".
Query: What is the title of Taylor Swift's next album?
Answer:

Mistral-Instruct responded with:

The title of Taylor Swift's next album is 'The Tortured Poets Department'.

This kind of prompting also reduces the likelihood of hallucinations dramatically. For example:

Context information is below.
---------------------
Alpocalypse is the thirteenth studio album by American parody 
musician "Weird Al" Yankovic, released on June 21, 2011.

Track List

1. Perform This Way (Parody of "Born This Way" by Lady Gaga)
2. CNR
3. TMZ (Parody of "You Belong with Me" by Taylor Swift)
4. Skipper Dan
5. Polka Face (Polka medley including songs by artists such as 
   Lady Gaga, Justin Bieber, Britney Spears, Ke$ha, and others)
6. Craigslist
7. Party in the CIA (Parody of "Party in the U.S.A." by Miley 
   Cyrus)
8. Ringtone
9. Another Tattoo (Parody of "Nothin' on You" by B.o.B featuring 
   Bruno Mars)
10. If That Isn't Love
11. Whatever You Like (Parody of "Whatever You Like" by T.I.)
12. Stop Forwarding That Crap to Me

---------------------
Given the context information and not prior knowledge, answer the 
query. Please be brief, concise, and complete.
If the context information does not contain an answer to the query, 
respond with "No information".
Query: What was Weird Al Yankovic's first Taylor Swift parody, what 
year was it released, and what song was he parodying?
Answer:

Weird Al Yankovic's first Taylor Swift parody was "TMZ," and it was 
released in 2011. He was parodying "You Belong with Me" by Taylor 
Swift.

Anatomy of a RAG system

A RAG system has, minimally, two components:

  • A generative AI model.
  • An information retrieval system.

In this article, we will use Mistral-Instruct as the generative AI model and access it via the Hugging Face Inference API. We will use the Qdrant vector database and Jina Embeddings together for the information retrieval system.

As a data source, we will use the National Artificial Intelligence Research and Development Strategic Plan 2023 Update, published in May 2023 by the National Science and Technology Council, a body that advises the US President on scientific and technical matters. This roughly 25,000-word document is a policy and strategic planning document for American AI policy and development.

It's also a classic “tl;dr” government policy paper. Most of it is very boring, and unless you have a stake or a close interest in this area, you probably aren’t going to read it. But you might still want to know what it says.

This article will walk you through the steps of creating a RAG system able to answer questions about the text and its contents.

Install the Prerequisites

First, make sure you have all the relevant Python libraries installed. In your Python environment, run the following:

pip install llama-index qdrant-client 
pip install pdfminer.six llama-index-vector-stores-qdrant
pip install llama-index-llms-openai llama-index-embeddings-jinaai 
pip install llama-index-llms-huggingface "huggingface_hub[inference]"

We will be using LlamaIndex to construct a RAG system around the Mistral-Instruct large language model and pdfminer.six to process the PDF file into a Qdrant vector store.

Connect to Mistral-Instruct via the Hugging Face Inference API

First, set up the LLM. You will need access to the Hugging Face Inference API, including an access token. If you have a Hugging Face account, you can get one from your account settings page.

If you do not have an account, first set one up, then create an access token.

Place your token in a variable for future use:

hf_inference_api_key = '<your HuggingFace Inference API token>'

Next, we construct a prompt template:

from llama_index.core import PromptTemplate

qa_prompt_tmpl = (
    "Context information is below.\n"
    "---------------------\n"
    "{context_str}\\n"
    "---------------------\n"
    "Given the context information and not prior knowledge, "
    "answer the query. Please be brief, concise, and complete.\n"
    "If the context information does not contain an answer to the query, "
    "respond with \"No information\".\n"
    "Query: {query_str}\n"
    "Answer: "
)
qa_prompt = PromptTemplate(qa_prompt_tmpl)

This template instructs the LLM to use only the context information provided in the prompt to answer questions. This prompt has worked well for us in working with Mistral-Instruct, but you can experiment with other wordings to see what works for your use case.

from llama_index.llms.huggingface import HuggingFaceInferenceAPI

mixtral_llm = HuggingFaceInferenceAPI(
    model_name="mistralai/Mixtral-8x7B-Instruct-v0.1", 
    token=hf_inference_api_key
)

Finally, create and initialize an object for the LlamaIndex framework that holds the connection to Mistral-Instruct. The code below comes from the previous post on creating RAG systems using LlamaIndex.

This puts the connection to the Mistral LLM into the variable mistral_llm.

Information Retrieval with Qdrant and Jina Embeddings

To set up the retrieval system, you will need a Jina Embeddings API key. You can get one for free with a 1 million-token prepaid budget at the Jina Embeddings website.

Embedding API
Start with 1M free tokens. Top-performing, 8192 context length bilingual embeddings for your search and RAG systems.

Place your Jina Embeddings key in a variable for future use:

jina_emb_api_key = "<your Jina Embeddings API key>"

Then, create a connector object using LlamaIndex for the Jina Embeddings server, selecting specifically the English monolingual model:

from llama_index.embeddings.jinaai import JinaEmbedding

jina_embedding_model = JinaEmbedding(
    api_key=jina_emb_api_key,
    model="jina-embeddings-v2-base-en",
)

Load text data

Next, we will load the document and split it up into paragraphs. First, download the PDF from the White House website into the variable pdf_data:

import urllib.request

uri = "https://www.whitehouse.gov/wp-content/uploads/2023/05/National-Artificial-Intelligence-Research-and-Development-Strategic-Plan-2023-Update.pdf"
pdf_data = urllib.request.urlopen(uri).read()

Next, we will process the PDF page by page, extracting the text and then chunking it into paragraphs by splitting on double line breaks. These are stored in the list text_paras:

import regex as re
from io import BytesIO, StringIO
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfparser import PDFParser

text_paras = []
parser = PDFParser(BytesIO(pdf_data))
doc = PDFDocument(parser)
rsrcmgr = PDFResourceManager()
for page in PDFPage.create_pages(doc):
    output_string = StringIO()
    device = TextConverter(rsrcmgr, output_string, laparams=LAParams())
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    interpreter.process_page(page)
    page_text = output_string.getvalue()
    text_paras.extend(re.split(r'\n\s*\n', page_text))

Check that everything is loaded:

assert len(text_paras) == 615

Next, we will covert this list of short texts into LlamaIndex Document objects:

from llama_index.core.readers import StringIterableReader

rag_docs = StringIterableReader().load_data(text_paras)

And you can inspect the text:

print(rag_docs[0].text)

Result:

NATIONAL ARTIFICIAL INTELLIGENCE 
RESEARCH AND DEVELOPMENT 
STRATEGIC PLAN 
2023 UPDATE

Set up a Qdrant Vector Database

In this article, we will use the Qdrant Vector Search Cloud to implement the RAG system’s database. Qdrant’s free tier includes 1GB of storage, which is more than enough for this tutorial.

You will need to create an account on the Qdrant Cloud website before continuing.

Vector Search Database | Qdrant Cloud
Managed cloud solution of the Qdrant vector search engine. Cloud-native vector database for high performant vector similarity search.

Once you have an account and are logged in, you will need to create a cluster. Follow the “quick start” instructions on the Qdrant Website to set up a free cluster and get an API and the name of the Qdrant host server.

Quickstart - Qdrant
Qdrant is an Open-Source Vector Database and Vector Search Engine written in Rust. It provides fast and scalable vector similarity search service with convenient API.

Store the key and hostname in variables:

qdrant_api_key = "<your API key>"
qdrant_server = "https://<your server>"

Next, we will need to import the relevant components from the qdrant_client and llama_index packages:

import qdrant_client
from llama_index.vector_stores.qdrant import QdrantVectorStore

client = qdrant_client.QdrantClient(qdrant_server, api_key=qdrant_api_key)
vector_store = QdrantVectorStore(client=client, collection_name="NTSC")

This creates a collection named NTSC in your free cluster.

You can read the Qdrant documentation for information on constructing a local data store in memory or on disk and hosting your own Qdrant server instance in a docker container via a web API.

Complete the RAG system

Now we will assemble these components into a complete RAG system using boilerplate code for LlamaIndex:

from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.core.storage.storage_context import StorageContext
from llama_index.core import (
		VectorStoreIndex,
		ServiceContext,
		get_response_synthesizer,
)

# set up the service and storage contexts
service_context = ServiceContext.from_defaults(
    llm=mixtral_llm, embed_model=jina_embedding_model
)
storage_context = StorageContext.from_defaults(vector_store=vector_store)

# create an index
index = VectorStoreIndex.from_documents(
    rag_docs, storage_context=storage_context, service_context=service_context
)

# configure retriever
retriever = VectorIndexRetriever(
    index=index,
    similarity_top_k=2,
)

# configure response synthesizer
response_synthesizer = get_response_synthesizer(
    service_context=service_context,
    text_qa_template=qa_prompt,
    response_mode="compact",
)

# assemble query engine
query_engine = RetrieverQueryEngine(
    retriever=retriever,
    response_synthesizer=response_synthesizer,
)

This system will use Jina Embeddings to index the paragraphs from our text source and will put the two best matches into the context of every prompt. To change to the three best, for example, just modify the VectorIndexRetriever initialization above to have a different similarity_top_k parameter:

# configure retriever
retriever = VectorIndexRetriever(
    index=index,
    similarity_top_k=3,
)

Now the system is ready to use.

Query a Document

Let’s try a straightforward query:

response = query_engine.query("""
What is the Biden Administration's policy with regard to AI? 
""")
print(response.response)

The result (yours may not be identical):

The Biden Administration prioritizes responsible AI systems that 
are ethical, trustworthy, and safe, and serve the public good. 
The Administration has committed to substantial funding for AI 
R&D, and has established the National AI Initiative Office to 
coordinate AI activities across the federal government. 

The Administration's AI policy focuses on developing evaluative
techniques for AI, workforce development, public-private
partnerships, and international collaboration in AI research.

Or something more specific:

response = query_engine.query("""
What protections does the AI Bill of Rights propose to offer?
""")

print(response.response)
The AI Bill of Rights proposes five core protections: Safe and 
Effective Systems; Algorithmic Discrimination Protections; Data 
Privacy; Notice and Explanation; and Human Alternatives, 
Consideration, and Fallback.

Or even very specific:

response = query_engine.query("Who is Kei Koizumi?")
print(response.response)
Kei Koizumi is the Principal Deputy Director for Policy at the Office 
of Science and Technology Policy (OSTP).

You can also ask more fanciful questions:

response = query_engine.query("""
What rights will AI's receive under President Biden's proposed 
AI Bill of Rights?
""")
print(response.response)
The proposed AI Bill of Rights does not grant rights to AI systems, but 
rather outlines principles to ensure that AI technologies are 
developed and used in a manner that respects human rights and values. 
The principles include safety, transparency, fairness, disclosure, 
data privacy, non-discrimination, and the ability for individuals to 
opt out of certain AI systems.
response = query_engine.query("""
Why is President Biden's proposing an AI Bill of Rights?
Does AI really need rights?
""")
print(response.response)
President Biden's proposed AI Bill of Rights aims to ensure that AI 
technologies are developed and used ethically, legally, and with 
societal considerations in mind. The Bill of Rights is not granting 
"rights" to AI, but rather setting guidelines for the responsible 
development and deployment of AI systems to protect individuals and 
communities from potential negative impacts.
response = query_engine.query("""
Has Donald Trump weighed in on AI?
Will he Make Humans Great Again?
""")
print(response.response)
No information. The context information does not mention Donald 
Trump's views on AI.

Jina AI and Qdrant

Jina Embeddings’ 8k token context window makes it especially well-suited to retrieval-augmented generation because it can work with much larger blocks of text. Where other RAG applications often have to store individual sentences or pairs of sentences, in this tutorial, we could use whole paragraphs without worrying about their size.

This reduces the number of text items that have to be stored to carry the same information, lowering compute costs, sparing memory, and making retrieval faster.

Qdrant’s vector database is simple to configure, fast, and cost-effective, and as you’ve seen, it takes only a few lines of Python to integrate it into a RAG system.

For more about Qdrant’s AI-ready database and cloud offerings, you can visit their website.

Qdrant - Vector Database
Qdrant is an Open-Source Vector Database and Vector Search Engine written in Rust. It provides fast and scalable vector similarity search service with convenient API.

Get in Touch

Jina AI is committed to bringing reliable, affordable AI technologies to enterprises of every size and type. We’d love to hear about your use cases and help fit AI into your business processes. For more information about Jina AI’s offerings and to contact us, check out the Jina AI website or join our community on Discord.

Jina AI - Best Embeddings and Perfect Prompts
Jina AI provides best-in-class embedding API and prompt optimizer, easing the development of multimodal AI applications.
Join the Jina AI Discord Server!
Check out the Jina AI community on Discord - hang out with 4493 other members and enjoy free voice and text chat.