记忆功能
大语言模型本身是无状态的,每次调用都是独立的。记忆(Memory)功能让 AI 应用能够记住之前的对话内容,实现真正的连续对话体验。
为什么需要记忆
没有记忆的对话:
用户:我叫小明
AI:你好小明!
用户:我叫什么名字?
AI:抱歉,我不知道你的名字。 ← 忘记了!
有记忆的对话:
用户:我叫小明
AI:你好小明!
用户:我叫什么名字?
AI:你叫小明。 ← 记住了!
记忆的实现原理
记忆的本质是将历史对话作为上下文传递给模型:
# 实际发送给模型的内容
messages = [
SystemMessage(content="你是一个助手"),
HumanMessage(content="我叫小明"), # 历史消息
AIMessage(content="你好小明!"), # 历史消息
HumanMessage(content="我叫什么名字?") # 当前消息
]
基础记忆类型
ConversationBufferMemory
最简单的记忆类型,保存所有对话历史:
from langchain.memory import ConversationBufferMemory
from langchain_openai import ChatOpenAI
from langchain.chains import ConversationChain
from dotenv import load_dotenv
load_dotenv()
# 创建记忆
memory = ConversationBufferMemory()
# 创建对话链
llm = ChatOpenAI(model="gpt-3.5-turbo")
conversation = ConversationChain(
llm=llm,
memory=memory,
verbose=True # 显示详细信息
)
# 对话
print(conversation.predict(input="你好,我叫小明"))
print(conversation.predict(input="你还记得我的名字吗?"))
# 查看记忆内容
print(memory.buffer)
ConversationBufferWindowMemory
只保留最近 N 轮对话:
from langchain.memory import ConversationBufferWindowMemory
# 只保留最近3轮对话
memory = ConversationBufferWindowMemory(k=3)
conversation = ConversationChain(
llm=llm,
memory=memory
)
# 进行多轮对话
for i in range(5):
response = conversation.predict(input=f"这是第{i+1}轮对话")
print(f"轮次{i+1}: {response[:50]}...")
# 记忆只包含最近3轮
print("\n记忆内容:")
print(memory.buffer)
ConversationSummaryMemory
将历史对话总结为摘要,节省 Token:
from langchain.memory import ConversationSummaryMemory
# 需要一个 LLM 来生成摘要
memory = ConversationSummaryMemory(llm=llm)
conversation = ConversationChain(
llm=llm,
memory=memory
)
# 长对话后查看摘要
conversation.predict(input="我是一名软件工程师,在北京工作")
conversation.predict(input="我主要用 Python 和 JavaScript 编程")
conversation.predict(input="我对人工智能很感兴趣")
print("对话摘要:")
print(memory.buffer)
ConversationSummaryBufferMemory
结合缓冲区和摘要,保留最近的完整对话,较早的进行摘要:
from langchain.memory import ConversationSummaryBufferMemory
memory = ConversationSummaryBufferMemory(
llm=llm,
max_token_limit=200 # 当超过200 token时开始摘要
)
conversation = ConversationChain(
llm=llm,
memory=memory
)
使用 LCEL 实现记忆
现代 LangChain 推荐使用 LCEL 和手动管理历史消息:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage
from langchain_core.output_parsers import StrOutputParser
from dotenv import load_dotenv
load_dotenv()
# 创建模型和提示词
llm = ChatOpenAI(model="gpt-3.5-turbo")
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个友好的助手。"),
MessagesPlaceholder(variable_name="history"),
("human", "{input}")
])
chain = prompt | llm | StrOutputParser()
# 手动管理历史
class ChatWithMemory:
def __init__(self):
self.history = []
def chat(self, message: str) -> str:
# 调用链
response = chain.invoke({
"history": self.history,
"input": message
})
# 更新历史
self.history.append(HumanMessage(content=message))
self.history.append(AIMessage(content=response))
return response
def clear(self):
self.history = []
# 使用
chat = ChatWithMemory()
print(chat.chat("我叫小明"))
print(chat.chat("你还记得我的名字吗?"))
记忆类型选择
| 记忆类型 | 特点 | 适用场景 |
|---|---|---|
| Buffer | 保存全部历史 | 短对话,需要完整上下文 |
| BufferWindow | 保存最近 N 轮 | 长对话,只关心近期内容 |
| Summary | 摘要所有历史 | 非常长的对话 |
| SummaryBuffer | 混合模式 | 平衡完整性和效率 |
| Token Buffer | 按 Token 限制 | 精确控制上下文长度 |
ConversationTokenBufferMemory
按 Token 数量限制记忆:
from langchain.memory import ConversationTokenBufferMemory
memory = ConversationTokenBufferMemory(
llm=llm,
max_token_limit=500 # 最多保留500个token
)
持久化存储
保存到文件
import json
from langchain_core.messages import HumanMessage, AIMessage, messages_to_dict, messages_from_dict
class PersistentMemory:
def __init__(self, filepath: str):
self.filepath = filepath
self.history = self._load()
def _load(self) -> list:
"""从文件加载历史"""
try:
with open(self.filepath, 'r', encoding='utf-8') as f:
data = json.load(f)
return messages_from_dict(data)
except FileNotFoundError:
return []
def save(self):
"""保存历史到文件"""
with open(self.filepath, 'w', encoding='utf-8') as f:
json.dump(messages_to_dict(self.history), f, ensure_ascii=False, indent=2)
def add_message(self, message):
"""添加消息并保存"""
self.history.append(message)
self.save()
def clear(self):
"""清除历史"""
self.history = []
self.save()
# 使用
memory = PersistentMemory("chat_history.json")
memory.add_message(HumanMessage(content="你好"))
memory.add_message(AIMessage(content="你好!有什么可以帮助你的?"))
使用 Redis 存储
from langchain_community.chat_message_histories import RedisChatMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
# 创建 Redis 历史存储
def get_session_history(session_id: str):
return RedisChatMessageHistory(
session_id=session_id,
url="redis://localhost:6379"
)
# 创建带历史的链
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个助手"),
MessagesPlaceholder(variable_name="history"),
("human", "{input}")
])
chain = prompt | llm
chain_with_history = RunnableWithMessageHistory(
chain,
get_session_history,
input_messages_key="input",
history_messages_key="history"
)
# 使用(不同 session_id 有不同的历史)
response = chain_with_history.invoke(
{"input": "你好"},
config={"configurable": {"session_id": "user_123"}}
)
使用 SQLite 存储
from langchain_community.chat_message_histories import SQLChatMessageHistory
def get_session_history(session_id: str):
return SQLChatMessageHistory(
session_id=session_id,
connection_string="sqlite:///chat_history.db"
)
# 用法同上
多用户会话管理
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory
# 会话存储
session_store = {}
def get_session_history(session_id: str) -> ChatMessageHistory:
if session_id not in session_store:
session_store[session_id] = ChatMessageHistory()
return session_store[session_id]
# 创建链
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个助手"),
MessagesPlaceholder(variable_name="history"),
("human", "{input}")
])
chain = prompt | llm | StrOutputParser()
# 包装成带历史的链
chain_with_history = RunnableWithMessageHistory(
chain,
get_session_history,
input_messages_key="input",
history_messages_key="history"
)
# 用户 A 的对话
response_a1 = chain_with_history.invoke(
{"input": "我叫小明"},
config={"configurable": {"session_id": "user_a"}}
)
# 用户 B 的对话
response_b1 = chain_with_history.invoke(
{"input": "我叫小红"},
config={"configurable": {"session_id": "user_b"}}
)
# 用户 A 继续对话(记住是小明)
response_a2 = chain_with_history.invoke(
{"input": "我叫什么名字?"},
config={"configurable": {"session_id": "user_a"}}
)
print(response_a2) # 你叫小明
实体记忆
记住对话中提到的实体信息:
from langchain.memory import ConversationEntityMemory
from langchain.chains import ConversationChain
# 创建实体记忆
memory = ConversationEntityMemory(llm=llm)
conversation = ConversationChain(
llm=llm,
memory=memory,
verbose=True
)
# 对话中提到实体
conversation.predict(input="张三是我的同事,他是一名工程师")
conversation.predict(input="李四是我的朋友,他喜欢打篮球")
# 查看记住的实体
print("记住的实体:")
print(memory.entity_store.store)
完整示例:智能客服系统
"""
智能客服系统 - 记忆功能示例
"""
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage
from langchain_core.output_parsers import StrOutputParser
from datetime import datetime
from dotenv import load_dotenv
load_dotenv()
class CustomerServiceBot:
"""智能客服机器人"""
def __init__(self, max_history: int = 10):
self.llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)
self.max_history = max_history
self.sessions = {} # 会话存储
# 系统提示词
self.system_prompt = """你是一个专业的客服助手,名叫小智。
你的职责:
1. 友好地回答客户问题
2. 帮助解决产品使用问题
3. 处理投诉和建议
4. 引导客户找到正确的解决方案
注意事项:
- 保持专业、友好的态度
- 如果无法解决问题,建议转人工客服
- 记住客户之前提到的信息
当前时间:{time}"""
# 创建提示词模板
self.prompt = ChatPromptTemplate.from_messages([
("system", self.system_prompt),
MessagesPlaceholder(variable_name="history"),
("human", "{input}")
])
# 创建链
self.chain = self.prompt | self.llm | StrOutputParser()
def get_session(self, session_id: str) -> list:
"""获取会话历史"""
if session_id not in self.sessions:
self.sessions[session_id] = {
"history": [],
"created_at": datetime.now(),
"last_active": datetime.now()
}
return self.sessions[session_id]
def chat(self, session_id: str, message: str) -> str:
"""处理客户消息"""
session = self.get_session(session_id)
# 调用链
response = self.chain.invoke({
"time": datetime.now().strftime("%Y-%m-%d %H:%M"),
"history": session["history"],
"input": message
})
# 更新历史
session["history"].append(HumanMessage(content=message))
session["history"].append(AIMessage(content=response))
session["last_active"] = datetime.now()
# 限制历史长度
if len(session["history"]) > self.max_history * 2:
session["history"] = session["history"][-self.max_history * 2:]
return response
def get_summary(self, session_id: str) -> str:
"""获取会话摘要"""
session = self.get_session(session_id)
if not session["history"]:
return "暂无对话记录"
summary_prompt = ChatPromptTemplate.from_template(
"""总结以下客服对话的要点:
{conversation}
摘要:"""
)
conversation = "\n".join([
f"{'客户' if isinstance(m, HumanMessage) else '客服'}: {m.content}"
for m in session["history"]
])
chain = summary_prompt | self.llm | StrOutputParser()
return chain.invoke({"conversation": conversation})
def clear_session(self, session_id: str):
"""清除会话"""
if session_id in self.sessions:
del self.sessions[session_id]
def get_stats(self) -> dict:
"""获取统计信息"""
return {
"total_sessions": len(self.sessions),
"active_sessions": sum(
1 for s in self.sessions.values()
if (datetime.now() - s["last_active"]).seconds < 3600
)
}
def main():
bot = CustomerServiceBot()
print("=" * 50)
print(" 智能客服系统")
print(" 输入 '退出' 结束对话")
print(" 输入 '摘要' 查看对话摘要")
print(" 输入 '清除' 清除对话历史")
print("=" * 50)
session_id = "test_user"
while True:
user_input = input("\n客户:").strip()
if not user_input:
continue
if user_input == "退出":
print("\n感谢您的咨询,再见!")
break
if user_input == "摘要":
print("\n【对话摘要】")
print(bot.get_summary(session_id))
continue
if user_input == "清除":
bot.clear_session(session_id)
print("\n对话历史已清除")
continue
response = bot.chat(session_id, user_input)
print(f"\n客服小智:{response}")
if __name__ == "__main__":
main()
小结
本章介绍了:
✅ 记忆功能的实现原理
✅ 各种记忆类型及其适用场景
✅ 使用 LCEL 实现记忆
✅ 持久化存储(文件、Redis、SQLite)
✅ 多用户会话管理
✅ 实体记忆
✅ 完整的智能客服示例
下一步
掌握记忆功能后,让我们学习工具使用,让 AI 能够执行实际操作。
练习
- 实现一个带有记忆限制的对话系统
- 使用 SQLite 实现持久化记忆
- 创建一个多用户聊天室应用
- 实现对话历史的导出和导入功能