Welcome to your next lesson on LangChain! So far, you've learned how to send basic messages to AI models, customize their parameters, and structure conversations using SystemMessage
and HumanMessage
. These skills have given you the foundation to create single-turn interactions with AI models. However, real-world conversations rarely consist of just one exchange.
Think about how you communicate with friends or colleagues. You ask a question, they respond, and then you might ask a follow-up question based on their answer. This natural flow of conversation relies on both participants remembering what was previously discussed. Without this shared context, conversations would feel disjointed and repetitive. The same principle applies when building AI applications. To create truly engaging and helpful AI assistants, we need to maintain conversation history across multiple exchanges. This allows the AI to understand references to previous messages and provide coherent, contextually appropriate responses.
In this lesson, we'll build on your knowledge of message types to implement multi-turn conversations. You'll learn how to create and manage a persistent conversation history, enabling the AI to maintain context across multiple exchanges. By the end of this lesson, you'll be able to create a conversational AI that can remember previous exchanges and respond appropriately to follow-up questions. Let's get started!
In our previous lesson, we learned how to use SystemMessage
and HumanMessage
classes to structure a single exchange with an AI model. Now, we'll expand on this concept by working with lists of messages that persist throughout a conversation.
The key to managing conversation history in LangChain is to maintain a list of messages that grows as the conversation progresses. Each message in this list represents a turn in the conversation, whether it's a system instruction, a human query, or an AI response.
Let's start by creating a message list to store our conversation:
Python1from langchain.schema.messages import SystemMessage, HumanMessage 2 3# Define initial messages for the conversation 4messages = [ 5 SystemMessage(content="You are a math assistant"), 6 HumanMessage(content="What is the square root of 9?") 7]
In this code, we're creating a list called messages
that contains our initial conversation state. We start with a system message that defines the AI's role as a math assistant, followed by a human message asking about the square root of 9. This list will serve as the foundation for our ongoing conversation.
Now that we have our initial messages list, let's send it to the AI model to get a response:
Python1from langchain_openai import ChatOpenAI 2 3# Create a ChatOpenAI instance 4chat = ChatOpenAI(model="gpt-4o-mini", max_tokens=50) 5 6# Send the initial messages to the AI model 7response = chat.invoke(messages) 8 9# Display the first AI response 10print(f"First Response: {response.content}")
When we run this code, we'll see output similar to:
Plain text1First Response: The square root of 9 is 3.
Notice that we're passing the entire messages
list to the invoke
method, not just the human message. This allows the AI to see both the system instruction (that it should act as a math assistant) and the human query (about the square root of 9). The AI then generates a response based on this complete context.
To create a true multi-turn conversation, we need to add the AI's response to our message history and then ask a follow-up question. This is where the AIMessage
class comes into play.
After receiving the AI's response, we can add it to our message list using the AIMessage
class:
Python1from langchain.schema.messages import AIMessage 2 3# Add the AI's response to the conversation history 4messages.append(AIMessage(content=response.content))
This line takes the content of the AI's response and wraps it in an AIMessage
object, which we then append to our messages
list. Our conversation history now contains three messages: the system instruction, the human's first question, and the AI's response.
With the AI's response added to our conversation history, we can now ask a follow-up question:
Python1# Add a new human message to the conversation 2messages.append(HumanMessage(content="And 16?"))
This line adds a new human message to our conversation history. Notice that the message is quite brief: "And 16?" In a normal conversation without history, this would be too vague for the AI to understand. However, because we're maintaining conversation history, the AI will have the context to understand that we're asking about the square root of 16.
Now that we've updated our conversation history with both the AI's first response and our follow-up question, let's send the updated messages list to the AI model:
Python1# Send the updated conversation to the AI model 2response = chat.invoke(messages) 3 4# Display the second AI response 5print(f"Second Response: {response.content}")
It's important to note that we're passing the entire messages
list to the invoke
method again, not just the new human message. This list now contains four messages: the system instruction, the first human question, the AI's first response, and the follow-up question. By sending the complete conversation history, we ensure the AI has all the context it needs to provide a relevant response.
When we run this code, we'll see output similar to:
Plain text1Second Response: The square root of 16 is 4
The AI correctly interprets our follow-up question as asking for the square root of 16, even though we didn't explicitly mention "square root" in our second message. This demonstrates the power of maintaining conversation history: the AI can understand context and references to previous exchanges, enabling more natural and efficient communication.
Let's put everything together to see the complete implementation of our conversational math assistant:
Python1from langchain_openai import ChatOpenAI 2from langchain.schema.messages import SystemMessage, HumanMessage, AIMessage 3 4# Create a ChatOpenAI instance 5chat = ChatOpenAI(model="gpt-4o-mini", max_tokens=150) 6 7# Define initial messages for the conversation 8messages = [ 9 SystemMessage(content="You are a math assistant"), 10 HumanMessage(content="What is the square root of 9?") 11] 12 13# Send the initial messages to the AI model 14response = chat.invoke(messages) 15print(f"First Response: {response.content}") 16 17# Add the AI's response to the conversation history 18messages.append(AIMessage(content=response.content)) 19 20# Add a new human message to the conversation 21messages.append(HumanMessage(content="And 16?")) 22 23# Send the updated conversation to the AI model 24response = chat.invoke(messages) 25print(f"Second Response: {response.content}")
This code demonstrates a complete multi-turn conversation with an AI assistant. We start with a system message and a human query, get a response from the AI, add that response to our conversation history, ask a follow-up question, and then get another response that takes into account the full conversation context.
In this lesson, you've learned how to manage conversation history in LangChain to create multi-turn interactions with AI models. Here are the key concepts we covered:
- Using message lists to maintain conversation state across multiple exchanges
- Incorporating the
AIMessage
class to capture and store AI responses - Adding new messages to an ongoing conversation
- Leveraging conversation history to enable contextual understanding of follow-up questions
These techniques allow you to build more sophisticated AI applications that can engage in natural, flowing conversations with users. By maintaining conversation history, your AI assistants can understand references to previous messages, remember information shared earlier in the conversation, and provide more coherent and contextually appropriate responses.
As you work through the practice exercises, try to think about how you might apply these techniques to your own projects. Consider what types of conversations would benefit from maintained history, and how you might structure your message lists to support different conversation flows. Happy coding!