老周虾扯:AI 记忆机制工程实践

前言

上一篇我们理论讲完了,现在动手实践实践。毕竟"纸上得来终觉浅,绝知此事要躬行。"

本文聚焦工程落地:从最简单的 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 到图记忆,每一层都有其适用场景。不要过度设计------从最简单的方案开始,随着业务复杂度增长逐步升级。

相关推荐
老周聊架构2 天前
老周虾扯:解构 AI 记忆构建长效 Agent 的底层逻辑与认知体系
ai记忆
wxl7812273 个月前
开源AI记忆工具Cognee深度解析:技术优势、部署实践与实测验证
人工智能·congee 0.5版本·ai记忆·替代rag