Getting started with RAG: Langchain, Google Drive, and Python
LangChain is a framework for building LLM powered apps. If you're coming from webdev-land, a useful analogy might be to think of LangChain as the [Django | Laravel | Rails]
of the LLM ecosystem: while it is possible to to build a web app using vanilla [Python | PHP | Ruby]
, you'll spend a lot of time reinventing wheels instead of working on the features that make your app unique. Similarly, once you get past "getting started" with the ChatGPT API, you'll hit some predictable speed bumps. For example:
- You want to bring your own data but bump into max token limits.
- You hit timeouts and rate limit errors and need to implement logic for retries and exponential backoffs.
- You want to swap out models and/or LLM providers but it requires rearchitecting your app.
These are just a few of the areas where LangChain's abstractions and features can rapidly accelerate the building of new features in your LLM powered app.
This tutorial looks at two scripts:
- A bare-bones ChatGPT implementation on the command line. This is "Hello World" for working with vanilla ChatGPT API in Python.
- Reproducing that same app "Hello World" app using LangChain, ChatGPT API, and Python.
When we're done, we'll have a jumping off point to start building LLM powered apps with the LangChain framework.
Hello World with Vanilla ChatGPT API
Let's first look at "Hello World" with ChatGPT and Python, which we previously discussed in this tutorial:
import openai
messages = []
while True:
message = input()
messages.append({"role": "user", "content": message})
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=messages)
reply = response["choices"][0]["message"]["content"]
print("\n" + reply + "\n")
messages.append({"role": "assistant", "content": reply})
For this to work you'll need to pip install openai
and have your OpenAI API key set as an environment variable.
These 13 lines of code give us ChatGPT on the command line. We store our chat history in a list of messages
. A message
takes the form of a dictionary with two parameters: role
and content
. Role indicates who said the thing, and can be either system
(silent instructions to the model), user
, or assistant
. content
is the body of the message. We pass the list of messages into the chatCompletion
endpoint at OpenAI, along with a parameter indicating which model we want to use. We parse the reply, print it, and and append it to messages
.
When considering what's possible with ChatGPT out of the box, this might the most bang-for-the-buck Python code I've ever written. If you want more detail on what that code's doing, check out this tutorial on getting started with ChatGPT and Python.
Hello World with LangChain and ChatGPT API
Now let's look at a implementation of this same minimal app using LangChain.
from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage
chat = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
messages = []
while True:
message = input("> ")
usr_msg = HumanMessage(content=message)
messages.append(usr_msg)
ai_msg = chat(messages)
print(ai_msg.content)
messages.append(ai_msg)
Again, you'll need to pip install langchain
for this to work, and set your OpenAI API Key as an environment variable for this to work.
Here's what's happening, step by step.
Import Langchain modules
from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage
The first two lines import the minimal required classes from the LangChain library. ChatOpenAI
is responsible for creating the chatbot instance. HumanMessage
is a class used to represent messages from the user.
A fundamental concept to understand when working with LangChain and ChatGPT is that instead of passing around text, LangChain uses Message
objects. LangChain also has AIMessage
and SystemMessage
classes, which we do not need to import for this minimal app – but the existence of these three classes marks a significant departure from our need to manually construct a dictionary to store the message in our vanilla example.
Create the chatbot instance
chat = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
We create an instance of the ChatOpenAI
class with two parameters: model
and temperature
. The model
parameter specifies which AI model to use, in this case, gpt-3.5-turbo
.
temperature
controls the randomness in ChatGPT's replies. When working directly with the ChatGPT API, the temperature parameter is optional, but LangChain requires it. You can set temperature between 0
and 2
. The closer to 2
, the more variance you'll see in ChatGPT's replies. Here we set temperature
to 0
, which makes the output deterministic and focused, meaning it will always generate the same response for the same input.
Initialize the messages list
messages = []
Like our previous example, we store our chat history in a list of messages.
Start the chat loop
while True:
An infinite loop (while True:
) keeps the conversation going until the user terminates the script manually.
Gather user input
message = input("> ")
We prompt the user to input a message, which is stored in the message
variable.
Create a HumanMessage object
usr_msg = HumanMessage(content=message)
We initialize a HumanMessage
object, with the content
parameter set to the user's input.
Append the user's message to the chat history
messages.append(usr_msg)
We append usr_msg
to the messages
list, updating the chat history.
Generate the AI's response
ai_msg = chat(messages)
This line, compared to the vanilla API call, best demonstrates the simplicity you get from LangChain's abstractions.
The chat
instance is called with the messages
list as its argument. The AI processes the conversation history and returns a response in the form of an AIMessage
, which we store in the ai_msg
variable.
Print ChatGPT's response
print(ai_msg.content)
We print ChatGPT's response. Again, notice the simplicity here versus processing the full dictionary returned by the vanilla API call. You can access the content
of a langchain Message
object by using the dot operator.
Append the AI Message to the chat history
messages.append(ai_msg)
Finally, the AI's response is appended to the messages
list, updating the conversation
After this, our loop repeats, gathering input from the user, getting replies from ChatGPT, and appending both to the chat history, until the user kills the script.
What's Next
That's it! When you run this script you'll get a carbon-copy experience of the original Hello World script, and now you have the foundation in place to start building robust, feature rich LLM-powered apps using LangChain. In future posts we'll explore LangChain features such as:
- Using Prompt Templates
- Adding Memory to your LLM apps
- Building LLM Chains to have models interact with each other
- Building Agents which use LLMs in conjunction with other tools, such as data retrieval or code execution