Introduction to LangChain
Hi everyone, I'm Patrick and welcome to this new tutorial about LangChain. LangChain is a framework for developing apps powered by large language models. For example, if you want to build your own ChatGPT app based on your own data, then this framework is perfect for it. But there is a lot more to it.
So here you can see all its key functionalities, which are divided into different modules. So there are models, so you can access different models with LangChain. Then there are prompts, so here you can easily create your own prompt templates. Then you can manage memory with it. Then there are indices; this is needed to combine the language models with your own text data. Then there are chains, so these are sequences of calls. For example, you can combine multiple different models or prompts. And lastly, there are agents. This is super powerful. For example, you can tell an agent to access the Google search.
So in this video, we go over all of these modules and in the end, you should have a great understanding of how this framework works. And then you can hopefully build your own AI apps with large language models. So let's get started.
Integrating Large Language Models
Installation can be done with pip install langchain. And then later when we want to use specific LLMs, for example, or a specific vector database, then we also have to install the corresponding packages, and we will get to this in a moment.
So the first core functionality is a generic interface for different LLMs, and we can have a look at the different integrations here. For example, we have OpenAI, we have Cohere, we have Hugging Face, and a lot more. Most of these integrations work via their API, but we can also run local models with LangChain.
So let me show you how to use OpenAI. In this case, we also have to install the Python SDK and then we have to set our OpenAI API key. So you can either do it like this in Python code or you can set this as your environment variable on your local system. And then we can import the OpenAI interface from LangChain and then create our OpenAI. And here we can set different parameters. For example, we can also set different model names. So this is the default model currently. And then we can give it a text and run the model. And this should give you the same output as you would get with the official OpenAI API. So here it provided a, or it created a company name. So let's run this again and see that we get a different output. So yeah, this is the company name it suggests.
Now, let me show you how to use the Hugging Face Hub as a second example. In this case, we have to set the Hugging Face Hub API token, so you get this at the Hugging Face website. Then we import the Hugging Face Hub and then we create our LLM by setting the repo ID. In this case, we use this model from Google. And then here again, we can set different parameters. And then again, we can run our LLM. In this case, we say, 'Translate English to German' and then the sentence. So this works. So now you know how to access different models with LangChain.
Optimizing with Prompt Templates
The second important functionality is prompt templates. So LangChain facilitates prompt management and optimization because often, or most of the times, we don't want to pass the question directly to the model like this. So here we ask, 'Can Barack Obama have a conversation with George Washington?' So let's run this and see what we get. And the output is, 'Barack Obama is a current president, George Washington was a past president.' So this is not quite correct and it also didn't answer the actual question.
So a better way to design our prompt is to say, 'Question:' and then we use the actual question, and we also say, 'Let's think step by step', and then we say, 'Answer:'. So let's pass this to the model and see what we get. And now the answer is, 'George Washington died in 1799. Barack Obama was born in 1961, so the final answer is no.' So this time we get a correct answer.
And LangChain makes it super simple to create these prompt templates. So for this, we can say from langchain import PromptTemplate. This is the most basic one. Then we specify our template where we define a placeholder like this. And then when we create our prompt template, we also give it the input variables, and this is a list. And now here we have to use the same names that we used for the placeholders. So now let's run the cell, and then we can, for example, say prompt.format and then we use the same name as an argument here, so the question, and then again we give it the question. And now you see this will be our final prompt.
But now we cannot directly pass this prompt to the LLM. So if we run this, then we get a type error.
Building Workflows with Chains
So now to combine a prompt template with a model, we have to use a so-called chain. So with chains, we can combine different LLMs and prompts in multi-step workflows. So here, we can chain multiple models and prompts together. And there are a lot of how-to guides for different use cases. So the most basic one is the LLMChain, but for example, there are also chains for conversations or for question answering or summarization. So for this, have a look at the documentation.
And now let's have a look at the LLMChain. So here we import this, then we create this. And here we give it the prompt template and the LLM as a parameter. Then again, here we create the same question and then we say llm_chain.run and then only give it the question. And remember this question is now passed to the prompt template, and then the final prompt is given to the LLM. So if we run this, we should again get a good response. And as you can see, again, we get a correct answer. So yeah, this is how to work with chains in LangChain.
Now let's talk about agents and tools. This is another core functionality in LangChain that can make your application extremely powerful. So with this, we can solve very complex questions and tasks. And in this concrete example I want to show you, for example, we will ask the model, 'In what year was the film The Departed with Leonardo DiCaprio released, and then what is this year raised to the 0.43 power?'
So often your model cannot answer this on its own, and for this, it can access different tools. In this example, it will access Wikipedia to look up the film, and then it will use LLM math to perform the actual math here. So this is super powerful if used correctly.
And now first, let's talk about how this works. So agents involve an LLM making decisions about which actions to take, then taking that action, seeing an observation, and repeating that until done. And for this, we have to differentiate between tools and LLM and the agent. So the tool is a function that performs a specific duty, and this can be things like Google Search, a database lookup, using the Python REPL, Wikipedia, the LLM math, and more. Then the LLM is the language model that powers the agent. And then we have the actual agent.
So first, let's have a look at some of the supported tools. So for example, we have ChatGPT plugins that can be used, then the Google Search, the Python wrapper, requests, the Wikipedia API, Wolfram Alpha, and some more. And then we also have to differentiate between different agent types. So right now, we have these four available. The one that you probably see the most is the 'zero-shot-react-description' type. So this will determine which tool to use based solely on the tool's description.
And now let me show you how to use this. So we import load_tools and we import initialize_agent. Then in this case, we want to use the Wikipedia tool, so here we also have to install the Python package. Then here again we set up a model, and here I have to say that the agents and tools works best with the OpenAI models. So let's create our LLM. Then we say load_tools and here as a list, we can use all these supported tools. Again, you will find their names here in the documentation. Then also you will give the LLM that will power the agent. And then you say initialize_agent with the tools, the LLM, and then the agent type. And then we can give it our complex question. So let's run this and see what we will get.
So here we get the whole output, and here we can follow the thought process. For example, the model said, 'I need to find out the year the film was released and then use the calculator to calculate the power.' So the first tool it wants to use is Wikipedia. So here it requests Wikipedia and then it says, 'I now know the year the film was released.' And then the next action to take is to use the calculator. So it uses the calculator and gets the math output. And then it says, 'I now know the final answer.' So the final answer is, 'The film The Departed with Leonardo DiCaprio was released in 2006, and this year raised to the 0.43 power is this value.' So yeah, this is correct. And as you can see, this concept with agent and tools is super powerful and allows a lot of complex questions or workflows that you can do with your models.
Adding State with Conversational Memory
The next important concept in LangChain is memories. So with LangChain, we can easily add state to chains and agents. The most popular example for this is, of course, if you want to build a chatbot, and we can do this very easily with the ConversationChain.
So we import this, then again we create a model, and then we create our conversation chain with the model. And then we can say conversation.predict and give it the first input. So let's run this, and since we set verbose=True, we can have a look at the whole output. So first of all, you will see what the conversation chain will do. This will, first of all, format the prompt like this: 'The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details.' Then it says, 'Current conversation: Human said this, and AI responded with this'. And then we get the response, 'Hi there, it's nice to meet you.'
And now if we run this again with the next input, 'Can we talk about AI?', and now again we can see the whole prompt, and here we can see the whole current conversation. So it remembered the previous questions and answers. And then again, the answer is here, 'Absolutely, what would you like to know about AI?' And yeah, this is how easily we can add memory to a chatbot.
Ingesting Data with Document Loaders
The next important module is document loaders. And so with document loaders, you can load your own text data from different sources very easily into your app and then feed this to your models. So let's go over the supported document loaders. Here is the whole list, and you can see there are quite a bunch of them. So for example, we have a CSV loader, an email loader, we have Evernote, Facebook chat, then we have HTML of course, Markdown, Notion, PDFs, PowerPoints you can load easily, also URLs. And for each of them, it's super simple to set this up.
For example, let's click on the PDF loader. And then this is how you would use them. So you import the loader, then you set this up, and then you say load, or in this case, load_and_split. In this notebook, I for example use the Notion directory loader. Then we give it the Notion database and then say loader.load. And now we have the raw docs.
Indexing Data: Embeddings, Splitters & Vector Stores
But now before we can feed this to the model, we need to understand indices. So indices refer to ways to structure documents so that LLMs can best interact with them. And the indices module in LangChain contains utility functions for working with documents. And in order to work with documents, we have to understand these three concepts.
First, we have embeddings. So an embedding is a numerical representation of your data, for example, of your text. Then we have text splitters that split long pieces of text into smaller chunks. And then we have vector stores. So this can be different vector databases we can use, and with this, we can understand the meaning of the data and then, for example, have more accurate search results. And usually in order to feed our own data to the model, we need to combine all of these concepts.
So let's go over a concrete example and then it will become more clear. So in this example, I want to load a text file that I download here, so a .txt file. And the first step is to apply a document loader. So there's also a dedicated one, in this case we use the text loader that we can set up here. Then the next step is to apply a text splitter. So again, there are different ones available. In this case, we use the character text splitter. Then we set this up and call split_documents. Then the next step is to set up embeddings. And again, there are different ones available. In this case, we use the Hugging Face embeddings, and for this, we have to install this third-party package. And then here, we simply create them. And then the last thing is to use a vector store. And there are different ones that are supported in LangChain. For example, you could use Elasticsearch, FAISS, Pinecone, or Weaviate. In this small code snippet, I use the FAISS vector store. So here we import this, and then we call FAISS.from_documents and then pass the docs and the embeddings. And then, for example, you could easily perform similarity search. So you could ask, 'What did the president say about Ketanji Brown Jackson?' And then this is the most similar result that it finds, so the most similar text chunk. And as you can see here, we also see the name. So this is working.
And yeah, this is typically how you would load text into your app. So first you use a document loader, then you use a text splitter, then you use embeddings, and lastly a vector store. And in order to understand this better, there's also a very cool end-to-end example that you can check out. This is the chat-langchain repository. The link will be in the description below.
Conclusion
So yeah, these are the most important concepts you should know about LangChain. Alright, so I hope you enjoyed this tutorial. If so, then drop me a like, and then I hope to see you in the next video. Bye.