Agent的记忆系统-短期记忆与长期记忆
LLM 有一个基本的物理限制:上下文窗口(Context Window)。模型在每次推理时只能"看到"有限数量的 token——GPT-4o 是 128k,Claude 是 200k,即便是最大的模型也有上限。
Agent 的记忆系统:短期记忆与长期记忆
为什么 Agent 需要记忆:上下文窗口的根本限制
LLM 有一个基本的物理限制:上下文窗口(Context Window)。模型在每次推理时只能"看到"有限数量的 token——GPT-4o 是 128k,Claude 是 200k,即便是最大的模型也有上限。
这个限制带来了一个严重问题:Agent 的"记忆"天然是有界的。
如果把所有历史信息都塞进上下文,很快就会撑爆窗口。如果只保留最近的对话,早期的关键信息就会丢失。一个用户在第 1 轮告诉 Agent "我是 Java 工程师",第 50 轮问"帮我写一个示例"时,Agent 如果因为上下文窗口限制已经"忘记"了用户的技术背景,给出的代码就会南辕北辙。
记忆是解决上下文窗口限制的根本方案
如果把上下文窗口比作人的"工作记忆"(短期、有限、高速),那么 Agent 需要的是:
- 能长期保存的存储(像人类的长期记忆)
- 能按需检索的机制(而不是把所有东西都塞进工作记忆)
- 能区分"当前任务需要"和"背景知识"的智能(按重要性分配有限的上下文空间)
这就是记忆系统要解决的问题。设计好的记忆系统,Agent 才能从一个"会话孤岛"变成一个真正意义上的持续存在的助手。
图:Agent 的三层记忆架构——短期记忆(当前对话上下文,在上下文窗口内)、长期记忆(向量数据库持久化存储)、工具记忆(工具调用结果缓存),三者协同让 Agent 突破上下文窗口限制。
本章介绍 Agent 的记忆架构,包括四种记忆类型及其实现方式,以及记忆检索策略的设计决策。
没有长期记忆的 Agent,每次都从零开始。它没有成长,没有积累,永远是第一天上班的样子。记忆系统是 Agent 从"工具"变成"助手"的关键差异。
人类记忆的四种类型
认知科学把人类记忆分成几个层次,LLM-based Agent 的记忆设计几乎和这个框架一一对应。理解这个对应关系,能帮助我们在做技术选型时找到正确的参照系——不是从"有哪些存储方案"出发,而是从"这种记忆的特性是什么"出发。
感知记忆(Sensory Memory)
持续时间极短,不到一秒。视觉输入先进入感知记忆,如果持续关注,才会进入工作记忆。
对应 Agent:当前 token 输入,模型正在处理的即时信息,也就是当前这一次推理的输入。处理完就消失了。
工作记忆(Working Memory)
短期内能主动处理的信息,容量有限(著名的"7±2"规则)。心算 37×48 的时候用的就是工作记忆,它保持中间结果,处理完就清空。
对应 Agent:当前对话的完整上下文,整个任务执行过程中的状态。在 LangGraph(LangChain 旗下的 Agent 工作流框架,用图结构管理有状态的 Agent 执行过程)里,这就是 State 对象。
情节记忆(Episodic Memory)
具体事件的记忆。"上周三下午讨论了架构方案"——这是情节记忆。它记录的是"什么时候、什么地点、发生了什么"。
对应 Agent:过去执行任务的具体记录,"上次处理这类财报分析时,先搜索了行业数据,发现效果不好,后来改成直接读 PDF 更准确"。存储在向量数据库里,按语义相似性检索。
语义记忆(Semantic Memory)
通用知识和规则,不依赖具体情境。"Python 的 GIL 锁会阻止多线程真正并行"——这是语义记忆。
对应 Agent:外部知识库,RAG 文档,公司内部的技术文档、规范、FAQ。也存储在向量数据库里,但内容是结构化知识,不是个人经历。
四种记忆的实现
工作记忆:LangGraph State
工作记忆是 Agent 执行任务时的运行时状态。在代码里,它对应一个在整个任务生命周期内持续存在的状态对象。
from typing import TypedDict, Annotated, List
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langchain_core.messages import HumanMessage, AIMessage
class AgentState(TypedDict):
# 对话历史(工作记忆的核心)
messages: Annotated[List, add_messages]
# 当前任务的中间结果
task_context: dict
# 已执行的步骤记录
steps_taken: List[str]
# 最终结果
final_result: str
def create_agent_graph():
graph = StateGraph(AgentState)
def think_node(state: AgentState) -> AgentState:
# 工作记忆在整个执行过程中持续传递
messages = state["messages"]
context = state.get("task_context", {})
steps = state.get("steps_taken", [])
# 模型能看到完整的对话历史和任务状态
print(f"当前已执行步骤:{steps}")
print(f"工作记忆中的消息数:{len(messages)}")
return state
graph.add_node("think", think_node)
graph.add_edge(START, "think")
graph.add_edge("think", END)
return graph.compile()
情节记忆:向量数据库存储经验
情节记忆让 Agent 能从过去的经历中学习。每次完成任务,把执行过程和结果存下来;下次遇到类似任务,先检索相关经验。代码中使用 ChromaDB(一个轻量级的开源向量数据库,适合本地开发和原型验证)存储经验记录。
from openai import OpenAI
import chromadb
import json
from datetime import datetime
client = OpenAI()
chroma_client = chromadb.Client()
collection = chroma_client.get_or_create_collection(name="agent_episodes")
def save_episode(task: str, approach: str, result: str, quality_score: float):
"""保存一次任务执行经历到情节记忆"""
episode = {
"task": task,
"approach": approach,
"result_summary": result,
"quality_score": quality_score,
"timestamp": datetime.now().isoformat()
}
# 用任务描述作为向量化内容,方便语义检索
collection.add(
documents=[task],
metadatas=[episode],
ids=[f"episode_{datetime.now().timestamp()}"]
)
print(f"已保存执行经历,质量评分:{quality_score}")
def retrieve_relevant_episodes(current_task: str, n_results: int = 3) -> List[dict]:
"""检索与当前任务相似的历史经历"""
results = collection.query(
query_texts=[current_task],
n_results=n_results
)
episodes = []
if results["metadatas"]:
for metadata in results["metadatas"][0]:
episodes.append(metadata)
return episodes
def agent_with_episodic_memory(task: str) -> str:
# 先检索相关历史经验
past_episodes = retrieve_relevant_episodes(task)
memory_context = ""
if past_episodes:
memory_context = "以下是处理类似任务的历史经验:\n"
for ep in past_episodes:
score = ep.get("quality_score", 0)
approach = ep.get("approach", "")
# 只参考质量高的经验
if score >= 0.7:
memory_context += f"- 任务类型:{ep['task'][:50]}...\n"
memory_context += f" 采用方案:{approach}\n"
memory_context += f" 质量评分:{score}\n\n"
messages = [
{
"role": "system",
"content": f"你是一个有经验的分析助手。{memory_context}"
},
{"role": "user", "content": task}
]
response = client.chat.completions.create(
model="gpt-4o",
messages=messages
)
result = response.choices[0].message.content
# 执行完成后,保存这次经历
save_episode(
task=task,
approach="直接分析 + 历史经验参考",
result=result[:200],
quality_score=0.8 # 实际场景应该由 Critic 评分
)
return result
语义记忆:RAG 知识库
语义记忆是 Agent 的"外脑",存放它需要但不可能全放进上下文的知识。
import chromadb
from openai import OpenAI
client = OpenAI()
chroma_client = chromadb.Client()
knowledge_base = chroma_client.get_or_create_collection(name="semantic_memory")
def add_knowledge(content: str, source: str, category: str):
"""向知识库添加内容"""
knowledge_base.add(
documents=[content],
metadatas=[{"source": source, "category": category}],
ids=[f"doc_{hash(content)}"]
)
def retrieve_knowledge(query: str, n_results: int = 3) -> str:
"""从知识库检索相关内容"""
results = knowledge_base.query(
query_texts=[query],
n_results=n_results
)
if not results["documents"] or not results["documents"][0]:
return ""
retrieved_docs = []
for doc, metadata in zip(results["documents"][0], results["metadatas"][0]):
retrieved_docs.append(f"[来源:{metadata['source']}]\n{doc}")
return "\n\n---\n\n".join(retrieved_docs)
# 预先加载公司内部知识
add_knowledge(
content="代码审查时,关注以下高风险模式:1. SQL 拼接(SQL 注入风险)2. 未加密的敏感数据存储 3. 未验证的用户输入直接传递给命令行",
source="安全规范文档 v2.1",
category="security"
)
def rag_agent(question: str) -> str:
# 从语义记忆检索相关知识
relevant_knowledge = retrieve_knowledge(question)
messages = [
{
"role": "system",
"content": f"你是一个代码审查专家。\n\n参考知识:\n{relevant_knowledge}"
},
{"role": "user", "content": question}
]
response = client.chat.completions.create(
model="gpt-4o",
messages=messages
)
return response.choices[0].message.content
记忆的存储层次
记忆存在哪里,直接决定了它的容量和访问速度:
| 存储层次 | 典型实现 | 容量 | 访问方式 | 适用场景 |
|---|---|---|---|---|
| In-context | Prompt 文本 | 受 context window 限制 | 直接访问 | 当前任务关键信息 |
| 内存缓存 | Redis、Python dict | 中等 | 极快 | 会话级状态 |
| 向量数据库 | ChromaDB、Pinecone(一种全托管的云向量数据库服务) | 近乎无限 | 语义检索 | 长期记忆、知识库 |
| 关系型数据库 | PostgreSQL、MySQL | 无限 | 精确查询 | 结构化历史记录 |
记忆检索:什么时候用语义检索,什么时候用精确查询
这是一个经常被忽视的设计决策。
用语义检索:当不知道确切的查询词,需要找"意思相近"的内容。比如检索"和现在这个任务类似的历史经验",或者"关于这个技术问题的相关文档"。
用精确查询:当有明确的 key 或 ID,或者需要结构化过滤。比如"查询用户 ID 12345 上周的所有操作记录",或者"找出所有质量评分大于 0.8 的执行记录"。
实际系统里通常两者结合:先语义检索缩小范围,再精确过滤。
def smart_memory_retrieval(query: str, min_quality: float = 0.7) -> list:
"""结合语义检索和精确过滤"""
# 第一步:语义检索,找相似内容
results = collection.query(
query_texts=[query],
n_results=10 # 先多拿一些
)
if not results["metadatas"]:
return []
# 第二步:精确过滤,只保留高质量的
filtered = [
metadata for metadata in results["metadatas"][0]
if metadata.get("quality_score", 0) >= min_quality
]
# 按质量评分排序
filtered.sort(key=lambda x: x.get("quality_score", 0), reverse=True)
return filtered[:3] # 最多返回 3 条
记忆系统是 Agent 从"工具"变成"助手"的关键
没有记忆的 Agent 是工具:每次调用都是独立的,没有上下文,没有个性,没有积累。
有了记忆的 Agent 才算助手:它知道用户的习惯,记得上次的决策,能从失败中学习,会随时间变得更懂用户。
这是 Agent 真正落地商业场景的关键能力。一个代码审查 Agent,第一周可能漏掉一些项目特定的代码规范,但如果有情节记忆,第二周它就会记住"这个项目要特别注意这几类问题"。一个客服 Agent,如果能记住客户的历史问题和偏好,给出的答案会完全不同。
记忆系统的设计是 Agent 工程里最容易被忽视,也是最值得投入的部分。