RunnableWithMessageHistory: память в цепочке
Урок показывает штатный способ добавить память к LCEL-цепочке.
RunnableWithMessageHistory — обёртка, которая автоматически подставляет историю сообщений по идентификатору сессии и дописывает в неё новые реплики.
Плейсхолдер для истории
Чтобы история попадала в промпт, в шаблон добавляют специальное место — MessagesPlaceholder. Туда обёртка вставит накопленные сообщения.
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages([
("system", "Ты дружелюбный помощник."),
MessagesPlaceholder(variable_name="history"),
("human", "{input}"),
])Обёртка с историей по сессии
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_openai import ChatOpenAI
store = {}
def get_history(session_id):
if session_id not in store:
store[session_id] = ChatMessageHistory()
return store[session_id]
chain = prompt | ChatOpenAI(model="gpt-4o-mini")
bot = RunnableWithMessageHistory(
chain, get_history,
input_messages_key="input",
history_messages_key="history",
)
bot.invoke({"input": "Привет, я Лена"},
config={"configurable": {"session_id": "u1"}})
print(bot.invoke({"input": "Как меня зовут?"},
config={"configurable": {"session_id": "u1"}}).content)Как работает под капотом
При вызове обёртка читает session_id из config и через вашу функцию get_history достаёт нужный объект истории. Она подставляет его сообщения в плейсхолдер history, прогоняет цепочку, а затем дописывает новую пару «вход пользователя — ответ модели» обратно в историю этой сессии. Благодаря тому, что историю возвращает ваша функция, хранилище может быть любым: память процесса, Redis, база данных — интерфейс один.
Частые ошибки
- Забыть
MessagesPlaceholder. Без него истории некуда подставиться, и память «не работает». - Один
session_idна всех. Тогда диалоги пользователей перемешаются. У каждого — свой идентификатор. - Несовпадение ключей.
input_messages_keyиhistory_messages_keyдолжны совпадать с именами в шаблоне.
Итог
MessagesPlaceholder— место в шаблоне, куда вставляется история.RunnableWithMessageHistoryавтоматически подставляет историю поsession_idи дописывает реплики.- У каждого диалога — свой
session_id; хранилище истории заменяемо.
Проверьте себя
1. Что вставляет историю сообщений в промпт?
AStrOutputParser
BMessagesPlaceholder
CRunnableLambda
DJsonOutputParser
2. Зачем нужен session_id в RunnableWithMessageHistory?
AЧтобы ускорить модель
BЧтобы у каждого диалога была своя отдельная история
CЧтобы задать температуру
DЧтобы выбрать модель