乐于分享
好东西不私藏

AI Agent 记忆系统设计:面试必考!三层记忆架构从原理到 LangGraph 实战

AI Agent 记忆系统设计:面试必考!三层记忆架构从原理到 LangGraph 实战

🧠 AI Agent · 面试必考 · 2026 最新

AI Agent 记忆系统设计
面试必考!三层记忆架构
从原理到 LangGraph 实战

Buffer Memory · Entity Memory · 向量长期记忆 · LangGraph 状态图 · 生产级接入方案全解析

🎯 高频面试题精选(答案在后文)

Q1. AI Agent 的记忆类型有哪些?它们分别解决什么问题?
Agent 记忆通常分为三层:① 短期/会话记忆(Buffer Memory)——维护当前对话上下文,解决多轮对话遗忘问题;② 实体/工作记忆(Entity Memory)——抽取并结构化关键信息(人物、偏好、状态),解决跨会话信息碎片化问题;③ 长期语义记忆(Vector Store Memory)——将历史经验向量化存储,通过相似度检索召回,解决大规模跨时间知识积累问题。三层配合使用,才能构建真正”记得住、想得起、用得上”的 Agent。
Q2. ConversationBufferMemory 和 ConversationSummaryMemory 的核心区别是什么?何时选用?
BufferMemory 完整保留对话历史,精度最高但 Token 消耗随轮次线性增长,适合短会话(≤20轮)。SummaryMemory 每隔 N 轮调用 LLM 对旧内容压缩摘要,Token 消耗稳定但有信息损失,适合长会话。实际生产常用混合策略:近 K 轮保留原文 + 更早内容压缩为摘要(ConversationSummaryBufferMemory),在精度与成本间取得最佳平衡。
Q3. 向量记忆(Vector Memory)与 RAG 的核心区别是什么?
RAG 是在推理时从外部知识库检索,知识库相对静态,更新需重新索引;向量记忆是 Agent 运行过程中动态写入/读取的个人化记忆,随交互持续积累,更新频繁。RAG 解决”模型不知道”的知识缺口问题,向量记忆解决”Agent 忘了你是谁”的个性化问题。实际系统中两者通常并存:RAG 提供领域知识,向量记忆提供用户上下文。
Q4. LangGraph 相比 LangChain 传统链(Chain)在记忆管理上有哪些优势?
LangChain 传统 Chain 记忆是线性附加的,状态传递不灵活,多 Agent 场景下共享记忆困难。LangGraph 将状态(State)建模为图节点间的共享 Schema,每个节点读写同一 State 对象,天然支持:① 多 Agent 共享记忆② 持久化 Checkpointing(可恢复任意历史节点);③ 分支与回滚(Human-in-the-loop);④ 并行子图执行。对于复杂 Agentic 工作流,LangGraph 是目前最成熟的工程选择。

📌 为什么 Agent 记忆系统是核心基础设施

大语言模型本身是无状态的——每次调用都是全新的,它不知道你昨天告诉它什么,也不记得三轮前的决策。一个没有记忆系统的 Agent 就像每隔几分钟失忆一次的助手,无法完成任何复杂的长程任务。

LLM 原生记忆窗口
128K
GPT-4o 上下文限制
$$$
长上下文 Token 成本
3层
生产级记忆架构

即使是 128K 的超长上下文,在实际工程中也面临三大问题:① Token 成本爆炸(每轮传入全量历史);② 注意力漂移(模型在极长上下文中容易遗漏中间信息,”Lost in the Middle”问题);③ 跨会话无法延续(重启后历史消失)。因此,设计结构化的记忆系统是构建生产级 Agent 的必修课。

🏗️ 三层记忆架构全景图

Agent Memory Architecture
Layer 1 · 短期会话记忆(Working Memory)
Buffer / Summary / Window — 当前会话上下文,存于内存,会话结束即销毁
🧩
Layer 2 · 实体/工作记忆(Entity Memory)
Entity Extraction → Structured Store — 跨会话关键信息,存于 KV/Redis,持久化
🌊
Layer 3 · 长期语义记忆(Semantic Memory)
Embedding → Vector Store — 历史经验/知识,存于 Milvus/Qdrant,相似度检索
上层读写快但容量小 · 下层容量大但需检索召回

短期会话记忆

管理当前对话轮次,直接拼入 prompt。Buffer(原文)、Window(滑窗)、Summary(压缩)三种策略按需选择。

🧩

实体记忆

从对话中抽取结构化实体(人名、偏好、任务状态)并持久化。跨会话后仍能”记住你是谁”。

🌊

语义长期记忆

历史对话/经验向量化存入向量库,查询时语义检索最相关片段注入上下文,支持百万级记忆规模。

⚡ Layer 1:短期会话记忆深度解析

三种策略对比

策略 原理 Token消耗 信息完整性 适用场景
BufferMemory 完整保留全部历史 O(n)线性增长 100% 短会话(<20轮)
WindowMemory 只保留最近 K 轮 O(1)固定 近期信息完整 客服、实时问答
SummaryMemory LLM 压缩旧历史为摘要 O(log n) 摘要有损 长会话、调研助手
SummaryBufferMemory 近K轮原文 + 旧历史摘要 接近O(log n) 近期完整 生产推荐 ✓

SummaryBufferMemory 代码实战

Python · LangChain SummaryBufferMemory
from langchain.memory import ConversationSummaryBufferMemory
from langchain_openai import ChatOpenAI
from langchain.chains import ConversationChain

# 初始化 LLM
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# SummaryBufferMemory:近 2000 Token 保留原文,超出则压缩为摘要
memory = ConversationSummaryBufferMemory(
    llm=llm,
    max_token_limit=2000,        # 超过此阈值触发摘要压缩
    memory_key="chat_history",
    return_messages=True,
    human_prefix="User",
    ai_prefix="Assistant"
)

# 构建对话链
chain = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=True
)

# 模拟多轮对话
response1 = chain.predict(input="我是小明,我在开发一个电商平台")
response2 = chain.predict(input="我主要负责后端 Java Spring Boot 模块")
response3 = chain.predict(input="现在帮我设计用户订单状态机")

# 查看当前记忆内容
print("== 当前记忆摘要 ==")
print(memory.moving_summary_buffer)   # 已压缩的历史摘要
print("== 近期原文记忆 ==")
for msg in memory.chat_memory.messages:
    print(f"{msg.type}: {msg.content[:100]}")
💡 工程建议 max_token_limit 建议设置为模型上下文窗口的 20%~30%。例如 GPT-4o(128K)设置为 25600,既保留足够近期上下文,又给工具调用和输出留出充足空间。

🧩 Layer 2:实体记忆(Entity Memory)

实体记忆的核心思想是从对话中抽取结构化信息并持久化,而不是保留原始对话文本。它能跨会话记住”用户叫什么名字、有什么偏好、当前任务状态”等关键实体信息。

实体记忆工作原理

  1. 每轮对话后,调用 LLM 对当前轮内容进行实体抽取(人名、组织、偏好、状态等)
  2. 将抽取的实体以 KV 格式更新到实体存储(内存字典 / Redis / 数据库)
  3. 下轮对话时,将相关实体描述注入 System Prompt,让模型”知道”用户背景
  4. 随着对话积累,实体信息持续增量更新,无需传入全量历史

Entity Memory + Redis 持久化实战

Python · 自定义 Entity Memory with Redis
import json
import redis
from langchain_openai import ChatOpenAI
from langchain.memory import ConversationEntityMemory
from langchain.memory.entity import RedisEntityStore

# Redis 实体存储后端(生产推荐,支持 TTL 和持久化)
redis_client = redis.Redis(host="localhost", port=6379, db=0)
entity_store = RedisEntityStore(
    redis_client=redis_client,
    session_id="user_alice_session",  # 按用户隔离
    key_prefix="entity",
    ttl=86400 * 30            # 实体信息保留30天
)

llm = ChatOpenAI(model="gpt-4o-mini")

memory = ConversationEntityMemory(
    llm=llm,
    entity_store=entity_store,
    memory_key="chat_history",
    input_key="input",
    k=5,                        # 注入最近5条相关实体
    return_messages=True
)

# 第一次会话:建立用户画像
memory.save_context(
    {"input": "我叫 Alice,是字节跳动的 Java 工程师,负责推荐系统"},
    {"output": "好的 Alice,很高兴认识你!推荐系统有什么我可以帮你的?"}
)

# 查看抽取到的实体
entities = entity_store.mget(["Alice", "字节跳动"])
for k, v in zip(["Alice", "字节跳动"], entities):
    print(f"{k}: {v}")
# 输出示例:
# Alice: Java工程师,就职于字节跳动,负责推荐系统开发
# 字节跳动: Alice的雇主,互联网公司

# === 三天后,新会话 ===
# 重新加载同一 session_id 的 entity_store,实体信息仍然存在
new_memory = ConversationEntityMemory(
    llm=llm,
    entity_store=RedisEntityStore(
        redis_client=redis_client,
        session_id="user_alice_session"  # 相同 session_id
    )
)
# Agent 仍然"记得"Alice是Java工程师,负责推荐系统
result = new_memory.load_memory_variables({"input": "帮我优化一下推荐算法"})

🌊 Layer 3:长期语义记忆(Vector Memory)

语义记忆是 Agent 记忆系统的”硬盘”——它能存储大量历史经验,并在需要时通过语义相似度检索召回最相关的片段注入上下文。这让 Agent 能真正”积累经验”而非每次都从零开始。

语义记忆读写流程

🔄 写入流程(Memory Consolidation) 每轮对话结束后:① 对话文本 → Embedding 模型生成向量 → ② 附加元数据(时间戳、用户ID、重要性分数)→ ③ Upsert 到向量数据库(Milvus/Qdrant)
🔍 读取流程(Memory Retrieval) 新轮次开始时:① 当前用户输入 → Embedding → ② 向量相似度搜索(Top-K)→ ③ 过滤元数据(时间衰减、用户过滤)→ ④ 注入 System Prompt

基于 Qdrant 的向量记忆系统实战

Python · VectorMemory with Qdrant + 时间衰减检索
import time
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct, Filter, FieldCondition, Range
from openai import OpenAI
import uuid

openai_client = OpenAI()
qdrant = QdrantClient(url="http://localhost:6333")

# 创建记忆集合
COLLECTION = "agent_memory"
qdrant.recreate_collection(
    collection_name=COLLECTION,
    vectors_config=VectorParams(size=1536, distance=Distance.COSINE)
)

def embed(text: str) -> list[float]:
    """调用 OpenAI text-embedding-3-small"""
    resp = openai_client.embeddings.create(
        model="text-embedding-3-small",
        input=text
    )
    return resp.data[0].embedding

def save_memory(user_id: str, text: str, importance: float = 1.0):
    """将一条记忆写入向量库"""
    vector = embed(text)
    qdrant.upsert(
        collection_name=COLLECTION,
        points=[PointStruct(
            id=str(uuid.uuid4()),
            vector=vector,
            payload={
                "user_id": user_id,
                "text": text,
                "timestamp": time.time(),     # Unix 时间戳,用于时间衰减
                "importance": importance       # 0~1,重要性评分
            }
        )]
    )

def retrieve_memory(user_id: str, query: str, top_k: int = 5) -> list[dict]:
    """检索最相关记忆,结合语义相似度与时间衰减"""
    vector = embed(query)
    results = qdrant.search(
        collection_name=COLLECTION,
        query_vector=vector,
        query_filter=Filter(
            must=[FieldCondition(
                key="user_id",
                match={"value": user_id}   # 用户级隔离
            )]
        ),
        limit=top_k * 3,               # 多取一些,后续重排序
        with_payload=True
    )

    now = time.time()
    scored = []
    for r in results:
        age_days = (now - r.payload["timestamp"]) / 86400
        # 时间衰减:7天后相关性减半,利用指数衰减
        time_decay = 0.5 ** (age_days / 7)
        final_score = r.score * 0.7 + time_decay * 0.2 + r.payload["importance"] * 0.1
        scored.append({"text": r.payload["text"], "score": final_score})

    scored.sort(key=lambda x: x["score"], reverse=True)
    return scored[:top_k]

# 写入几条历史记忆
save_memory("alice", "Alice偏好使用 Java 开发后端,擅长 Spring Boot 和 Kafka", importance=0.9)
save_memory("alice", "Alice在2026年3月完成了推荐系统 A/B 测试,CTR 提升了12%", importance=0.8)
save_memory("alice", "Alice的团队正在迁移到 K8s,遇到了 Ingress 配置问题", importance=0.7)

# 检索相关记忆
memories = retrieve_memory("alice", "帮我设计一个高并发订单服务")
context = "\n".join([m["text"] for m in memories])
print("注入的记忆上下文:\n", context)

🕸️ LangGraph 三层记忆完整集成实战

LangGraph 通过共享 State Schema 天然支持记忆的读写分离和跨节点访问。以下是一个集成三层记忆的 Agent 完整代码骨架:

Python · LangGraph Agent with 三层记忆 State
from typing import Annotated, TypedDict, Optional
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.sqlite import SqliteSaver
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
import operator

# ── State Schema:三层记忆统一管理 ──
class AgentState(TypedDict):
    # Layer 1: 当前会话消息列表(LangGraph 自动追加)
    messages: Annotated[list[BaseMessage], operator.add]

    # Layer 2: 实体记忆(结构化 KV)
    entities: dict[str, str]           # {"Alice": "Java工程师...", "项目X": "..."}

    # Layer 3: 语义记忆检索结果(注入当前轮)
    retrieved_memories: list[str]

    # 用户标识(用于记忆隔离)
    user_id: str

# ── 节点1:从向量库检索相关记忆 ──
def retrieve_memories_node(state: AgentState) -> dict:
    latest_msg = state["messages"][-1].content
    memories = retrieve_memory(state["user_id"], latest_msg, top_k=3)
    return {"retrieved_memories": [m["text"] for m in memories]}

# ── 节点2:LLM 推理(注入三层记忆)──
def agent_node(state: AgentState) -> dict:
    # 构建 System Prompt(融合三层记忆)
    entity_ctx = "\n".join([f"{k}: {v}" for k, v in state["entities"].items()])
    semantic_ctx = "\n".join(state["retrieved_memories"])

    system_prompt = f"""你是一个专业的 AI 助手。

【实体记忆(用户背景)】
{entity_ctx}

【相关历史经验】
{semantic_ctx}

请结合以上背景信息回答用户问题。"""

    # 调用 LLM(此处省略具体实现)
    response = llm.invoke([{"role": "system", "content": system_prompt}] + state["messages"])
    return {"messages": [AIMessage(content=response.content)]}

# ── 节点3:更新记忆(对话后写入)──
def update_memory_node(state: AgentState) -> dict:
    # 异步写入语义记忆(最近一轮对话)
    last_human = next(m for m in reversed(state["messages"]) if isinstance(m, HumanMessage))
    last_ai = next(m for m in reversed(state["messages"]) if isinstance(m, AIMessage))
    memory_text = f"用户问:{last_human.content}\n助手答:{last_ai.content[:200]}"
    save_memory(state["user_id"], memory_text)
    return {}

# ── 构建图 ──
graph = StateGraph(AgentState)
graph.add_node("retrieve", retrieve_memories_node)
graph.add_node("agent", agent_node)
graph.add_node("update_memory", update_memory_node)

graph.set_entry_point("retrieve")
graph.add_edge("retrieve", "agent")
graph.add_edge("agent", "update_memory")
graph.add_edge("update_memory", END)

# 持久化 Checkpointing(支持会话恢复)
checkpointer = SqliteSaver.from_conn_string("agent_memory.db")
app = graph.compile(checkpointer=checkpointer)

# 调用 Agent(thread_id 用于识别会话)
result = app.invoke(
    {
        "messages": [HumanMessage(content="帮我设计一个高并发订单服务")],
        "entities": {"Alice": "Java工程师,字节跳动,推荐系统"},
        "retrieved_memories": [],
        "user_id": "alice"
    },
    config={"configurable": {"thread_id": "alice_thread_001"}}
)
✅ LangGraph Checkpointing 的核心价值 SqliteSaver / RedisSaver 会自动保存每次图执行的完整 State。即使进程重启,只要 thread_id 不变,Agent 下次运行时能从上次中断点继续——这是构建”可恢复 Agent”的关键能力。

🗑️ 记忆遗忘策略:有遗忘才有智慧

无限积累记忆会导致检索噪声增加、存储成本爆炸、隐私风险。生产系统必须设计主动遗忘机制:

遗忘策略 触发条件 实现方式 适用层
TTL 过期 超过保留时限 Redis EXPIRE / Qdrant payload filter Layer 1 / 2
重要性阈值 importance < 0.3 定期扫描删除低分记忆 Layer 3
容量上限 LRU 记忆数量超出配额 维护访问时间戳,淘汰最久未用 Layer 3
语义去重 余弦相似度 > 0.95 写入时检测近重复,合并或跳过 Layer 3
用户主动删除 隐私/GDPR 请求 按 user_id 批量删除全部向量 所有层

🛠️ 生产工程落地建议

  • 记忆分层隔离:短期记忆放进程内存/Redis(TTL 2小时),实体记忆放 Redis(TTL 30天),语义记忆放 Qdrant(永久+定期清理)。不同生命周期的数据不要混存。
  • 写入异步化:每轮对话后的记忆写入(Embedding + Upsert)放入消息队列异步处理,不能阻塞主对话链路。P99 延迟要求 <500ms 时必须异步。
  • 检索注入量控制:每轮注入的历史记忆建议 Top-3~5 条,总字符数不超过 1000 字符,防止 Token 超限。超出时优先保留 importance 高的。
  • 用户记忆隔离:所有向量必须携带 user_id 字段,检索时强制 Filter,防止记忆越权访问(这是数据安全的底线)。
  • 记忆摘要定期整合:超过 100 条的用户记忆,定期调用 LLM 做记忆整合(Memory Consolidation)——将相似记忆合并为一条高质量摘要,保持向量库的精简和高质量。
  • 冷启动处理:新用户首次会话时,从注册信息/行为数据预填充实体记忆,避免”记忆冷启动”影响首次体验。
  • 可观测性:记录每轮的记忆检索命中率、注入内容、最终回答质量,接入 LangFuse 进行全链路追踪,持续迭代记忆策略。
⚠️ 常见踩坑 1. Entity Memory 不做持久化:LangChain 默认 EntityMemory 存在内存中,进程重启全丢——生产必须接 Redis 后端。
2. 向量记忆无用户隔离:多用户共用一个集合但查询时忘了加 user_id Filter,导致用户 A 看到用户 B 的历史。
3. 记忆无限增长:忘记设置 TTL 和容量上限,6个月后向量库膨胀到 100GB 运维告警。
CODER8023

每天一篇技术干货,助你在面试和工作中脱颖而出

关注公众号 CODER8023,获取最新技术文章

🔜 下期预告:LLM 安全与对齐实战 — Prompt Injection 攻防 + 生产护栏设计