009.LangChain 手动记忆全流程

该教程旨在带大家从 0 起步,掌握用 Python 开发大模型应用的技能。若当前内容让你感到晦涩,可回溯本合集的前期文章,降低学习难度。


1. 为什么需要记忆?

1.1. 大模型无状态

每次请求独立,不会主动记住上一轮内容。

典型翻车场景:

复制代码
用户:丘吉尔是谁?
用户:他哪国人?   ← 模型不知"他"指谁

1.2. 解决思路

把历史对话当成消息列表的一部分塞给模型。

与小样本提示原理相同:

系统消息 → 历史消息 → 当前用户问题


2. 手动记忆 5 步流程

2.1. 环境

shell 复制代码
pip install langchain langchain-deepseek
export DEEPSEEK_API_KEY=sk-xxx

2.2. 初始化记忆容器

python 复制代码
from langchain.memory import ConversationBufferMemory

memory = ConversationBufferMemory(return_messages=True)   # 必须True

2.3. 查看当前记忆(空)

python 复制代码
print(memory.load_memory_variables({}))
# → {'history': []}

2.4. 把一轮对话写进记忆

python 复制代码
memory.save_context(
    {"input": "丘吉尔是谁?"},
    {"output": "英国政治家、演说家"}
)

写后再 load_memory_variables 可见两条消息对象。

2.5. 提示模板占位历史消息

python 复制代码
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是历史问答助手,回答简洁。"),
    MessagesPlaceholder(variable_name="history"),  # 占位符
    ("human", "{input}")
])

2.6. 取历史 → 拼消息 → 调模型 → 写回新对话

python 复制代码
from langchain_deepseek import ChatDeepSeek

llm = ChatDeepSeek(model="deepseek-chat", temperature=0)

def chat_with_memory(user_question: str) -> str:
    history = memory.load_memory_variables({})["history"]   # ① 取历史
    messages = prompt.format_messages(history=history, input=user_question)  # ② 拼消息
    response = llm.invoke(messages)                          # ③ 调模型
    memory.save_context({"input": user_question}, {"output": response.content})  # ④ 写回
    return response.content

3. 多轮体验

python 复制代码
print("=== 多轮对话 ===")
print(chat_with_memory("丘吉尔是谁?"))
print(chat_with_memory("他哪国人?"))         # 利用上下文答"英国人"
print(chat_with_memory("我们刚才聊的是谁?"))  # 仍能答"丘吉尔"

4. 完整可运行代码

python 复制代码
from langchain.memory import ConversationBufferMemory
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_deepseek import ChatDeepSeek

# ① 初始化记忆
memory = ConversationBufferMemory(return_messages=True)

# ② 提示模板占位
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是历史问答助手,回答简洁。"),
    MessagesPlaceholder(variable_name="history"),
    ("human", "{input}")
])

llm = ChatDeepSeek(model="deepseek-chat", temperature=0)

# ③ 记忆对话函数
def chat_with_memory(user_question: str) -> str:
    history = memory.load_memory_variables({})["history"]   # 取历史
    messages = prompt.format_messages(history=history, input=user_question)
    response = llm.invoke(messages)
    # 写回记忆
    memory.save_context({"input": user_question}, {"output": response.content})
    return response.content

# ④ 多轮测试
if __name__ == "__main__":
    print("=== 多轮对话 ===")
    print(chat_with_memory("丘吉尔是谁?"))
    print(chat_with_memory("他哪国人?"))
    print(chat_with_memory("我们刚才聊的是谁?"))

运行结果示例:

diff 复制代码
=== 多轮对话 ===
丘吉尔是英国政治家、演说家...
他是英国人。
我们刚才聊的是丘吉尔。
相关推荐
短剑重铸之日3 小时前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
JMchen1233 小时前
AI编程与软件工程的学科融合:构建新一代智能驱动开发方法学
驱动开发·python·软件工程·ai编程
Dragon Wu4 小时前
Spring Security Oauth2.1 授权码模式实现前后端分离的方案
java·spring boot·后端·spring cloud·springboot·springcloud
一个有梦有戏的人4 小时前
Python3基础:进阶基础,筑牢编程底层能力
后端·python
爬山算法4 小时前
Hibernate(88)如何在负载测试中使用Hibernate?
java·后端·hibernate
独断万古他化5 小时前
【Spring 原理】Bean 的作用域与生命周期
java·后端·spring
我爱加班、、5 小时前
Websocket能携带token过去后端吗
前端·后端·websocket
一 乐5 小时前
校园二手交易|基于springboot + vue校园二手交易系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端
80530单词突击赢5 小时前
SpringBoot整合SpringMVC全解析
java·spring boot·后端
hdsoft_huge6 小时前
1panel面板中部署SpringBoot和Vue前后端分离系统 【图文教程】
vue.js·spring boot·后端