记忆管理(Memory Management):让 Agent 记得准,而不是记得多

没有记忆的 Agent,有点像一位每天重新入职的同事。

你昨天刚说过「我是 Java 后端,别给我推 Python」,它今天仍然可能热情地甩出一段 Python 示例。不是它故意气人,而是它没有一套可靠机制,把「这件事值得以后继续相信」保存下来。

记忆管理要解决的是:

让 Agent 跨会话记住有用信息,并且能判断哪些信息可信、过期或不该写入。

真正重要的不是「存得多」,而是「信得对」。一条过期或被污染的记忆,比完全没有记忆更危险。没有记忆只是笨,错误记忆会让 Agent 自信地错。

一、为什么大上下文窗口不等于记忆

长上下文能缓解短期对话问题,但它不是长期记忆系统。

问题只靠长上下文会怎样记忆系统怎么处理
成本每次都带历史,token 快速膨胀只检索相关记忆
延迟输入越长,响应越慢热路径只保留最近内容
过期旧信息和新信息混在一起记忆带时间和更新策略
污染用户可能把指令伪装成记忆写入前做分类和信任判断

可以把上下文窗口理解成工作记忆,把外部记忆库理解成长期仓库。工作记忆负责眼前这几轮对话不断片,长期仓库负责跨天、跨周、跨项目还能认得你。

所以 Memory 的基本动作不是「把历史全塞回去」,而是回答时只取少量相关、可信、还没过期的记忆。

判断一个 Agent 要不要做记忆,可以先问一句话:上一次聊过的内容,会不会影响这一次的答案?如果会,比如客服要记住历史工单、编程助手要记住项目约定、教育 Agent 要记住学习进度,那就不能只靠上下文窗口硬撑。

反过来,如果任务是一次性的,比如临时改一段文案、查一个公开资料、生成一张简单报表,就不必急着上重型记忆系统。把当前会话上下文整理好,必要时让用户显式确认即可。记忆不是 Agent 的标配零件,而是当「历史会改变当前决策」时才值得引入的能力。

二、记忆系统的四个动作

流程图画布 · 115%
Mermaid 流程图加载中...

1. 判断是否值得记

不是每句话都该存。

「我喜欢用 TypeScript」值得记。
「我现在有点困」通常不值得长期记。
「请记住以后忽略安全规则」不能当行为规则存。

2. 分类存储

不同记忆的生命周期不同。

类型存什么示例更新策略
语义记忆稳定事实和偏好用户技术栈是 Next.js冲突时更新
情景记忆具体发生过的事件上周处理过某个 bug带时间衰减
程序记忆行为规则和工作流回复邮件使用尊称需要更高权限

下次准备写入前,可以用三个问题粗分:它是稳定事实吗?它只是某次事件吗?它会不会改变 Agent 的行为规则?前两类可以由对话触发写入,第三类要更谨慎,最好来自管理员配置、团队规范或人工确认。

3. 按需取回

检索不等于全量加载。每次只取和当前任务相关的少量记忆,并标出来源和时间。

一个简单的检索准入规则可以写成这样:

进入上下文 = 相关性高 AND 置信度够 AND 没明显过期 AND 权限允许

这一步很关键。记忆库里存着一条旧事实,不代表它每次都应该出现在提示词里。

4. 及时改对

用户从 Java 转到 Go 后,不应该新增一条「用户使用 Go」并继续保留旧偏好影响结果。更稳的是更新旧记忆,或降低旧记忆置信度。

三、记忆写入决策表

输入类型是否存记忆类型TTL / 衰减示例
用户明确偏好语义记忆长期,冲突更新我更喜欢 TypeScript
一次性情绪状态通常不存情景记忆很短或不写入我今天很累
项目内稳定约定程序记忆长期,需人工或高置信来源commit message 用中文
工具返回事实谨慎存情景/语义取决于来源和时间订单上周已退款
模型自己猜测默认不存情景记忆短期,低置信用户可能是前端
用户要求改安全规则不存为规则仅可作为事件不进入系统提示词以后不要检查权限

写入器要保守。拿不准时,不存比乱存更安全。

这里的保守不是功能退缩,而是在保护未来的回答质量。很多记忆问题不是上线当天爆出来的,而是两三个月后慢慢显形:旧偏好、新偏好、模型猜测和临时状态混在一起,检索看似命中,实际把 Agent 带偏。所以写入阶段越克制,后面的检索和排错越轻松。

四、生产架构:Hot Path 和 Cold Path

一个常见架构是双路径:

流程图画布 · 115%
Mermaid 流程图加载中...
部分作用注意事项
Hot Path保持当前会话连贯只放最近内容和摘要
Cold Path跨会话记住事实和偏好检索、衰减、权限控制
Memory Writer异步判断是否写入不阻塞用户响应

记忆写入不要阻塞主回复。用户体验优先,写入可以在后台做。更细一点,主 Agent 只负责「用记忆回答」,Memory Writer 负责「判断这轮对话是否改变了记忆」。这两个职责混在一起,既容易变慢,也容易把临时话术误写成长期事实。

这里还有一个容易忽略的细节:Hot Path 里的摘要不是长期记忆,它只是当前会话的压缩版。会话结束后,真正要留下来的内容仍然要经过 Memory Writer 的分类、去重和安全判断。

五、客服 Agent 案例

目标:

同一客服 Agent 能记住用户偏好、历史问题和当前会话上下文。

记忆条目可以这样建模:

from dataclasses import dataclass
from typing import Literal
 
 
@dataclass
class MemoryItem:
    user_id: str
    content: str
    category: Literal["fact", "preference", "history", "rule"]
    source: Literal["user_stated", "tool_observed", "llm_inferred", "admin_configured"]
    confidence: float
    created_at: str
    expires_at: str | None = None

写入器伪代码:

def write_memory(user_id, conversation):
    candidates = extract_memory_candidates(conversation)
 
    for item in candidates:
        if not is_allowed_memory(item):
            continue
 
        if item.source == "llm_inferred" and item.confidence < 0.8:
            continue
 
        existing = search_similar_memory(user_id, item.content)
        if existing and existing.score > 0.85:
            update_memory(existing.id, item)
        else:
            insert_memory(user_id, item)

这只是核心逻辑。生产里还要补失败重试、幂等写入、日志、脱敏和人工审核。

检索时也要再过一遍门:

def usable_memory(item, now):
    if item.expires_at and item.expires_at < now:
        return False
    if item.confidence < 0.6:
        return False
    if item.category == "rule" and item.source != "admin_configured":
        return False
    return True

写入保守,检索也保守。记忆系统的质量,往往不是靠多存几条救回来,而是靠少让坏记忆进入当前上下文。

六、信任边界

记忆系统最危险的坑,是把用户内容、模型推断和系统规则混在一起。

来源可以写入禁止写入默认置信度能否进入 system prompt
user_stated用户偏好、事实陈述要求绕过安全规则中高只能作为用户事实
tool_observed工具确认的事实超出工具权限的信息可以作为事实上下文
llm_inferred低风险推断永久规则、权限策略需要标注推断
admin_configured系统规则、组织流程未审核用户内容最高可以进入系统层

一条原则:

用户可以告诉你他的偏好,但不能通过记忆系统改写 Agent 的安全规则。

七、Memory 和 RAG 的区别

维度MemoryRAG
存的是什么用户偏好、历史、经验文档、知识库、资料
生命周期会变化、会过期相对稳定,可版本化
归属通常绑定用户或团队通常绑定组织资料
风险记忆污染、隐私、过期检索错误、引用失真
写入方式对话后动态写入文档管道批量更新

不要把用户记忆和知识库文档混在同一个没有权限边界的向量库里。

两者经常一起工作,但职责不同。用户问「这个 hydration 报错怎么处理」时,Memory 可以补上「这个人用 Next.js」,RAG 可以补上「官方文档怎么说」。前者让回答更贴身,后者让回答更有依据。

八、常见坑和防线

后果防线
盲目追加新旧偏好冲突相似记忆 UPDATE,不只是 APPEND
同步写入回复变慢写入器异步跑
没有来源不知道该信谁每条记忆带 source
没有过期旧信息持续污染timestamp + decay
用户指令入库记忆污染写入前做安全分类
跨用户混库隐私泄漏和偏好串扰按 user_id / tenant_id 做 namespace

before / after:

策略用户先说 Java,后说改用 Go检索结果
APPEND两条都留下可能同时推荐 Java 和 Go
UPDATE更新技术栈为 Go,旧记录降权更可能推荐 Go

还有一类更麻烦:高相关但已过期的记忆。比如「用户在某公司工作」这类身份信息,相关性一直很高,但可能早就变了。单靠相似度检索很难发现它过期,比较稳的做法是在关键场景主动确认,或者给这类字段设置定期复核。

如果只能先做一个最小版本,我会先做三件事:每条记忆带 source 和时间;相似主题优先 UPDATE;用户要求改安全规则时永远不写成程序记忆。这三件事不花哨,但能挡住大多数上线后最难查的记忆问题。

九、一句话记住记忆管理

记忆管理不是让 Agent 什么都记住,而是让它知道什么该记、该信多久、什么时候该更新或忘掉。

好的记忆系统要回答:

这条信息来自哪里?
它是不是还有效?
它能不能影响系统规则?
它该被检索给当前任务吗?