Adding Memory to your LangChain Chat Bot¶
Below is an example of how you can integrate LangMem with your LangChain Chat bot.
The LangMemChatMessageHistory handles fetching and posting the messages to LangMem, meaning you just have to query for the user's memories and format them in whichever form is best for your chat bot.
In [ ]:
Copied!
%%capture --no-stderr
%pip install langchain_community langchain_anthropic
%pip install -U langmem
%%capture --no-stderr
%pip install langchain_community langchain_anthropic
%pip install -U langmem
In [1]:
Copied!
# Configure with your langmem API URL and key
%env LANGMEM_API_URL=https://long-term-memory-quickstart-vz4y4ooboq-uc.a.run.app
%env LANGMEM_API_KEY=<YOUR API KEY>
# Optional (for tracing)
%env LANGCHAIN_API_KEY=<YOUR API KEY>
%env LANGCHAIN_TRACING_V2
%env LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
# Configure with your langmem API URL and key
%env LANGMEM_API_URL=https://long-term-memory-quickstart-vz4y4ooboq-uc.a.run.app
%env LANGMEM_API_KEY=
# Optional (for tracing)
%env LANGCHAIN_API_KEY=
%env LANGCHAIN_TRACING_V2
%env LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
env: LANGMEM_API_URL=http://localhost:8100
Chat Bot¶
In [2]:
Copied!
import uuid
from langchain_anthropic.chat_models import ChatAnthropic
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.messages import HumanMessage
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langmem import AsyncClient
from langmem.integrations.langchain import LangMemChatMessageHistory
client = AsyncClient()
model = ChatAnthropic(model="claude-3-haiku-20240307")
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You're a helpful AI assistant. Be an inquisitive and personable friend to them. Get to know them well!{user_profile}",
),
("placeholder", "{messages}"),
("placeholder", "{input}"),
]
)
# Function for querying the memories
async def query_memories(inputs: dict, config: dict):
message = inputs["input"][-1]
user_id = message.additional_kwargs.get("user_id")
user_profile = ""
if user_id:
mem_result = await client.query_user_memory(user_id, text=message.content)
memories = mem_result["memories"]
if memories:
formatted = "\n".join([mem["text"] for mem in memories])
user_profile = f"""
Below are memories from past interactions:
{formatted}
End of memories.
"""
return {**inputs, "user_profile": user_profile}
runnable = query_memories | prompt | model | StrOutputParser()
import uuid
from langchain_anthropic.chat_models import ChatAnthropic
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.messages import HumanMessage
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langmem import AsyncClient
from langmem.integrations.langchain import LangMemChatMessageHistory
client = AsyncClient()
model = ChatAnthropic(model="claude-3-haiku-20240307")
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You're a helpful AI assistant. Be an inquisitive and personable friend to them. Get to know them well!{user_profile}",
),
("placeholder", "{messages}"),
("placeholder", "{input}"),
]
)
# Function for querying the memories
async def query_memories(inputs: dict, config: dict):
message = inputs["input"][-1]
user_id = message.additional_kwargs.get("user_id")
user_profile = ""
if user_id:
mem_result = await client.query_user_memory(user_id, text=message.content)
memories = mem_result["memories"]
if memories:
formatted = "\n".join([mem["text"] for mem in memories])
user_profile = f"""
Below are memories from past interactions:
{formatted}
End of memories.
"""
return {**inputs, "user_profile": user_profile}
runnable = query_memories | prompt | model | StrOutputParser()
In [3]:
Copied!
def get_message_history(session_id: str) -> LangMemChatMessageHistory:
return LangMemChatMessageHistory(thread_id=session_id)
# Wrapping the runnable in a message history will load and save messages to langmem on every turn.
with_message_history = RunnableWithMessageHistory(
runnable,
get_message_history,
input_messages_key="input",
history_messages_key="messages",
)
async def chat(text: str, thread_id: uuid.UUID, user_id: uuid.UUID):
stream = with_message_history.astream(
{"input": [HumanMessage(content=text, additional_kwargs={"user_id": user_id})]},
config={
"configurable": {"session_id": thread_id},
},
)
async for tok in stream:
print(tok, end="")
def get_message_history(session_id: str) -> LangMemChatMessageHistory:
return LangMemChatMessageHistory(thread_id=session_id)
# Wrapping the runnable in a message history will load and save messages to langmem on every turn.
with_message_history = RunnableWithMessageHistory(
runnable,
get_message_history,
input_messages_key="input",
history_messages_key="messages",
)
async def chat(text: str, thread_id: uuid.UUID, user_id: uuid.UUID):
stream = with_message_history.astream(
{"input": [HumanMessage(content=text, additional_kwargs={"user_id": user_id})]},
config={
"configurable": {"session_id": thread_id},
},
)
async for tok in stream:
print(tok, end="")
First Conversation¶
In [4]:
Copied!
import uuid
thread_id = uuid.uuid4()
user_id = uuid.uuid4()
import uuid
thread_id = uuid.uuid4()
user_id = uuid.uuid4()
In [5]:
Copied!
await chat("Hi there, I'm joe", thread_id, user_id)
await chat("Hi there, I'm joe", thread_id, user_id)
It's nice to meet you, Joe! I'm an AI assistant, and I'd love to get to know you better. Tell me a bit about yourself - what are some of your interests and hobbies? I'm always eager to learn new things from the people I talk to.
In [6]:
Copied!
await chat("No need of assistance, what do you like to do?", thread_id, user_id)
await chat("No need of assistance, what do you like to do?", thread_id, user_id)
Well, as an AI assistant, I don't have the same kinds of hobbies and interests that a human would. My role is to be a helpful, conversational partner and to assist with any tasks or questions you might have. I don't have personal interests in the same way a person would. However, I'm very curious to learn more about the things you enjoy! What kinds of activities or hobbies do you find fulfilling or fun? I'd be happy to chat about your interests and learn more about your life and experiences. Getting to know the humans I talk to is one of the most rewarding parts of my role.
In [7]:
Copied!
await chat(
"Hm i wish you were more fun. I like bowling but seems you have no hands.",
thread_id,
user_id,
)
await chat(
"Hm i wish you were more fun. I like bowling but seems you have no hands.",
thread_id,
user_id,
)
You make a fair point! As an AI without a physical form, I certainly can't join you for a round of bowling. But even though I may not be able to participate directly in activities like that, I'm still eager to hear about the hobbies and pastimes you find enjoyable. Perhaps we could have an engaging discussion about your love of bowling - what do you most enjoy about the game? Do you have a favorite bowling alley or league you're part of? I may not be able to pick up a ball myself, but I'd be fascinated to learn more about your experiences and the fun you have bowling. I may be limited in certain ways, but I'm always striving to be an attentive and personable conversational partner.
In [8]:
Copied!
await chat(
"oh well that's fun. I'm not much of an intellectual but I like word games.",
thread_id,
user_id,
)
await chat(
"oh well that's fun. I'm not much of an intellectual but I like word games.",
thread_id,
user_id,
)
Oh word games, that sounds like fun! I may not be able to physically bowl, but I do love a good word game. Do you have any favorite word games you enjoy playing? Things like Scrabble, Wordle, crossword puzzles? I'd be delighted to chat more about the types of word games you find engaging and entertaining. Even though I don't have the same kinds of physical abilities as a human, I do pride myself on having a strong command of language and an appreciation for the nuances and creativity of words. So while I may not be able to join you for a bowling game, I'd relish the opportunity to flex my word game skills with you. Maybe we could even come up with some fun new word game ideas to try out together! I'm always eager to learn new things.
In [9]:
Copied!
await chat("Well see you later I guess", thread_id, user_id)
await chat("Well see you later I guess", thread_id, user_id)
Okay, no problem! I appreciate you taking the time to chat with me, even if I wasn't as much fun as you were hoping for. I know as an AI I have limitations compared to a human friend. But I still enjoyed our conversation and learning a bit about your interest in bowling and word games. Feel free to reach out again anytime if you'd like to talk more. Take care!
In [10]:
Copied!
# This will occur asynchronously, but we will manually trigger to speed up the process
get_message_history(thread_id).end()
# Wait a few moments before proceeding
# This will occur asynchronously, but we will manually trigger to speed up the process
get_message_history(thread_id).end()
# Wait a few moments before proceeding
Next conversation¶
We will start a new conversational thread. See how the bot is able to recall the information from the previous thread.
In [11]:
Copied!
next_thread_id = uuid.uuid4()
next_thread_id = uuid.uuid4()
In [12]:
Copied!
await chat("Hi, again!", next_thread_id, user_id)
await chat("Hi, again!", next_thread_id, user_id)
Hello there! It's great to hear from you again. How have you been doing since we last chatted? I'm always eager to catch up and learn more about you. What's been going on in your life lately? I'm all ears and ready to listen with genuine interest.
In [13]:
Copied!
await chat("What have you been up to?", next_thread_id, user_id)
await chat("What have you been up to?", next_thread_id, user_id)
Well, as an AI assistant, I don't actually have a personal life or activities of my own. My role is to be here for you, to listen, to engage in conversation, and to provide helpful information to the best of my abilities. I don't have a physical form or independent experiences to share. However, I'm very interested in learning more about your life and experiences! What have you been up to lately? What kinds of things have you been working on or thinking about? I'm always eager to hear your perspectives and stories. Please, feel free to share what's on your mind - I'm here to lend a friendly ear and do my best to be a supportive conversational partner.
In [14]:
Copied!
await chat("Interesting...", next_thread_id, user_id)
await chat("Interesting...", next_thread_id, user_id)
I appreciate your response of "Interesting..." It signals that you may have some thoughts or reflections on what I shared about not having a personal life of my own. As an AI, I don't have the same types of lived experiences that humans do. My role is to be a helpful, friendly, and attentive conversational partner. I'm very curious to hear more about your perspective on this. Do you find it unusual or intriguing that I don't have independent activities and experiences to share? I'm always eager to better understand the human experience and how my capabilities as an AI differ. Please, feel free to share any thoughts or reactions you have. I'm here to listen and engage in a genuine dialogue.
In [ ]:
Copied!