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 复制代码
=== 多轮对话 ===
丘吉尔是英国政治家、演说家...
他是英国人。
我们刚才聊的是丘吉尔。
相关推荐
用户81818706274630 分钟前
第25章 Redis集群脑裂实录:一次真实故障复盘
java·后端
呃呃呃呃ex36 分钟前
2026年古法编程的末法时代,如何评估自己完成迅速转行
前端·后端
EatFan37 分钟前
从单体到模块化:我的 Spring Boot 项目为什么拆成 framework、module、server?
java·spring boot·后端
youcans_43 分钟前
【嵌入式软件AI编程】08. 第一个STM32工程
stm32·单片机·ai编程·嵌入式软件·claude code
sarasuki43 分钟前
上下文快爆炸了?Agent 的两种压缩手段:微压缩 vs LLM 摘要
人工智能·ai编程
学者猫头鹰44 分钟前
RAG检索增强生成:文本清洗
ai编程
回家路上绕了弯44 分钟前
Codex 与 ZCode 有什么区别?从开发工作流看 AI 编程工具怎么选
后端
Java内核笔记1 小时前
Spring Boot 4 可观测性源码剖析:OpenTelemetry 全链路打通日志、指标、追踪
java·后端
学渣超1 小时前
从一次早高峰数据库告警说起:你真的理解缓存该如何落地应用吗?
redis·后端·架构