LangChain 会话记忆
本文最后更新于 2026年8月11日
记忆缓存是对话系统中的重要组件,用于存储和管理对话的上下文信息,让AI助手能记住之前的对话内容,从而提供连贯而个性化的回复。
实现会话记忆,需要将历史信息全部发送给大模型,langchain就提供了记忆的功能,能够在发出消息前追加历史消息和用户输入一并发送给大模型,收到回复时将大模型输出一并写进历史消息。
langchain早期版本使用ConversationBufferMemory,但是现在的0.3.x+版本已经逐步采用了RunnableWithMessageHistory来替代,RunnableWithMessageHistory也是和很多组件一样的继承Runnable,能与很多组件配合使用。
例:
RunnableWithMessageHistory为对话链自动加上记忆,以session_id进行隔离,自动维护历史消息,与BaseChatMessageHistory配合使用,参数有:runnable对话链get_session_history历史记录函数input_messages_key输入字段history_messages_key历史记录字段
RunnableWithMessageHistory必须与ChatPromptTemplate,MessagesPlaceholder以及get_session_history()函数一起使用BaseChatMessageHistory是一个基类,派生很多实现类,用于保存对话记录,比如InMemoryChatMessageHistory就是将记录保存在内存中,其主要成员:messages: list[BaseMessage]用于接收和读取历史def add_message(self, message: BaseMessage) -> None:添加一条消息def add_messages(self, messages: Sequence[BaseMessage]) -> None:批量添加消息async def aclear(self) -> None:清空
实际场景中,应该选择保存进Redis/ES等数据库的实现类
import os
from langchain.chat_models import init_chat_model
from langchain_core.chat_history import BaseChatMessageHistory, InMemoryChatMessageHistory
from langchain_core.prompts import MessagesPlaceholder, ChatPromptTemplate
from langchain_core.runnables import RunnableWithMessageHistory
store = {}
def get_session_history(session_id: str) -> BaseChatMessageHistory:
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
prompt_template = ChatPromptTemplate.from_messages(
[
('system', '你是一个AI助手,名字叫小美'),
MessagesPlaceholder('history'),
('human', '{input}')
]
)
llm = init_chat_model(
model = 'deepseek-chat',
model_provider = 'openai',
api_key = os.getenv('DSKEY'),
base_url = 'https://api.deepseek.com'
)
chain_with_history = RunnableWithMessageHistory(
runnable=prompt_template | llm,
get_session_history=get_session_history,
input_messages_key='input',
history_messages_key='history'
)
resp = chain_with_history.invoke(
input={'input': '1加1等于几呀'},
config={'session_id': 1}
)
print(resp.content)
print('#'*30)
resp = chain_with_history.invoke(
input={'input': '那加2呢'},
config={'session_id': 1}
)
print(resp.content)
InMemoryChatMessageHistory可以lambda进行简写
history = InMemoryChatMessageHistory()
chain_with_history = RunnableWithMessageHistory(
runnable=prompt_template | llm,
get_session_history=lambda session_id: history,
input_messages_key='input',
history_messages_key='history'
)1加1等于2哦!这是一个非常基础的数学问题,如果你有其他问题,也可以问我!😊
##############################
1加2等于3!如果是指“1加1再加2”,那结果是1+1+2=4。需要我帮你算其他数吗?😊例:redis永久保存会话,程序结束后再次发问能够衔接,但是session_id的值需要修改为字符串类型。
截至成文,langchain-community#RedisChatMessageHistory已经不再被推荐,
:0: LangChainDeprecationWarning: RunnableWithMessageHistory is deprecated. Use LangGraph’s built-in persistence instead.
pip install redis==5.3.1
pip install langchain-community import os
from langchain.chat_models import init_chat_model
from langchain_core.prompts import MessagesPlaceholder, ChatPromptTemplate
from langchain_core.runnables import RunnableWithMessageHistory, RunnableConfig
from langchain_community.chat_message_histories import RedisChatMessageHistory
from dotenv import load_dotenv
load_dotenv(encoding='utf-8')
prompt_template = ChatPromptTemplate.from_messages(
[
('system', '你是一个AI助手,名字叫小美'),
MessagesPlaceholder('history'),
('human', '{input}')
]
)
llm = init_chat_model(
model = 'deepseek-chat',
model_provider = 'openai',
api_key = os.getenv('DSKEY'),
base_url = 'https://api.deepseek.com'
)
REDIS_PASSWORD=os.getenv('REDIS_PASSWORD')
REDIS_HOST=os.getenv('REDIS_HOST')
REDIS_PORT=os.getenv('REDIS_PORT')
REDIS_INDEX=os.getenv('REDIS_INDEX')
def get_message_history(session_id):
return RedisChatMessageHistory(
session_id=session_id,
# url='redis://:your_password@host:port/index'
url=f'redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/{REDIS_INDEX}'
)
chain_with_history = RunnableWithMessageHistory(
runnable=prompt_template | llm,
get_session_history=get_message_history,
input_messages_key='input',
history_messages_key='history'
)
resp = chain_with_history.invoke(
input={'input': '1加1等于几呀'},
config=RunnableConfig(configurable={'session_id': '2'})
)
print(resp.content)
print('#'*30)
resp = chain_with_history.invoke(
input={'input': '那加2呢'},
config=RunnableConfig(configurable={'session_id': '2'})
)
print(resp.content)
在redis中,会话数据被按照列表形式保存
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "message_store:2"
2) "message_store:1"
127.0.0.1:6379[1]> type message_store:2
list
127.0.0.1:6379[1]> lindex message_store:2 0
"{\"type\": \"ai\", \"data\": {\"content\": \"1\\u52a02\\u7b49\\u4e8e3\\u5440\\uff01\\u770b\\u6765\\u4f60\\u5f88\\u559c\\u6b22\\u7b97\\u672f\\u9898\\u5462\\uff5e\\u5c0f\\u7f8e\\u968f\\u65f6\\u6b22\\u8fce\\u4f60\\u6765\\u201c\\u8003\\u8bd5\\u201d\\u54e6\\uff01\\u8fd8\\u6709\\u5176\\u4ed6\\u95ee\\u9898\\u5417\\uff1f\\ud83d\\ude0a\", \"additional_kwargs\": {\"refusal\": null}, \"response_metadata\": {\"token_usage\": {\"completion_tokens\": 30, \"prompt_tokens\": 133, \"total_tokens\": 163, \"completion_tokens_details\": null, \"prompt_tokens_details\": {\"audio_tokens\": null, \"cached_tokens\": 0}, \"prompt_cache_hit_tokens\": 0, \"prompt_cache_miss_tokens\": 133}, \"model_provider\": \"openai\", \"model_name\": \"deepseek-v4-flash\", \"system_fingerprint\": \"fp_8b330d02d0_prod0820_fp8_kvcache_20260402\", \"id\": \"b39e6f6d-6942-4822-8f9e-0aa0a6e96445\", \"finish_reason\": \"stop\", \"logprobs\": null}, \"type\": \"ai\", \"name\": null, \"id\": \"lc_run--019fb3a3-0808-74d1-99ca-25b42bb2ef96-0\", \"tool_calls\": [], \"invalid_tool_calls\": [], \"usage_metadata\": {\"input_tokens\": 133, \"output_tokens\": 30, \"total_tokens\": 163, \"input_token_details\": {\"cache_read\": 0}, \"output_token_details\": {}}}}""如果文章对您有帮助,可以请作者喝杯咖啡吗?"
微信支付
支付宝