, I walked you thru establishing a quite simple RAG pipeline in Python, utilizing OpenAI’s API, LangChain, and your native information. In that submit, I cowl the very fundamentals of making embeddings out of your native information with LangChain, storing them in a vector database with FAISS, making API calls to OpenAI’s API, and in the end producing responses related to your information. 🌟

Nonetheless, on this easy instance, I solely show the way to use a tiny .txt file. On this submit, I additional elaborate on how one can make the most of bigger information together with your RAG pipeline by including an additional step to the method — chunking.
What about chunking?
Chunking refers back to the means of parsing a textual content into smaller items of textual content—chunks—which can be then remodeled into embeddings. This is essential as a result of it permits us to successfully course of and create embeddings for bigger information. All embedding fashions include varied limitations on the dimensions of the textual content that’s handed — I’ll get into extra particulars about these limitations in a second. These limitations enable for higher efficiency and low-latency responses. Within the case that the textual content we offer doesn’t meet these dimension limitations, it’ll get truncated or rejected.
If we wished to create a RAG pipeline studying, say from Leo Tolstoy’s Battle and Peace textual content (a relatively massive guide), we wouldn’t be capable of straight load it and rework it right into a single embedding. As an alternative, we have to first do the chunking — create smaller chunks of textual content, and create embeddings for every one. Every chunk being under the dimensions limits of no matter embedding mannequin we use permits us to successfully rework any file into embeddings. So, a considerably extra practical panorama of a RAG pipeline would look as follows:

There are a number of parameters to additional customise the chunking course of and match it to our particular wants. A key parameter of the chunking course of is the chunk dimension, which permits us to specify what the dimensions of every chunk might be (in characters or in tokens). The trick right here is that the chunks we create need to be sufficiently small to be processed throughout the dimension limitations of the embedding, however on the similar time, they need to even be massive sufficient to include significant info.
As an example, let’s assume we wish to course of the next sentence from Battle and Peace, the place Prince Andrew contemplates the battle:

Let’s additionally assume we created the next (relatively small) chunks :

Then, if we have been to ask one thing like “What does Prince Andrew imply by ‘all the identical now’?”, we might not get an excellent reply as a result of the chunk “However isn’t all of it the identical now?” thought he. doesn’t comprise any context and is obscure. In distinction, the that means is scattered throughout a number of chunks. Thus, regardless that it’s just like the query we ask and could also be retrieved, it doesn’t comprise any that means to provide a related response. Subsequently, choosing the suitable chunk dimension for the chunking course of according to the kind of paperwork we use for the RAG, can largely affect the standard of the responses we’ll be getting. Usually, the content material of a piece ought to make sense for a human studying it with out some other info, as a way to additionally be capable of make sense for the mannequin. In the end, a trade-off for the chunk dimension exists — chunks should be sufficiently small to fulfill the embedding mannequin’s dimension limitations, however massive sufficient to protect that means.
• • •
One other vital parameter is the chunk overlap. That’s how a lot overlap we wish the chunks to have with each other. As an example, within the Battle and Peace instance, we might get one thing like the next chunks if we selected a piece overlap of 5 characters.

That is additionally a vital determination now we have to make as a result of:
- Bigger overlap means extra calls and tokens spent on embedding creation, which implies dearer + slower
- Smaller overlap means a better likelihood of shedding related info between the chunk boundaries
Selecting the right chunk overlap largely is dependent upon the kind of textual content we wish to course of. For instance, a recipe guide the place the language is easy and simple likely gained’t require an unique chunking methodology. On the flip aspect, a traditional literature guide like Battle and Peace, the place language may be very advanced and that means is interconnected all through completely different paragraphs and sections, will likely require a extra considerate strategy to chunking to ensure that the RAG to provide significant outcomes.
• • •
However what if all we want is an easier RAG that appears as much as a few paperwork that match the dimensions limitations of no matter embeddings mannequin we use in only one chunk? Will we nonetheless want the chunking step, or can we simply straight make one single embedding for your entire textual content? The brief reply is that it’s all the time higher to carry out the chunking step, even for a data base that does match the dimensions limits. That’s as a result of, because it seems, when coping with massive paperwork, we face the issue of getting misplaced within the center — lacking related info that’s included in massive paperwork and respective massive embeddings.
What are these mysterious ‘dimension limitations’?
Usually, a request to an embedding mannequin can embody a number of chunks of textual content. There are a number of completely different sorts of limitations now we have to think about comparatively to the dimensions of the textual content we have to create embeddings for and its processing. Every of these several types of limits takes completely different values relying on the embedding mannequin we use. Extra particularly, these are:
- Chunk Measurement, or additionally most tokens per enter, or context window. That is the utmost dimension in tokens for every chunk. As an example, for OpenAI’s
text-embedding-3-small
embedding mannequin, the chunk dimension restrict is 8,191 tokens. If we offer a piece that’s bigger than the chunk dimension restrict, typically, it will likely be silently truncated‼️ (an embedding goes to be created, however just for the primary half that meets the chunk dimension restrict), with out producing any error. - Variety of Chunks per Request, or additionally variety of inputs. There’s additionally a restrict on the variety of chunks that may be included in every request. As an example, all OpenAI’s embedding fashions have a restrict of two,048 inputs — that’s, a most of two,048 chunks per request.
- Complete Tokens per Request: There’s additionally a limitation on the overall variety of tokens of all chunks in a request. For all OpenAI’s fashions, the overall most variety of tokens throughout all chunks in a single request is 300,000 tokens.
So, what occurs if our paperwork are greater than 300,000 tokens? As you could have imagined, the reply is that we make a number of consecutive/parallel requests of 300,000 tokens or fewer. Many Python libraries do that routinely behind the scenes. For instance, LangChain’s OpenAIEmbeddings
that I take advantage of in my earlier submit, routinely batches the paperwork we offer into batches beneath 300,000 tokens, provided that the paperwork are already offered in chunks.
Studying bigger information into the RAG pipeline
Let’s check out how all these play out in a easy Python instance, utilizing the Battle and Peace textual content as a doc to retrieve within the RAG. The information I’m utilizing — Leo Tolstoy’s Battle and Peace textual content — is licensed as Public Area and could be present in Mission Gutenberg.
So, initially, let’s attempt to learn from the Battle and Peace textual content with none setup for chunking. For this tutorial, you’ll must have put in the langchain
, openai
, and faiss
Python libraries. We are able to simply set up the required packages as follows:
pip set up openai langchain langchain-community langchain-openai faiss-cpu
After ensuring the required libraries are put in, our code for a quite simple RAG appears to be like like this and works fantastic for a small and easy .txt file within the text_folder
.
from openai import OpenAI # Chat_GPT API key
api_key = "your key"
# initialize LLM
llm = ChatOpenAI(openai_api_key=api_key, mannequin="gpt-4o-mini", temperature=0.3)
# loading paperwork for use for RAG
text_folder = "RAG information"
paperwork = []
for filename in os.listdir(text_folder):
if filename.decrease().endswith(".txt"):
file_path = os.path.be part of(text_folder, filename)
loader = TextLoader(file_path)
paperwork.lengthen(loader.load())
# generate embeddings
embeddings = OpenAIEmbeddings(openai_api_key=api_key)
# create vector database w FAISS
vector_store = FAISS.from_documents(paperwork, embeddings)
retriever = vector_store.as_retriever()
def fundamental():
print("Welcome to the RAG Assistant. Sort 'exit' to stop.n")
whereas True:
user_input = enter("You: ").strip()
if user_input.decrease() == "exit":
print("Exiting…")
break
# get related paperwork
relevant_docs = retriever.invoke(user_input)
retrieved_context = "nn".be part of([doc.page_content for doc in relevant_docs])
# system immediate
system_prompt = (
"You're a useful assistant. "
"Use ONLY the next data base context to reply the person. "
"If the reply is just not within the context, say you do not know.nn"
f"Context:n{retrieved_context}"
)
# messages for LLM
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_input}
]
# generate response
response = llm.invoke(messages)
assistant_message = response.content material.strip()
print(f"nAssistant: {assistant_message}n")
if __name__ == "__main__":
fundamental()
However, if I add the Battle and Peace .txt file in the identical folder, and attempt to straight create an embedding for it, I get the next error:

ughh 🙃
So what occurs right here? LangChain’s OpenAIEmbeddings
can’t break up the textual content into separate, lower than 300,000 token iterations, as a result of we didn’t present it in chunks. It doesn’t break up the chunk, which is 777,181 tokens, resulting in a request that exceeds the 300,000 tokens most per request.
• • •
Now, let’s attempt to arrange the chunking course of to create a number of embeddings from this huge file. To do that, I might be utilizing the text_splitter
library offered by LangChain, and extra particularly, the RecursiveCharacterTextSplitter
. In RecursiveCharacterTextSplitter
, the chunk dimension and chunk overlap parameters are specified as numerous characters, however different splitters like TokenTextSplitter
or OpenAITokenSplitter
additionally enable to arrange these parameters as numerous tokens.
So, we are able to arrange an occasion of the textual content splitter as under:
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
… after which use it to separate our preliminary doc into chunks…
split_docs = []
for doc in paperwork:
chunks = splitter.split_text(doc.page_content)
for chunk in chunks:
split_docs.append(Doc(page_content=chunk))
…after which use these chunks to create the embeddings…
paperwork= split_docs
# create embeddings + FAISS index
embeddings = OpenAIEmbeddings(openai_api_key=api_key)
vector_store = FAISS.from_documents(paperwork, embeddings)
retriever = vector_store.as_retriever()
.....
… and voila 🌟
Now our code can successfully parse the offered doc, even when it’s a bit bigger, and supply related responses.

On my thoughts
Selecting a chunking strategy that matches the dimensions and complexity of the paperwork we wish to feed into our RAG pipeline is essential for the standard of the responses that we’ll be receiving. For positive, there are a number of different parameters and completely different chunking methodologies one must consider. Nonetheless, understanding and fine-tuning chunk dimension and overlap is the inspiration for constructing RAG pipelines that produce significant outcomes.
• • •
Liked this submit? Acquired an fascinating information or AI challenge?
Let’s be associates! Be part of me on
📰Substack 📝Medium 💼LinkedIn ☕Purchase me a espresso!
• • •