AI 智能体记忆系统实战:从上下文到长期记忆

AI 智能体记忆不是把聊天记录堆在上下文里那么简单。没有记忆的智能体,每轮对话都是「失忆重启」,无法追问、无法沉淀、也无法跨会话延续任务。本文从工程视角拆解智能体的三层记忆架构——工作记忆、短期记忆、长期记忆——并用向量库落地一套可写入、可检索、可压缩、可评测的长期记忆系统,让 Agent 真正「记得住、用得上、不膨胀」。

如果把记忆和上下文混为一谈,工程上一定会走弯路。大模型上下文工程解决的是「单次推理里塞什么」,而记忆解决的是「跨多次、跨多天,Agent 凭什么比上次更聪明」。两者互补,但实现路径完全不同。

一、为什么智能体必须自己管理记忆

LLM 本身是无状态的:每次推理只看到当前这一次传入的 token。上下文窗口无论多大(128K、200K、1M),关掉再打开,模型对之前发生的事一无所知。要让 Agent 具备「连续性」,记忆必须由应用层显式地存、取、管——模型不负责记,应用负责。

没有记忆的 Agent 有三个硬伤:① 无法多轮追问(上一轮说的约束忘了);② 无法从历史交互中学习用户偏好;③ 无法在长任务里累积中间结论。这也是为什么 LangChain Agent 这类框架都要内置 Memory 抽象——它本质上是把「状态」从模型外部接管过来。

二、三层记忆架构:工作 / 短期 / 长期

成熟的智能体记忆通常分三层,对应不同的容量、时效和存储介质:

层级容量时效典型存储职责
工作记忆小(当前轮)毫秒级运行时变量 / 消息列表本轮推理可用的全部上下文
短期记忆中(最近 N 轮)会话内内存 / Redis维持单次会话的连贯对话
长期记忆大(跨会话)永久向量库 + 关系表沉淀用户画像、历史结论、知识

工作记忆就是当前 prompt 里的全部内容;短期记忆是「这一通对话」的滑动窗口;长期记忆才是真正让 Agent 越用越聪明的部分,也是本文重点。

三、长期记忆的存储选型

长期记忆既要「语义检索」(「上次客户投诉过什么」),又要「精确查询」(「用户手机号」)。单一存储很难兼顾,常见组合是「向量库 + 结构化表」:

存储适合存什么检索方式代表实现
向量库对话片段、经验、非结构化结论相似度 / 语义检索Chroma、PGVector、Qdrant
关系表 / KV用户画像、偏好、实体属性主键 / 字段精确查MySQL、Redis、PostgreSQL
对象存储长文档原文、附件路径引用S3 / 本地盘

向量检索部分和 Chroma 向量库Embedding 向量检索 的原理完全一致:把文本编码成向量,再按相似度召回最相关片段。区别只是这里召回的是「记忆」。

四、记忆的写入与检索流程

一个最小可用的长期记忆管理器,核心是两个动作:写(把一条经验向量化入库)和读(把相关记忆召回拼进 prompt)。下面是一段可直接跑的骨架:

import uuid, datetime
from embeddings import embed   # 返回 768 维向量
from vectordb import query, insert

class MemoryStore:
    def write(self, text, scope, meta=None):
        """把一条记忆写入长期存储。
        scope 用于隔离不同用户/会话,避免串档。"""
        vec = embed(text)
        doc = {
            "id": str(uuid.uuid4()),
            "text": text,
            "scope": scope,            # 例如 user:1024
            "meta": meta or {},
            "created_at": datetime.datetime.utcnow().isoformat(),
        }
        insert(collection="memories", vector=vec, document=doc)
        return doc["id"]

    def recall(self, query_text, scope, top_k=5):
        """召回与当前问题最相关的历史记忆。"""
        vec = embed(query_text)
        hits = query(collection="memories", vector=vec,
                     filter={"scope": scope}, top_k=top_k)
        return [h["text"] for h in hits]

关键点在于 scope 隔离:每个用户、每个会话的记忆必须分桶,否则 A 客户的隐私会出现在 B 客户的回答里——这是生产事故,不是优化项。

五、记忆压缩与去重:别让记忆膨胀

长期记忆如果不加治理,会无限增长:存储成本上升、检索噪声变大、prompt 被无关记忆塞爆。必须定期「压缩」——把零散片段聚合成高层摘要。常见做法是用模型自身做摘要:

# 把同一主题的 N 条旧记忆,压缩成一条语义摘要后回写
SUMMARY_PROMPT = """以下是某用户近 30 天的多条历史交互片段,
请提炼为一条不超过 120 字的长期记忆,保留:稳定偏好、反复出现的问题、已确认的结论。
只输出摘要,不要解释。

片段:
{fragments}"""

def compress(memories, scope):
    fragments = "\n".join(m["text"] for m in memories)
    summary = llm(SUMMARY_PROMPT.format(fragments=fragments))
    # 删除旧碎片,写入摘要,避免重复占用
    for m in memories: delete(m["id"])
    return write(summary, scope, meta={"type": "summary"})

去重同样重要:语义相近的记忆要合并,而不是各存一份。可以借用 结构化输出 把记忆打上标签,再按标签做聚合,降低冗余。

六、从 episodic 到 semantic:让记忆沉淀为知识

认知科学把记忆分为 episodic(事件记忆,记得「上周三发生了什么」)和 semantic(语义记忆,记得「这个客户的通用偏好」)。智能体记忆的成熟标志,就是从 episodic 向 semantic 演进:

原始对话是 episodic,经过压缩、归纳后才变成 semantic。semantic 记忆更泛化、更省空间、更抗噪声,是 Agent「越用越懂你」的来源。工程上可以用一个标记字段区分两者,检索时优先返回 semantic,episodic 作为补充证据。

七、实战:一个带记忆的客服 Agent

把上面的零件拼起来,一个最小客服 Agent 的推理循环长这样:

def answer(user_id, question):
    # 1. 召回长期记忆
    mem = store.recall(question, scope=f"user:{user_id}", top_k=5)
    # 2. 召回业务知识(RAG)
    kb = rag_search(question)            # 见 RAG 进阶
    # 3. 组装 prompt
    prompt = build_prompt(question, memories=mem, knowledge=kb)
    reply = llm(prompt)
    # 4. 把本轮有价值的结论写回长期记忆
    if is_worth_remembering(question, reply):
        store.write(f"Q: {question}\nA: {reply}", scope=f"user:{user_id}")
    return reply

注意第四步的「是否值得记」闸门:不是每句话都入库,否则噪声会淹没信号。可以简单用「用户表达了偏好 / 解决了具体问题 / 修正了之前的回答」作为写入触发条件。这个 Agent 的编排框架可参考 MCP 与 A2A 协作 的调用规范。

八、可观测与评测:记忆到底有没有用

记忆系统上线后必须能量化效果,否则只是多了个存储。建议埋三条指标:① 记忆命中率(多少问题召回了相关记忆);② 复用率(被召回的记忆最终进入答案的比例);③ 任务完成率在有/无记忆下的对比。观测可以直接接 Langfuse 这类链路追踪,把每次回忆和写入都打点。更系统的能力评测方法见 AI Agent 评测基准

九、最常见的五个反模式

反模式表现后果
不隔离 scope所有用户记忆混在一个桶串档泄露隐私,严重事故
全量回灌上下文每次把全部记忆塞进 prompttoken 爆炸、噪声淹没信号
从不压缩记忆只增不删存储与检索成本线性上涨
记了不校验模型生成的「记忆」含幻觉错误信念被长期固化为「事实」
无评测记忆系统上线即弃管无法证明收益,易被砍

十、落地检查清单

如果你打算给自己的 Agent 加记忆,按这个顺序走:① 先定 scope 隔离规则(用户/会话分桶);② 选「向量库 + 结构化表」双存储;③ 实现 write / recall 两个最小接口;④ 加「值得记」闸门与定期压缩;⑤ 接可观测,跑有/无记忆的对照评测。记忆不是炫技,它的唯一价值是让 Agent 在第二次见面时,比第一次更懂你。

上一篇 技术团队 OKR 实战:从目标拆解到季度复盘
下一篇 MySQL 字符集与时区踩坑:乱码与时间差 8 小时