你是否遇到过这样的情况?和 AI 聊完天,关闭窗口后再打开,AI 就完全不认识你了,问什么都得从头解释。这就像鱼的记忆一样——只有 7 秒。
但如果你有一个”私人助理”,即使过了一个月,它还记得你”喜欢吃披萨”、”住在上海”、”喜欢蓝色”——那该有多好!
这就是记忆机制要解决的问题。在 LangChain(特别是 LangGraph)中,我们可以轻松实现这两种记忆:短期记忆和长期记忆。
项目地址:langchain_memory_demo —— 一个演示 LangGraph 记忆机制的入门项目,建议边读文章边对照代码!
1. 什么是记忆机制?
想象一下你在和 AI 聊天,有两种不同的记忆方式:
短期记忆 📝
就像人的”短期记忆”,只记得当前对话的内容:
- 关闭对话框再打开,AI 就忘了之前聊过什么
- 需要通过”会话ID”(thread_id)来恢复之前的对话
- 适合:当前会话的多轮对话
长期记忆 🧠
就像人的”长期记忆”,AI 会记住你的偏好:
- 即使关闭程序再打开,AI 仍然记得你”喜欢吃披萨”
- 就像一个私人助理,了解你的习惯和偏好
- 适合:记住用户偏好、历史记录
两者对比
| 特性 |
短期记忆 |
长期记忆 |
| 存储方式 |
内存 |
ChromaDB 向量数据库 |
| 持久化 |
❌ 进程结束丢失 |
✅ 进程重启后保留 |
| 用途 |
多轮对话 |
个性化推荐、用户画像 |
| 实现 |
InMemorySaver |
ChromaDB |
2. 核心概念解析
2.1 LLM vs Embedding
在学习记忆机制之前,我们需要理解两个核心概念:
- LLM(推理模型):像大脑,负责”思考”和”回答问题”
- Embedding(向量化):像眼睛,负责”理解”文字的”含义”
1 2 3 4 5
| "我喜欢吃披萨" → Embedding → [0.12, -0.34, 0.56, ...] ↓ "我想吃东西" → Embedding → [0.11, -0.35, 0.55, ...] ↓ 相似度高!→ 检索到记忆
|
2.2 thread_id
就像每个微信会话有一个独立的聊天记录,thread_id 用来区分不同的会话:
1 2 3 4
| config = {"configurable": {"thread_id": "session_1"}}
result = agent.invoke({"messages": [HumanMessage("你好")]}, config)
|
3. 短期记忆实现
短期记忆使用 LangGraph 的 InMemorySaver(内存检查点)来实现。
3.1 核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| from langgraph.checkpoint.memory import InMemorySaver from langgraph.graph import StateGraph, START from langchain_core.messages import HumanMessage
short_term_checkpointer = InMemorySaver()
class ShortMemoryState(TypedDict): messages: Annotated[list[AnyMessage], operator.add]
def call_model(state: ShortMemoryState): response = model.invoke(state["messages"]) return {"messages": [response]}
short_memory_builder = StateGraph(ShortMemoryState) short_memory_builder.add_node(call_model) short_memory_builder.add_edge(START, "call_model")
short_memory_agent = short_memory_builder.compile(checkpointer=short_term_checkpointer)
|
3.2 如何使用
1 2 3 4 5 6 7 8 9 10 11 12
| config = {"configurable": {"thread_id": "session_1"}} result = short_memory_agent.invoke( {"messages": [HumanMessage(content="你好,我叫 Bob")]}, config )
result = short_memory_agent.invoke( {"messages": [HumanMessage(content="我叫什么名字?")]}, config )
|
3.3 工作原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| ┌─────────────────────────────────────────────────────────┐ │ 短期记忆工作流程 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 用户: "你好,我叫 Bob" │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ call_model │ → 调用 LLM 生成回复 │ │ └────────┬────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ InMemorySaver │ → 自动保存对话状态到内存 │ │ │ thread_id=xxx │ │ │ └────────┬────────┘ │ │ │ │ │ ▼ │ │ 用户: "我叫什么?" │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ 从内存恢复历史 │ → 读取 thread_id 对应的对话历史 │ │ └────────┬────────┘ │ │ │ │ │ ▼ │ │ LLM: "你叫 Bob" │ │ │ └─────────────────────────────────────────────────────────┘
|
3.4 特点总结
| 特点 |
说明 |
| ✅ 优点 |
速度快,零配置 |
| ❌ 缺点 |
进程结束数据丢失 |
| 适用场景 |
当前会话的多轮对话 |
4. 长期记忆实现
长期记忆使用 ChromaDB(向量数据库)来实现,支持语义搜索和持久化存储。
4.1 核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| from langchain_chroma import Chroma from langchain_huggingface import HuggingFaceEmbeddings from pathlib import Path
embedding_model = HuggingFaceEmbeddings( model_name="sentence-transformers/all-MiniLM-L6-v2" )
chroma_path = Path(__file__).parent / "chroma_db" vectorstore = Chroma( persist_directory=str(chroma_path), embedding_function=embedding_model, )
def save_memory(user_id: str, memory_key: str, text: str): vectorstore.add_texts(texts=[text], ids=[memory_key])
def retrieve_memories(user_id: str, query: str, limit: int = 2) -> str: docs = vectorstore.similarity_search(query, k=limit) memories = "\n".join(doc.page_content for doc in docs) return f"## 用户记忆\n{memories}" if memories else ""
|
4.2 如何使用
1 2 3 4 5 6 7 8 9 10 11
| save_memory("user_123", "memory_1", "我喜欢吃披萨") save_memory("user_123", "memory_2", "我住在上海")
result = long_memory_agent.invoke( {"messages": [HumanMessage(content="我饿了想吃东西")]}, )
|
4.3 工作原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| ┌─────────────────────────────────────────────────────────┐ │ 长期记忆工作流程 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 步骤1: 保存记忆 │ │ ┌─────────────────┐ │ │ │ "我喜欢吃披萨" │ → Embedding → [0.12, -0.34, ...] │ │ └────────┬────────┘ ↓ │ │ │ ChromaDB 存储 │ │ ▼ │ │ ┌─────────────────┐ │ │ │ ID: memory_1 │ │ │ │ 向量: [0.12...]│ │ │ │ 原文: 我喜欢吃披萨 │ │ └─────────────────┘ │ │ │ │ 步骤2: 检索记忆 │ │ 用户: "我饿了" │ │ │ │ │ ▼ │ │ "我饿了" → Embedding → [0.11, -0.33, ...] │ │ │ │ │ ▼ │ │ ChromaDB 语义搜索 → 找到最相似的记忆 │ │ │ │ │ ▼ │ │ 找到: "我喜欢吃披萨" (相似度: 0.92) │ │ │ │ 步骤3: 生成回复 │ │ System: "## 用户记忆\n我喜欢吃披萨" │ │ LLM: "要不要点个披萨?" │ │ │ └─────────────────────────────────────────────────────────┘
|
4.4 特点总结
| 特点 |
说明 |
| ✅ 优点 |
持久化存储,支持语义搜索 |
| ❌ 缺点 |
首次加载较慢(需要初始化 Embedding 模型) |
| 适用场景 |
个性化推荐、用户画像、跨会话记忆 |
5. 实战演示
5.1 项目结构
1 2 3 4 5 6 7 8
| langchain_memory_demo/ ├── main.py # 主入口,交互式演示 ├── src/agent/ │ ├── model.py # 模型配置(LLM + Embedding) │ ├── state.py # Agent 状态定义 │ └── memory/ │ ├── short_memory.py # 短期记忆实现 │ └── long_memory.py # 长期记忆实现
|
5.2 运行演示
1 2 3 4 5 6 7 8 9
| git clone https://github.com/liupx/langchain_memory_demo cd langchain_memory_demo
uv sync
uv run python main.py
|
运行后会看到交互式菜单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ╔══════════════════════════════════════════════════════════════╗ ║ 🎯 LangGraph 记忆机制演示 🎯 ║ ║ 短期记忆 vs 长期记忆 ║ ╚══════════════════════════════════════════════════════════════╝
📋 请选择功能: 1. 🎯 短期记忆 - 多轮对话演示 2. 🧠 长期记忆 - 语义搜索演示 3. ⚙️ 自定义记忆 - 添加自己的记忆 4. 🔍 查看短期记忆会话列表 5. 🔍 查看长期记忆内容 6. 🗑️ 清空短期记忆 7. 🧹 清空长期记忆 0. 🚪 退出程序
|
5.3 短期记忆演示
1 2 3 4 5 6 7 8 9 10 11 12 13
| 🎯 短期记忆模式 请告诉我你的名字:小明
🤖: 你好小明!很高兴认识你。
👤 你:我喜欢什么? 🤖: 你还没有告诉我你喜欢什么哦。
👤 你:我喜欢打篮球 🤖: 好的,我记住你喜欢打篮球了!
👤 你:我刚才说什么? 🤖: 你刚才说你喜欢打篮球。
|
5.4 长期记忆演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 🧠 长期记忆模式 请添加你的记忆(输入格式:记忆 你的内容) 添加记忆:我喜欢吃火锅 ✅ 已保存:我喜欢吃火锅 添加记忆:我喜欢打篮球 ✅ 已保存:我喜欢打篮球 添加记忆:完成
🎤 开始对话(AI 会根据记忆回复): 👤 你:我饿了
📚 检索到的记忆: ## 用户记忆 我喜欢吃火锅
🤖: 想必你饿了吧?要不要吃火锅?
|
6. 技术栈总结
| 技术 |
用途 |
| LangGraph |
Agent 工作流框架 |
| DeepSeek API |
LLM 推理模型(对话) |
| langchain-huggingface + sentence-transformers |
本地 Embedding 模型(向量化) |
| ChromaDB |
向量数据库(长期记忆持久化) |
7. 常见问题
Q: 为什么用本地 Embedding 而不是 API?
A: 本地模型免费、离线可用,适合学习和小项目。生产环境可以用 OpenAI/DeepSeek 的 Embedding API。
Q: 长期记忆数据保存在哪里?
A: 保存在 src/agent/memory/chroma_db/ 目录,进程重启后不会丢失。
Q: 如何选择短期记忆还是长期记忆?
A:
- 需要多轮对话、会话续接 → 短期记忆
- 需要记住用户偏好、跨会话记忆 → 长期记忆
- 两者可以同时使用!
Q: 如何扩展更多功能?
A: 可以添加:
- 工具调用(Tools)
- 多模态支持
- 更复杂的记忆策略(如记忆分级、遗忘机制)
8. 总结
通过本文,我们学习了 LangChain/LangGraph 中的两种记忆机制:
| 记忆类型 |
实现方式 |
特点 |
适用场景 |
| 短期记忆 |
InMemorySaver |
速度快,进程结束丢失 |
多轮对话 |
| 长期记忆 |
ChromaDB |
持久化,语义搜索 |
用户画像、个性化推荐 |
核心要点:
- 短期记忆通过
thread_id 区分不同会话
- 长期记忆通过 Embedding 实现语义搜索
- 两者可以结合使用,提供更好的用户体验
参考资源
关于作者:本文基于 langchain_memory_demo 项目编写,这是一个适合理解 LangGraph 记忆机制的实战入门项目。欢迎 Star 和 Fork!