Setup guide
This guide shows you how to use LlamaIndex and Pinecone to both perform traditional semantic search and build a RAG pipeline. Specifically, you’ll do the following:- Load, transform, and vectorize sample data with LlamaIndex
- Index and store the vectorized data in Pinecone
- Search the data in Pinecone and use the results to augment an LLM call
- Evaluate the answer you get back from the LLM
This guide shows one of many ways to use LlamaIndex as part of a RAG pipeline. See LlamaIndex’s section on Advanced RAG to learn more about what’s possible.
Set up the environment
Install the libraries:Set your Pinecone and OpenAI API keys as environment variables:All code on this page runs on Python 3.12.
Shell
Shell
Load the data
This guide uses the canonical HNSW paper by Yuri Malkov (PDF) as the sample dataset. First, download the PDF from arXiv.org and load it into a LlamaIndex loader called PDF Loader. This loader is available (along with many more) on LlamaHub, a directory of data loaders.Each A file loader from LlamaHub breaks your PDF down into LlamaIndex Documents. Each Document object comes with a customizable metadata dictionary and a hash ID, among other useful artifacts.
Python
Response
Document has a lot of useful information, but depending on which loader you choose, you may have to clean your data. In this case, you need to remove things like remaining \n characters and broken, hyphenated words (e.g., alg o-\nrithms → algorithms).Python
Response
Transform the data
Metadata
If you look at one of your cleaned Document objects, you’ll see that the default values in your metadata dictionary aren’t particularly useful.Python
Response
LlamaIndex also provides advanced customizations for what metadata the LLM can see vs. the embedding, etc.
Python
Response
Ingestion pipeline
To turn your data into indexable vectors and put them into Pinecone, create what’s called an Ingestion Pipeline. An Ingestion Pipeline takes your list of Documents, parses them into Nodes (or “chunks” in non-LlamaIndex contexts), vectorizes each Node’s content, and upserts them into Pinecone.In the following pipeline, you’ll use LlamaIndex’s SemanticSplitterNodeParser, which uses OpenAI’s text-embedding-3-small model to split Documents into semantically coherent Nodes.This step uses the OpenAI API key you set as an environment variable earlier.Python
Upsert the data
The Ingestion Pipeline you defined still needs a vector store to upsert your transformed data into.LlamaIndex lets you declare a VectorStore and add it directly to the pipeline for ingestion. The following code does this with Pinecone.This step uses the Pinecone API key you set as an environment variable earlier.Now that your Confirm that your index is up and running with a Pinecone-native method like Your index now has vectors in it. Because it has 46 vectors, you can infer that your
Python
PineconeVectorStore is initialized, add it to your pipeline and run it.Python
.describe_index_stats():Python
Response
SemanticSplitterNodeParser split your list of Documents into 46 Nodes.Query the data
To fetch search results from Pinecone itself, you need to create a VectorStoreIndex object and a VectorIndexRetriever object. You can then pass natural language queries to your Pinecone index and receive results.These search results can now be plugged into any downstream task you want.One of the most common ways to use these search results is as additional context to augment a query sent to an LLM. This workflow is commonly called a RAG application.
Python
Response
Build a RAG app with the data
You could create a Query Engine out of your You can also inspect the context (Nodes) that informed your LLM’s answer with the
vector_index object by calling vector_index.as_query_engine().query('some query'), but then you wouldn’t be able to specify the number of Pinecone search results you’d like to use as context.To control how many search results your RAG app uses from your Pinecone index, create your Query Engine with the RetrieverQueryEngine class instead. This class lets you pass in the retriever you created earlier, which you configured to retrieve the top 5 search results.Python
Response
.source_nodes attribute. The following example inspects the first Node:Python
Response
Evaluate the data
Now that you’ve made a RAG app and queried your LLM, evaluate its response.With LlamaIndex, there are many ways to evaluate the results your RAG app generates. A good first step is to confirm (or deny) that your LLM’s responses are relevant, given the context retrieved from your Pinecone index. To do this, you can use LlamaIndex’s RelevancyEvaluator class.This type of evaluation doesn’t need ground truth data (i.e., labeled datasets to compare answers with).Your evaluator’s result has various attributes you can inspect to see what’s going on behind the scenes. To get a quick binary True/False signal as to whether your LLM is producing relevant results given your context, inspect the Then evaluate the response. The evaluator returns As expected, when you send an out-of-scope question through your RAG pipeline, your evaluator says the LLM’s answer isn’t relevant to the retrieved context.
Python
Response
.passing attribute.Next, send an out-of-scope query through your RAG app. Issue a random query you know your RAG app can’t answer, given what’s in your index:Python
Response
False, because the answer doesn’t come from the retrieved context:Python
Response