Chat History and Memory
A model forgets everything the moment it answers. Every call starts fresh.
If you want a real conversation, you have to send the old messages again each time.
That list of old messages is the chat history. Keeping it is what people call memory.
Think of a librarian with a notebook. She does not remember you. But she writes down every visit, and reads the notebook before she answers.
The simple way: a Python list
You already know the pieces. A list, a MessagesPlaceholder, and append.
The placeholder is where the old messages will go. The new question goes last.
After each answer you append both the question and the reply. Next time, the model sees them.
This is all memory really is. Everything else in this lesson is a tidier way to do the same thing.
Why the simple way is not enough
One global list means every user shares one memory. Bad for a website.
You have to remember to append in the right place every time.
The list only lives in RAM. Restart the program and it is gone.
One history per session
InMemoryChatMessageHistory is a small object that holds a list of messages. Keep one per user in a dict.
The function takes a session id and returns that session's history. New id, new empty history.
Later you can swap InMemoryChatMessageHistory for one backed by a database. The rest stays the same.
RunnableWithMessageHistory: memory that manages itself
This wrapper reads the history before the call and saves the new messages after. You never call append.
input_messages_key says which input is the new human message. history_messages_key says which placeholder gets the old ones.
The session id travels in config, not in the input. Use a different id and you get a fresh conversation.
When history gets too long
Every message you send costs tokens. A long chat gets slow and expensive, and can hit the model's limit.
trim_messages cuts the list down before it goes to the model.
strategy last keeps the newest messages. include_system keeps the system message even if it is old.
start_on human makes sure the trimmed list begins with a human turn, which models expect.
You can put the trimmer inside the chain as a step, so it runs on every call.
The big picture
The model never remembers. Your code does, by resending old messages.
A plain list works for scripts and quick tests.
RunnableWithMessageHistory gives each session its own memory and handles the saving.
Trim long histories so you do not run out of tokens or money.
For serious apps, LangGraph has built in persistence. That is lesson 25.
Remember: memory is just old messages sent again. The session id in config decides whose messages get sent.
Test yourself
Three quick questions made just for this lesson. Earn 10 XP per correct answer.