LangChain 中文教程LangChain 中文教程
首页
  • 什么是 LangChain
  • 环境搭建
  • 第一个应用
  • 模型调用
  • 提示词模板
  • 链式调用
  • 记忆功能
  • 工具使用
  • 检索增强生成(RAG)
  • Agent 智能体
  • LangGraph 入门
  • LangSmith 监控
  • 部署与优化
LangChain 官网
首页
  • 什么是 LangChain
  • 环境搭建
  • 第一个应用
  • 模型调用
  • 提示词模板
  • 链式调用
  • 记忆功能
  • 工具使用
  • 检索增强生成(RAG)
  • Agent 智能体
  • LangGraph 入门
  • LangSmith 监控
  • 部署与优化
LangChain 官网
  • 进阶篇

    • 链式调用
    • 记忆功能
    • 工具使用
    • 检索增强生成(RAG)

记忆功能

大语言模型本身是无状态的,每次调用都是独立的。记忆(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 能够执行实际操作。

练习

  1. 实现一个带有记忆限制的对话系统
  2. 使用 SQLite 实现持久化记忆
  3. 创建一个多用户聊天室应用
  4. 实现对话历史的导出和导入功能
Prev
链式调用
Next
工具使用