智能体的记忆机制:短期与长期记忆设计

记忆让智能体从"金鱼脑"变成能积累经验的助手,是长期可用性的关键。

大语言模型本身是无状态的:每次调用都是独立的,模型不记得上一轮说了什么。我们在对话中感受到的"上下文连贯",实际上是开发者把历史消息重新喂给模型实现的。当对话变长或任务变复杂时,简单的"全部重放"就行不通了,需要设计结构化的记忆机制。

两类记忆的本质区别

维度 短期记忆 长期记忆
存储位置 模型上下文窗口 外部数据库/文件
生命周期 单次会话内有效 跨会话持久存在
容量限制 受token上限约束 理论上无限
检索方式 按时间顺序全量放入 按相关性检索部分放入
典型实现 消息历史数组 向量数据库、键值存储

短期记忆解决"当前对话的连贯性",长期记忆解决"跨对话的知识积累"。一个完整的智能体通常两者都需要。

短期记忆的管理策略

最简单的短期记忆就是把所有历史消息原样放入上下文。但对话轮次一多,token消耗会迅速增长,甚至超出上下文窗口。常用策略有三种:

滑动窗口

只保留最近 N 轮对话,更早的消息直接丢弃。实现简单,适合问答类场景。缺点是会"遗忘"早期的重要信息。

摘要压缩

每隔几轮对话,用模型把较早的历史消息压缩成一段摘要,用摘要替代原始消息。这样既保留了关键信息,又控制了token用量。摘要的频率和粒度需要根据任务调整——太频繁会增加延迟和成本,太稀疏会丢失细节。

混合策略

前几轮和最近几轮保留原文,中间部分用摘要替代。这是目前大多数生产系统的做法,兼顾了准确性和成本。

# 伪代码示例
messages = []
if len(history) > 20:
    # 保留最近5轮原文,其余压缩为摘要
    old_messages = history[:-10]
    recent_messages = history[-10:]
    summary = summarize(old_messages)
    messages = [{"role": "system", "content": f"之前对话摘要: {summary}"}] + recent_messages
else:
    messages = history

长期记忆的实现方式

长期记忆的核心问题是"怎么存"和"怎么取"。

键值存储:结构化事实

把用户的关键信息以键值对形式存储,每次对话开始时加载到系统提示词中。适合存储明确的偏好和事实:

{
  "user_name": "张三",
  "preferred_tone": "简洁直接",
  "industry": "自媒体运营",
  "known_topics": ["短视频", "私域流量", "社群运营"]
}

这种方式实现简单,检索精确,但只能存储预先定义好字段的信息,无法处理模糊的语义匹配。

向量数据库:语义检索

把每条记忆编码为向量存入向量数据库,对话时把当前问题也编码为向量,检索语义最相近的记忆片段。这种方式不需要预定义字段,能处理模糊查询,是目前长期记忆的主流方案。

流程如下:

  1. 每轮对话结束后,提取值得记住的信息(用户偏好、任务结论、事实知识等)。
  2. 将信息分段,每段生成embedding向量。
  3. 存入向量数据库,附带元数据(时间戳、来源、标签等)。
  4. 下次对话时,把用户当前输入编码为向量,从数据库中检索top-K相关片段。
  5. 将检索到的片段拼入系统提示词。

文件存储:可读可编辑

把记忆存为Markdown文件或JSON文件,用户可以直接查看和编辑。这种方式透明度高,用户对"AI记住了什么"有完全的控制感,适合个人助手类场景。

记忆的写入时机

不是所有对话内容都值得记住。写入时机有三种模式:

实践中推荐"批量+按需"的组合:对话结束时自动提取结论性信息,同时支持用户主动触发记忆。

记忆的淘汰机制

长期记忆如果不淘汰,会越来越臃肿,检索质量也会下降。常见的淘汰规则:

记忆机制的设计没有标准答案,需要根据智能体的使用场景和用户期望来调整。核心原则是:该记的不能忘,不该记的不要存,过时的要及时更新。