Hi and welcome to this course on LangGraph, LangChain, and LangSmith. My name is Dirk van Meerveld and I will be your host and guide as we go on this exploration together.
So what is up with all these Lang-words? Well, in short:
- LangChain is a basic framework that will allow us to work with LLMs.
- LangGraph will allow us to make more complex combinations using LangChain by introducing graph structures, where we can have multiple nodes or even teams of LLM agents working together.
- LangSmith is a tool that helps us see exactly what is going on while we work with the above two, to help us debug and improve our code in a more convenient way.
LangChain
Let’s get started with LangChainπ first. Langchain is a framework designed to make it easier to build applications that use large language models (LLMs). Think of it as a set of tools that helps bridge the gap between LLMs and the applications you might want to build with them.
LangChain helps us:
- Provide a unified interface: Any code you write can be used with different LLMs with little modification, and you can use the same code to write prompts or tools for different LLMs.
- Prebuilt tools for common tasks: Langchain includes tools for common tasks you might want to do with LLMs, such as building chatbots, summarizing documents, or analyzing code. Besides just building our own tools and functions, we can also import community pre-built tools.
- Memory and Context: Langchain makes it easy to incorporate memory and context into our LLM applications. This means our application can remember past interactions and use that information to inform future responses.
So let’s get started! First go ahead and create a new project folder and name it whatever you like, I’ll call mine FINX_LANGGRAPH:
π FINX_LANGGRAPH
Create a venv in the root project folder
We’ll be running this project inside a virtual environment. A virtual environment is a self-contained directory that will allow us to install specific versions of packages inside the virtual environment without affecting the global Python installation.
We will use this as I will be using specific versions for the libraries we install as we go along, and I want to make sure that you have the exact same experience as I do.
For example, when we use pydantic we’ll be using the older V1 for this project, as it plays nicely with LangChain. You’ll probably have V2 installed on your system-wide Python installation, and then your imports will be different from mine, causing confusion. We also don’t want to mess with your system-wide Python installation.
The virtual environment will make it easy for you to install my exact versions without worrying about affecting any of your other projects and is a good practice to follow in general.
To create a new virtual environment we’ll use a tool called pipenv. If you don’t have pipenv installed, you can install it using pip, which is Python’s package manager. Run the following command in your terminal:
pip install pipenv
Make sure the terminal is inside your root project folder, e.g. /c/Coding_Vault/Finx_Fine_Tuning, and then run the following command to create a new virtual environment:
pipenv shell
This will create a new virtual environment and also a Pipfile in your project directory. Any packages you install using pipenv install will be added to the Pipfile.
- To generate a
Pipfile.lock, which is used to produce deterministic builds, run:
pipenv lock
This will create a Pipfile.lock in your project directory, which contains the exact version of each dependency to ensure that future installs are able to replicate the same environment.
We don’t need to install a library first to create a Pipfile.lock. From now on when we install a library in this virtual environment with pipenv install library_name, they will be added to the Pipfile and Pipfile.lock, which are basically just text files keeping track of our exact project dependencies.
For reference, I’m using Python 3.10 for this project, but you should be fine with any recent version. Consider upgrading if you’re using an older version.
Basic project setup
Before we get started, we need to make sure we have our OpenAI API key ready to load in a convenient way, we cannot hardcode this one in our source code. Go to https://platform.openai.com/api-keys and copy your API key, or make a new one. You’ll only pay for what you use which will be cents if you just play around with it casually. Then create a new file called .env in the root folder of your project:
π FINX_LANGGRAPH
π .env β¨New file
π Pipfile
π Pipfile.lock
And paste your API key in the .env file like this, making sure not to use any spaces or quotes:
OPENAI_API_KEY=your_api_key_here
Then go ahead and save and close this file. If you are using Git, make sure to add this file to your .gitignore file so you don’t accidentally commit your API key to your repository. If you’re not using Git, just make sure you exclude the .env file if you share your code with anyone.
We’ll be using several API keys and settings across our project, adding more as we go, so let’s create a simple and reusable way to load them to stop us from writing the same code over and over again.
Run the following command in your terminal to add the python-decouple package inside your pipenv environment:
pipenv install python-decouple==3.7
We will use this package to read the .env file and get the API key from it. Now create a new file named setup_environment.py in the root folder of your project:
π FINX_LANGGRAPH
π .env
π Pipfile
π Pipfile.lock
π setup_environment.py β¨New file
Then inside this new setup_environment.py file, write the following code:
import os
from decouple import config
def set_environment_variables() -> None:
os.environ["OPENAI_API_KEY"] = str(config("OPENAI_API_KEY"))
We import the os and config from the decouple package we just installed a minute ago. We then create a function we can import from our other code files.
The config("OPENAI_API_KEY") function reads the .env file and gets the value of the OPENAI_API_KEY variable we set in there, so make sure you have used the exact same name in there. The str() cast just makes sure it’s a string value. We then set this value to the OPENAI_API_KEY environment variable using os.environ.
This way we can just use LangChain freely without having to worry about our API key as both LangChain and OpenAI are set up to read our API keys from the environment variables automatically.
LangChain basics
Ok, time to get started with LangChain! Let’s cover the basics first so we understand the building blocks. We’ll start with some installs. Make sure you run all of these even if you have some of these libraries installed already as we’re not using the global Python installation but our virtual environment. Run the following command in your terminal:
pipenv install openai==1.14.2 langchain==0.1.13 langchain-openai==0.1.0
The openai library will work with the OpenAI API behind the scenes while we use langchain and the langchain-openai library has some functionality that overlaps both.
Now create a new file named langchain_basics.py in the root folder of your project:
π FINX_LANGGRAPH
π .env
π langchain_basics.py β¨New file
π Pipfile
π Pipfile.lock
π setup_environment.py
Inside this new langchain_basics.py file, let’s get started with the following imports:
from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI from setup_environment import set_environment_variables
Before we explain the imports, I want to cover a potential problem you may have here. You may have the following problem where the imports are not recognized and have red squiggly lines under them even though you just installed these libraries:

So what is going on here? Well, the virtual environment we created comes with its own Python interpreter, and the Python interpreter in your code editor is probably set to the system-wide Python interpreter. This means that the code editor doesn’t know where to find the libraries we just installed in the virtual environment.
To fix this, press Ctrl+Shift+P in VS Code to open the command palette, then type Python: Select Interpreter and select the Python interpreter from the virtual environment you created. You can find the correct one easily by comparing your root project name with the interpreter name. My root folder is FINX_LANGGRAPH, so I can find mine in the list under this name:

When you click this the red squiggly lines should go away and you’re now using the correct Python interpreter.
With that out of the way, let’s look at the imports here:
StrOutputParseris a class that will help us parse the output from the LLMs into a string format. Normally when you get the return from ChatGPT, we have to index into theresponse.choices[0].message.contentto get the response. Just think of this as a convenience class that will help us with this.ChatPromptTemplateis a class that will help us create a template for our chat prompts. This will make it easier to create prompts for the LLMs.ChatOpenAIis a class that will basically just allow us to create an instance ofOpenAIand use it with LangChain.
The value here of these output parsers and prompt templates is that they are a unified interface that we can use in the same manner without changes even if we change the LLM we are using halfway through our project or in the future.
Prompt templates
We then import the set_environment_variables function from the setup_environment file we created earlier. Now let’s continue our code by creating a prompt template:
set_environment_variables()
french_german_prompt = ChatPromptTemplate.from_template(
"Please tell me the french and german words for {word} with an example sentence for each."
)
First, we make sure to call our set_environment_variables function to set our API key. As a simple example prompt, I’ll create an example that asks for the French and German words for a given word, along with an example sentence for each. This is just a simple example to show the parts of LangChain before we get into more complex examples.
The {word} part is the template variable that we can replace with any word we want to ask about. We then create a ChatPromptTemplate instance using the from_template method and pass in our prompt string. The ChatPromptTemplate class will help us create prompts for the LLMs in a more convenient way and basically deals with formatting message history like this:
## Example of a ChatPromptTemplate
template = ChatPromptTemplate.from_messages([
("system", "You are a helpful AI bot. Your name is {name}."),
("human", "Hello, how are you doing?"),
("ai", "I'm doing well, thanks!"),
("human", "{user_input}"),
])
We need only a single message here though, which is why we use the from_template method. In this case, LangChain will assume this to be a human message so this will result in:
template = ChatPromptTemplate.from_messages([
("human", "Please tell me the french and german words for {word} with an example sentence for each.")
])
Creating a chain
Now that we have a prompt template to create our prompts, let’s continue:
llm = ChatOpenAI(model="gpt-3.5-turbo-0125") output_parser = StrOutputParser() french_german_chain = french_german_prompt | llm | output_parser
First, we define our LLM instance using the ChatOpenAI class and pass in the model w
