AI Agent 记忆系统的四层架构各层的职责与存储介质是什么?
聊到记忆系统的分层,其实工程界并没有一个“官方钦定”的四层结构,但结合认知科学和实际落地,我习惯把它抽象成下面这四层。每层职责明确,存储介质选型也完全不一样,面试时如果能把这四层讲清楚,基本就超出 90% 的候选人。
👁️ L1:感知缓冲层(Sensory Buffer)¶
职责:
承接摄像头、麦克风、传感器等原始流数据,只做极短时间的“寄存”,不做任何理解。它的核心任务是削峰填谷——下游模块来不及处理时,数据不丢;处理完一帧就扔掉,绝不长期占用资源。
存储介质:
内存环形队列、Redis Stream、Kafka Topic。
特点是高吞吐、自动覆盖、零持久化。
import collections
import time
class SensoryBuffer:
"""最近 3 秒的音频帧缓冲区"""
def __init__(self, max_seconds=3):
self.buffer = collections.deque()
self.max_seconds = max_seconds
def push(self, audio_chunk):
self.buffer.append((time.time(), audio_chunk))
self._evict()
def get_all(self):
self._evict()
return [chunk for _, chunk in self.buffer]
def _evict(self):
now = time.time()
while self.buffer and now - self.buffer[0][0] > self.max_seconds:
self.buffer.popleft()
实际踩坑:这里千万别上磁盘,否则延迟一上来,整个 Agent 的实时性就崩了。
🧠 L2:工作上下文层(Working Context)¶
职责:
维持当前任务的全部“思维素材”——最近的对话轮次、中间推理步骤(CoT)、子目标、工具返回结果等。它决定了 Agent “此刻能考虑多少信息”,也是 token 预算管控的关键。
存储介质:
LLM 上下文窗口本身(消息列表)、内存变量(scratchpad)、必要时靠 Redis 做跨会话的短期暂存。
import tiktoken
class WorkingContext:
def __init__(self, system_prompt, max_tokens=4000):
self.messages = [{"role": "system", "content": system_prompt}]
self.scratchpad = ""
self.max_tokens = max_tokens
self.enc = tiktoken.get_encoding("cl100k_base")
def add(self, role, content):
self.messages.append({"role": role, "content": content})
self._trim()
def _trim(self):
total = sum(len(self.enc.encode(m["content"])) for m in self.messages)
while total > self.max_tokens and len(self.messages) > 1:
removed = self.messages.pop(1) # 保留 system prompt
total -= len(self.enc.encode(removed["content"]))
这一层的难点不是存,而是 怎么在信息超载时聪明地忘掉不重要的部分。
📝 L3:情景历史层(Episodic History)¶
职责:
把每次交互的事件摘要、用户反馈、决策结果打包成“经验片段”,支持按时间或语义检索。下次遇到相似场景时,Agent 能翻出“上次我们怎么解决的”。
存储介质:
向量数据库(Chroma / Milvus)存 embedding + 元数据,关系数据库(PostgreSQL)存完整日志,方便按时间范围查询。
import chromadb
from datetime import datetime
from sentence_transformers import SentenceTransformer
class EpisodicMemory:
def __init__(self):
self.client = chromadb.Client()
self.collection = self.client.create_collection("episodes")
self.encoder = SentenceTransformer('all-MiniLM-L6-v2')
def store(self, user_input, agent_action, outcome):
text = f"input: {user_input}\naction: {agent_action}\noutcome: {outcome}"
emb = self.encoder.encode(text).tolist()
self.collection.add(
embeddings=[emb],
documents=[text],
metadatas=[{"timestamp": datetime.now().isoformat(), "outcome": outcome}],
ids=[str(abs(hash(text)))]
)
def recall(self, query, k=3):
emb = self.encoder.encode(query).tolist()
return self.collection.query(query_embeddings=[emb], n_results=k)["documents"][0]
面试加分点:提到会设计 记忆衰减权重,让 Agent 更倾向于采纳近期高质量的经验。
📚 L4:语义知识层(Semantic Knowledge)¶
职责:
存领域知识、产品手册、政策文档等去情境化的稳定知识。和情景历史不同,它不关心“什么时候学的”,只关心“这个事实本身对不对”。
存储介质:
文档块 + 向量索引(FAISS / Pinecone),或结构化知识图谱(Neo4j)。通常结合 RAG 架构,检索后注入工作上下文。
from sentence_transformers import SentenceTransformer
import numpy as np
class SemanticKnowledgeBase:
def __init__(self, documents):
self.encoder = SentenceTransformer('all-MiniLM-L6-v2')
self.chunks = []
self.embeddings = []
for doc in documents:
emb = self.encoder.encode(doc).tolist()
self.chunks.append(doc)
self.embeddings.append(emb)
self.embeddings = np.array(self.embeddings)
def query(self, question, top_k=2):
q_emb = np.array(self.encoder.encode(question))
scores = np.dot(self.embeddings, q_emb) / (
np.linalg.norm(self.embeddings, axis=1) * np.linalg.norm(q_emb)
)
top_idx = np.argsort(scores)[-top_k:][::-1]
return [self.chunks[i] for i in top_idx]
⚡ 四层架构总览¶
| 层级 | 职责 | 典型存储介质 | 生命周期 |
|---|---|---|---|
| 👁️ 感知缓冲 | 暂存原始流,等待处理 | 环形队列、Redis Stream | 毫秒~秒 |
| 🧠 工作上下文 | 维持当前思考窗口 | 内存消息列表、scratchpad | 单次任务 |
| 📝 情景历史 | 积累具体交互经验 | 向量库+元数据库 | 跨会话长期 |
| 📚 语义知识 | 存储稳定领域知识 | 向量索引/知识图谱 | 静态或定期更新 |
🔄 一个延伸思考¶
我们在 L3 和 L4 上都用了向量检索,但当情景记忆(“上次客户这么说是要退款”)和语义知识(“退款政策是 7 天内”)给出的指引矛盾时,Agent 该听谁的?
这背后其实是记忆检索的 优先级仲裁机制——它比选哪个向量库更能决定系统的可靠程度。