9.4.3 短期记忆

很多人一提“Agent 记忆”,脑子里先想到“长期存档”。 但真实系统里,最先决定体验的,往往反而是短期记忆:
系统能不能稳稳记住“这次任务正在发生什么”。
这一节讲的就是这层“工作记忆”。
学习目标
- 理解短期记忆和长期记忆的区别
- 理解为什么不能把整段历史无限塞给模型
- 掌握对话窗口、运行态状态、摘要记忆三种常见短期记忆方式
- 看懂一个简单的短期记忆管理器
- 知道短期记忆最常见的失效方式
短期记忆到底是什么?
一句话理解
短期记忆可以先理解成:
系统为了完成当前这轮任务,暂时保留的上下文和中间状态。
它通常包括:
- 最近几轮对话
- 当前任务目标
- 已执行步骤
- 临时中间结果
和长期记忆有什么不同?
| 类型 | 关注什么 |
|---|---|
| 短期记忆 | 当前这次任务要用的信息 |
| 长期记忆 | 跨任务、跨会话仍然有价值的信息 |
例如:
- “用户上一句说想查退款政策” -> 短期记忆
- “这个用户喜欢简洁回答” -> 更像长期记忆
为什么不能把所有历史都一直塞给模型?
因为上下文窗口不是无限的
模型能看的上下文长度有限。 如果你把所有历史都不断塞进去,会遇到:
- token 成本越来越高
- 响应越来越慢
- 重要信息被淹没
信息越多,不一定越好
很多新人会觉得:
“多给模型一点历史,总不会错吧?”
其实不一定。
因为如果上下文里混了太多无关内容,模型反而更容易:
- 抓错重点
- 复读旧信息
- 忘掉当前真正要做的事
所以短期记忆真正要解决的不是“记得越多越好”,而是:
在有限预算里,保留当前最有用的信息。
短期记忆最常见的三种形态
对话窗口(sliding window)
最简单的方式:
- 只保留最近 N 轮消息
优点:
- 简单
- 实现成本低
缺点:
- 太久之前的重要信息会被挤掉
运行态状态(task state)
不是只记聊天文本,而是明确记:
- 当前任务目标
- 已经查过什么
- 下一步该做什么
这类状态对 Agent 特别重要。
摘要记忆(summary memory)
当历史太长时,不是全丢掉,而是先压缩成摘要。
例如:
- 保留最近 4 轮原文
- 更早的内容压成一段总结
这是一种很常见的折中方式。
一个最简单的短期记忆:滑动窗口
可运行示例
messages = [
{"role": "user", "content": "你好"},
{"role": "assistant", "content": "你好,我可以帮你做什么?"},
{"role": "user", "content": "我想了解退款政策"},
{"role": "assistant", "content": "你是想了解时间范围,还是具体条件?"},
{"role": "user", "content": "主要看时间范围"},
]
window_size = 3
short_term_memory = messages[-window_size:]
for msg in short_term_memory:
print(msg)
预期输出:
{'role': 'user', 'content': '我想了解退款政策'}
{'role': 'assistant', 'content': '你是想了解时间范围,还是具体条件?'}
{'role': 'user', 'content': '主要看时间范围'}
这段代码虽然简单,但已经很重要
它教你一件最本质的事:
短期记忆最先是一个“保留哪些消息”的选择问题。
不是所有历史都值得继续带着走。
但仅靠消息窗口还不够
为什么不够?
看这组对话:
- 用户说“我想查退款政策”
- 后面又连续问了几轮别的细节
- 到第 10 轮又问“那我这种情况能退吗?”
如果你只保留最近 3 轮,系统可能已经忘了:
- 当前任务其实一直围绕“退款”
所以 Agent 还要有结构化状态
例如:
task_state = {
"goal": "帮助用户判断退款条件",
"last_tool": "search_policy",
"latest_policy_result": "购买后 7 天内且学习进度低于 20% 可退款"
}
print(task_state)
预期输出:
{'goal': '帮助用户判断退款条件', 'last_tool': 'search_policy', 'latest_policy_result': '购买后 7 天内且学习进度低于 20% 可退款'}
这类状态和原始聊天记录不同,它更像:
系统正在干什么的工作区。
一个更有教学意义的短期记忆管理器
下面这个例子同时管理:
- 最近几轮消息
- 当前任务状态
class ShortTermMemory:
def __init__(self, max_messages=4):
self.max_messages = max_messages
self.messages = []
self.state = {}
def add_message(self, role, content):
self.messages.append({"role": role, "content": content})
self.messages = self.messages[-self.max_messages:]
def update_state(self, **kwargs):
self.state.update(kwargs)
def snapshot(self):
return {
"messages": self.messages,
"state": self.state
}
memory = ShortTermMemory(max_messages=3)
memory.add_message("user", "我想查退款政策")
memory.add_message("assistant", "你更关心时间范围还是条件?")
memory.add_message("user", "先看时间范围")
memory.update_state(goal="判断退款资格", topic="退款政策")
print(memory.snapshot())
预期输出:
{'messages': [{'role': 'user', 'content': '我想查退款政策'}, {'role': 'assistant', 'content': '你更关心时间范围还是条件?'}, {'role': 'user', 'content': '先看时间范围'}], 'state': {'goal': '判断退款资格', 'topic': '退款政策'}}

这个例子真正比“只存历史消息”强在哪里?
因为它把短期记忆拆成了两层:
- 文本上下文
- 结构化状态
这在 Agent 系统里非常重要。
摘要记忆:当消息越来越长怎么办?
一种常见策略
真实系统很常见这种做法:
- 最近几轮消息原样保留
- 更早历史压缩成摘要
一个简化版示例
old_messages = [
"用户先问了退款政策",
"之后问了证书要求",
"最后又回到退款条件"
]
summary = "用户本轮主要目标是判断自己是否满足退款条件,中间顺带问过证书。"
recent_messages = [
{"role": "user", "content": "那我学习进度 30% 还能退吗?"}
]
memory_package = {
"summary": summary,
"recent_messages": recent_messages
}
print(memory_package)
预期输出:
{'summary': '用户本轮主要目标是判断自己是否满足退款条件,中间顺带问过证书。', 'recent_messages': [{'role': 'user', 'content': '那我学习进度 30% 还能退吗?'}]}
这就是最基本的“摘要 + 最近窗口”的思路。
短期记忆在 Agent 里到底解决什么?
它主要解决三件事:
保持当前任务连贯性
系统不能每一步都像第一次见到用户那样重新开始。
让多步执行不丢状态
例如:
- 已经调用了哪个工具
- 已经查到了什么
- 还差哪一步
控制上下文成本
短期记忆不是只为“记住”,也是为了:
- 少塞无关内容
- 降低 token 成本
- 提高响应稳定性
短期记忆最常见的失效方式
记得太少
表现:
- 系统突然忘了刚才正在说什么
记得太多
表现:
- 上下文又长又乱
- 回答跑偏
- 成本变高
只存消息,不存状态
表现:
- 多步任务容易掉链子
- 工具调用前后状态衔接差
只存状态,不存对话原文
表现:
- 容易丢掉用户原始表达
- 语气、约束和细节缺失
所以短期记忆通常不是“只选一种”,而是组合设计。
初学者最常踩的坑
把短期记忆和长期记忆混在一起
短期记忆解决的是当前任务,不是用户画像全集。
以为消息窗口越大越稳
窗口太大也会带来噪声和成本。
忽略结构化状态
这会让 Agent 一到多步任务就开始发飘。
小结
这一节最重要的不是记住“窗口”“摘要”这些词,而是抓住这条主线:
短期记忆的目标,不是无限保留历史,而是在有限上下文里维持当前任务的连贯性。
真正设计得好的短期记忆,通常既包含最近消息,也包含任务状态,有时还会加一层摘要压缩。
练习
- 把本节的
ShortTermMemory扩展成支持summary字段。 - 把最大消息窗口从 3 改成 5,观察
snapshot()输出怎样变化。 - 想一想:如果一个 Agent 经常忘掉“当前已经调过哪个工具”,你会优先补消息窗口,还是补结构化状态?
- 用自己的话解释:为什么说短期记忆解决的是“当前任务连贯性”,而不是“长期用户画像”?