前言
上一篇我们理论讲完了,现在动手实践实践。毕竟"纸上得来终觉浅,绝知此事要躬行。"
本文聚焦工程落地:从最简单的 Buffer Memory 到生产级的向量记忆、图记忆,一步步带你把 AI 记忆真正跑起来。所有代码均可直接运行。
一、最简单的起点:ConversationBufferMemory
1.1 原理
把完整的对话历史直接塞进 Prompt 的 {history} 占位符。
python
from langchain_openai import OpenAI
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
llm = OpenAI(temperature=0, openai_api_key="YOUR_KEY")
conversation = ConversationChain(
llm=llm,
memory=ConversationBufferMemory()
)
# 第一轮
conversation.predict(input="我叫张三,我是一名 Python 工程师。")
# 第二轮
conversation.predict(input="我叫什么名字?")
# 输出:你叫张三。✅
1.2 问题:Token 爆炸
随着对话增长,历史记录越来越长,Token 消耗线性增长:
第1轮:~50 tokens
第10轮:~500 tokens
第100轮:~5000 tokens ← 开始超出 Context Window
解决方案:引入记忆压缩策略。
二、记忆压缩策略
2.1 ConversationBufferWindowMemory(滑动窗口)
只保留最近 K 轮对话:
python
from langchain.memory import ConversationBufferWindowMemory
memory = ConversationBufferWindowMemory(k=5) # 只保留最近5轮
conversation = ConversationChain(llm=llm, memory=memory)
优点 :Token 消耗可控
缺点:早期重要信息会丢失
2.2 ConversationSummaryMemory(摘要压缩)
用 LLM 对历史对话进行摘要,用摘要替代原始历史:
python
from langchain.memory import ConversationSummaryMemory
memory = ConversationSummaryMemory(llm=llm)
conversation = ConversationChain(llm=llm, memory=memory)
# 内部会自动调用 LLM 生成摘要:
# "用户张三是 Python 工程师,对 LLM 集成感兴趣..."
优点 :长对话也能保持低 Token 消耗
缺点:摘要过程有额外 LLM 调用成本,细节可能丢失
2.3 ConversationSummaryBufferMemory(混合策略)
结合滑动窗口和摘要:近期对话保留原文,远期对话压缩为摘要。
python
from langchain.memory import ConversationSummaryBufferMemory
memory = ConversationSummaryBufferMemory(
llm=llm,
max_token_limit=2000 # 超过2000 token 时触发摘要
)
三、向量记忆:语义检索长期记忆
3.1 架构设计
用户输入
↓
[向量化] → 查询向量数据库 → 检索相关记忆
↓
注入 Prompt → LLM 生成回复
↓
[异步] 提取新记忆 → 向量化 → 存入向量数据库
3.2 使用 Chroma 实现本地向量记忆
python
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_chroma import Chroma
from langchain.memory import VectorStoreRetrieverMemory
from langchain.chains import ConversationChain
from langchain.prompts import PromptTemplate
# 初始化向量数据库
embeddings = OpenAIEmbeddings()
vectorstore = Chroma(
collection_name="agent_memory",
embedding_function=embeddings,
persist_directory="./chroma_db"
)
# 创建记忆检索器
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
memory = VectorStoreRetrieverMemory(retriever=retriever)
# 预存一些记忆
memory.save_context(
{"input": "我最喜欢的编程语言是 Python"},
{"output": "好的,我记住了"}
)
memory.save_context(
{"input": "我在做一个 RAG 项目"},
{"output": "了解,RAG 是检索增强生成"}
)
# 使用记忆
prompt = PromptTemplate(
input_variables=["history", "input"],
template="""
以下是与用户的相关历史记忆:
{history}
当前对话:
用户:{input}
AI:"""
)
chain = ConversationChain(llm=ChatOpenAI(), memory=memory, prompt=prompt)
# 测试语义检索
result = chain.predict(input="推荐一些适合我项目的工具")
# AI 会检索到"RAG 项目"相关记忆,给出针对性建议
3.3 使用 Pinecone 实现云端向量记忆
python
from pinecone import Pinecone
from langchain_pinecone import PineconeVectorStore
pc = Pinecone(api_key="YOUR_PINECONE_KEY")
index = pc.Index("agent-memory")
vectorstore = PineconeVectorStore(
index=index,
embedding=OpenAIEmbeddings(),
namespace="user_123" # 按用户隔离
)
# 存储记忆
vectorstore.add_texts(
texts=["用户偏好 Python,正在做 RAG 项目"],
metadatas=[{"user_id": "123", "timestamp": "2026-03-16", "type": "preference"}]
)
# 检索记忆
results = vectorstore.similarity_search(
"用户的技术栈是什么?",
k=3,
filter={"user_id": "123"}
)
四、LangGraph 长期记忆:生产级方案
4.1 LangGraph Memory Store
LangGraph 提供了内置的 Memory Store,支持跨会话持久化:
python
from langgraph.store.memory import InMemoryStore
from langgraph.graph import StateGraph, MessagesState
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage
import uuid
# 初始化存储(生产环境用 PostgresStore 或 RedisStore)
store = InMemoryStore()
model = ChatOpenAI(model="gpt-4o")
def call_model(state: MessagesState, config, *, store):
user_id = config["configurable"]["user_id"]
namespace = ("memories", user_id)
# 检索用户记忆
memories = store.search(namespace)
info = "\n".join([m.value["data"] for m in memories])
system_msg = f"""你是一个有记忆的 AI 助手。
关于用户的已知信息:
{info}
根据以上信息个性化你的回复。"""
response = model.invoke(
[SystemMessage(content=system_msg)] + state["messages"]
)
# 提取并保存新记忆
new_memory = extract_memory(state["messages"][-1].content)
if new_memory:
store.put(namespace, str(uuid.uuid4()), {"data": new_memory})
return {"messages": response}
def extract_memory(text: str) -> str:
"""用 LLM 提取值得记忆的信息"""
extraction_prompt = f"""
从以下用户消息中提取值得长期记忆的关键信息(偏好、事实、背景)。
如果没有值得记忆的信息,返回空字符串。
用户消息:{text}
提取的记忆(简洁格式):"""
result = model.invoke(extraction_prompt)
return result.content.strip()
# 构建 Graph
builder = StateGraph(MessagesState)
builder.add_node("model", call_model)
builder.set_entry_point("model")
builder.set_finish_point("model")
graph = builder.compile(store=store)
# 使用
config = {"configurable": {"user_id": "user_123", "thread_id": "thread_1"}}
# 第一次对话
graph.invoke(
{"messages": [{"role": "user", "content": "我叫李四,我是一名架构师"}]},
config=config
)
# 新会话,记忆依然存在
config2 = {"configurable": {"user_id": "user_123", "thread_id": "thread_2"}}
result = graph.invoke(
{"messages": [{"role": "user", "content": "你还记得我是做什么的吗?"}]},
config=config2
)
# 输出:你是一名架构师,叫李四。✅
五、Mem0:专业记忆引擎
5.1 快速上手
bash
pip install mem0ai
python
from mem0 import Memory
import os
os.environ["OPENAI_API_KEY"] = "YOUR_KEY"
os.environ["MEM0_API_KEY"] = "YOUR_MEM0_KEY" # 使用托管版
memory = Memory()
# 添加记忆
memory.add(
messages=[
{"role": "user", "content": "我是一名后端工程师,专注于 Java 和 Spring Boot"},
{"role": "assistant", "content": "了解,我会记住你的技术背景"}
],
user_id="user_001"
)
# 搜索记忆
results = memory.search(
query="用户的技术栈",
user_id="user_001"
)
for r in results:
print(r["memory"])
# 输出:用户是后端工程师,专注于 Java 和 Spring Boot
5.2 多层记忆管理
python
# 会话级记忆(短期)
memory.add(
messages=[{"role": "user", "content": "今天我在调试一个 OOM 问题"}],
user_id="user_001",
session_id="session_20260316" # 会话结束后可清除
)
# 用户级记忆(长期)
memory.add(
messages=[{"role": "user", "content": "我最近在学习 Rust"}],
user_id="user_001"
# 无 session_id = 长期保存
)
# 获取所有记忆
all_memories = memory.get_all(user_id="user_001")
for m in all_memories:
print(f"[{m['created_at']}] {m['memory']}")
5.3 与 LangChain 集成
python
from mem0 import MemoryClient
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage
client = MemoryClient(api_key="YOUR_MEM0_KEY")
llm = ChatOpenAI(model="gpt-4o")
def chat_with_memory(user_id: str, user_message: str) -> str:
# 1. 检索相关记忆
memories = client.search(user_message, user_id=user_id)
memory_context = "\n".join([m["memory"] for m in memories])
# 2. 构建带记忆的 Prompt
system_prompt = f"""你是一个有记忆的 AI 助手。
用户相关记忆:
{memory_context if memory_context else "暂无历史记忆"}
请根据以上记忆个性化回复。"""
# 3. 调用 LLM
response = llm.invoke([
SystemMessage(content=system_prompt),
HumanMessage(content=user_message)
])
# 4. 异步保存新记忆
client.add(
messages=[
{"role": "user", "content": user_message},
{"role": "assistant", "content": response.content}
],
user_id=user_id
)
return response.content
# 测试
print(chat_with_memory("user_001", "我叫王五,我在做微服务架构设计"))
print(chat_with_memory("user_001", "给我推荐一些适合我工作的工具"))
六、Zep:图记忆与上下文工程
6.1 Zep 的核心优势
Zep 不只是存储记忆,而是构建时序上下文图(Temporal Context Graph):
- 自动提取实体和关系
- 当事实变化时自动失效旧记忆
- 支持 Graph RAG 多跳推理
- 200ms 检索延迟
6.2 快速集成
bash
pip install zep-cloud
python
from zep_cloud.client import AsyncZep
from zep_cloud.types import Message
import asyncio
client = AsyncZep(api_key="YOUR_ZEP_KEY")
async def main():
# 创建用户
await client.user.add(user_id="user_001")
# 创建会话
await client.memory.add_session(
session_id="session_001",
user_id="user_001"
)
# 添加对话记忆
await client.memory.add(
session_id="session_001",
messages=[
Message(role="user", role_type="user",
content="我是一名 DevOps 工程师,负责公司的 K8s 集群"),
Message(role="assistant", role_type="assistant",
content="了解,你负责 Kubernetes 集群运维")
]
)
# 检索上下文(Zep 自动组装最相关的上下文)
memory = await client.memory.get(session_id="session_001")
print(memory.context)
# 输出:用户是 DevOps 工程师,管理 K8s 集群...
# 图查询:查找与用户相关的所有实体
facts = await client.graph.search(
user_id="user_001",
query="用户的技术职责"
)
for fact in facts.edges:
print(f"{fact.source} → {fact.relation} → {fact.target}")
asyncio.run(main())
七、生产环境最佳实践
7.1 记忆分层架构
┌─────────────────────────────────────────────────────┐
│ 生产级记忆架构 │
├─────────────────────────────────────────────────────┤
│ L1: 会话缓存(Redis) │
│ - 当前对话历史 │
│ - TTL: 24小时 │
├─────────────────────────────────────────────────────┤
│ L2: 向量记忆(Pinecone/Weaviate) │
│ - 语义化长期记忆 │
│ - 按用户 namespace 隔离 │
├─────────────────────────────────────────────────────┤
│ L3: 图记忆(Zep/Neo4j) │
│ - 实体关系网络 │
│ - 支持复杂推理查询 │
├─────────────────────────────────────────────────────┤
│ L4: 结构化存储(PostgreSQL) │
│ - 用户档案、偏好设置 │
│ - 精确查询场景 │
└─────────────────────────────────────────────────────┘
7.2 记忆写入流水线
python
import asyncio
from datetime import datetime
class MemoryPipeline:
def __init__(self, vector_store, graph_store, kv_store):
self.vector_store = vector_store
self.graph_store = graph_store
self.kv_store = kv_store
async def process_conversation(self, user_id: str, messages: list):
"""异步处理对话,提取并存储记忆"""
# 并行执行多个记忆提取任务
await asyncio.gather(
self._extract_and_store_facts(user_id, messages),
self._update_session_cache(user_id, messages),
self._update_graph(user_id, messages)
)
async def _extract_and_store_facts(self, user_id, messages):
"""提取事实性记忆存入向量库"""
facts = await self._llm_extract_facts(messages)
if facts:
await self.vector_store.add_texts(
texts=facts,
metadatas=[{
"user_id": user_id,
"timestamp": datetime.now().isoformat(),
"type": "fact"
}] * len(facts)
)
async def _update_session_cache(self, user_id, messages):
"""更新 Redis 会话缓存"""
key = f"session:{user_id}:history"
await self.kv_store.lpush(key, *[str(m) for m in messages[-5:]])
await self.kv_store.expire(key, 86400) # 24小时过期
async def _update_graph(self, user_id, messages):
"""更新知识图谱"""
entities = await self._extract_entities(messages)
await self.graph_store.upsert_entities(user_id, entities)
7.3 隐私保护
python
import hashlib
import re
def sanitize_memory(text: str) -> str:
"""脱敏处理:移除手机号、邮箱、身份证等敏感信息"""
# 手机号脱敏
text = re.sub(r'1[3-9]\d{9}', '[手机号已脱敏]', text)
# 邮箱脱敏
text = re.sub(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
'[邮箱已脱敏]', text)
# 身份证脱敏
text = re.sub(r'\d{17}[\dXx]', '[身份证已脱敏]', text)
return text
def hash_user_id(user_id: str) -> str:
"""对用户 ID 进行哈希,避免直接存储明文 ID"""
return hashlib.sha256(user_id.encode()).hexdigest()[:16]
八、常见踩坑与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 记忆检索不准确 | 向量化质量差 | 使用更好的 Embedding 模型(text-embedding-3-large) |
| Token 超限 | 注入记忆过多 | 限制检索数量(top_k=3),使用 Reranker 过滤 |
| 记忆冲突 | 用户信息更新 | 添加时间戳,优先使用最新记忆 |
| 跨用户记忆泄露 | namespace 未隔离 | 严格按 user_id 隔离存储和检索 |
| 记忆写入延迟 | 同步写入阻塞 | 改为异步后台写入 |
| 冷启动无记忆 | 新用户首次使用 | 设计引导流程主动收集用户信息 |
九、总结
记忆实现路径选择:
简单场景 → ConversationBufferMemory / SummaryMemory
中等场景 → VectorStoreRetrieverMemory + Chroma/Pinecone
复杂场景 → LangGraph Memory Store + Mem0
企业级 → Zep(图记忆 + 上下文工程)
从 Buffer Memory 到图记忆,每一层都有其适用场景。不要过度设计------从最简单的方案开始,随着业务复杂度增长逐步升级。