用户一周前留下过一项偏好,今天接着做任务,Agent 却像第一次听见。很多开发者会先增加历史对话,把旧消息继续拼进 Prompt。短对话里还能撑住,记录一长,上下文窗口和 token 成本都会被吃掉。
亚马逊 AWS 官方博客解释了原因:LLM 每次只能处理上下文窗口里的信息,Prompt 和此前的对话都要占用空间。内容超出窗口后,模型就无法继续访问。PPIO也提到,重复发送历史对话会增加 token 成本。
工程里的“记住”,通常要经过写入、找回,再把结果放回当前 Prompt。数据已经存下,却没有在这次请求中取出来,模型照样看不见。
先别把聊天记录一股脑扔进向量库
小林面试笔记把 Agent 记忆分成感知记忆、短期记忆、长期记忆和实体记忆。四类信息的用途不同,读取方法也不同。
| 记忆类型 | 放什么 | 怎么读取 |
|---|---|---|
| 感知记忆 | 当前输入的原始内容 | 直接参与当前推理 |
| 短期记忆 | 上下文窗口中的近期对话 | 随 Prompt 提交 |
| 长期记忆 | 外部存储中的历史内容、用户偏好和成功模式 | 通过语义检索召回 |
| 实体记忆 | 用户、任务等结构化事实 | 按字段精确查询 |
它们更像一条分流路线。当前输入先被读取,需要延续当前对话的内容留在短期记忆;有跨会话价值的信息,再进入长期记忆或实体记忆。
把所有对话切片、生成 embedding、塞进向量数据库,看起来最省事。麻烦也从这里开始:语义相近,不代表事实完全相同。向量库适合寻找“意思接近”的内容;偏好、任务状态等需要精确读取和更新的事实,更适合保留结构化入口。
《AI Agent 开发实战》提醒,向量相似度无法保证精确匹配,召回率和准确率也需要取舍。只靠相似度查关键事实,拿到的记录可能很像,却不是当前要找的那一条。
写入时,先想清楚以后怎么找
记忆写入规则可以从未来的读取方式倒推:
当前输入
├─ 仅供当前处理 → 感知记忆
├─ 需要延续当前对话 → 短期记忆
├─ 以后按语义找回 → 长期记忆
└─ 以后按字段查询或更新 → 实体记忆
同一段对话可以形成不同记录。用户偏好本身适合抽取成实体事实,相关对话如果还包含有价值的背景,可以同时保留为长期记忆。前者方便精确查询和更新,后者负责补充语境。
存储记录中可以保留这些信息:
- 记忆内容及所属类型;
- 对应的用户或任务;
- 信息来源;
- 创建与更新时间;
- 需要语义检索时使用的 embedding。
来源和更新时间能帮助应用处理新旧信息。用户偏好发生变化后,旧记录要更新还是失效,应当有明确规则。否则,相互矛盾的偏好可能一起进入 Prompt,最后只能交给模型猜。
召回的顺序,比多拿几段历史更要紧
读取时可以按这个顺序处理:
当前请求
→ 按用户和任务查询实体记忆
→ 语义召回长期记忆
→ 合并必要的短期对话
→ 组装 Prompt
先拿到需要精确匹配的事实,再寻找语义相关的历史内容。长期记忆的检索范围也要受当前用户和任务约束,避免把无关记录送进上下文。
最终进入 Prompt 的内容应当包括当前请求、必要的近期对话、明确的实体事实,以及与任务相关的长期记忆。长文本上下文只是提供了更大的空间,它不会替应用判断哪些历史值得保留,也处理不了新旧事实之间的冲突。
向量维度只是其中一个参数。《AI Agent 开发实战》列出的常见维度是 768 或 1536,OpenAI 的 text-embedding-3-small 为 1536 维。这些数字值得在选型时确认,但解决不了错误的数据分层。偏好如果一直埋在普通对话切片里,实体事实又没有及时更新,embedding 选对了也可能找错内容。
模型没有一条以“一周”为界的遗忘线
同一场对话里,较早的信息只要超出上下文窗口,模型就可能无法访问。外部存储中的记录只要被正确召回,一周前的内容仍然能参与当前回答。
假设用户一周前留下了一项需要跨会话沿用的偏好。写入时,偏好本身进入实体记忆;相关对话中有用的背景,可以保留在长期记忆里。
今天的新请求到来后,应用先按用户查询这项偏好。任务需要更多背景时,再通过向量检索找回相关历史,最后和短期上下文一起组装进 Prompt。Agent 能接上这段历史,是因为应用把旧信息重新提供给了模型。
自建或托管,应用仍要定规则
AWS 官方博客给出了自建和托管两条路径:团队可以基于亚马逊云科技的数据产品搭建记忆模块,也可以评估 Bedrock AgentCore 的 Agent memory 托管方案。
服务可以接管部分存储和检索设施,记忆规则仍要由应用定义:什么值得保存,写进哪一层,冲突时如何更新,这次请求又该取回哪些内容。
《AI Agent 开发实战》还把 PostgreSQL 列为长期记忆的存储示例。实际组合可以让 PostgreSQL 保存实体、来源和更新时间,向量索引负责语义召回,没必要让向量数据库兼任所有角色。
还在忘事,就顺着存取过程排查
- 上下文窗口被当成唯一记忆:内容超出后,模型无法继续访问。
- 每次都回传完整历史:窗口很快被占满,token 成本也会增加。
- 偏好和任务事实只进向量库:相似度检索无法保证精确匹配。
- 记录已经写入,却没有执行召回:数据存在,模型仍然看不见。
- 召回结果没有放进 Prompt:检索完成了,生成时却没有使用。
- 新旧偏好缺少更新规则:相互冲突的记录可能同时进入上下文。
感知记忆接住当前输入,短期记忆续上对话,长期记忆负责语义找回,实体记忆保存可精确更新的事实。设计时多问几个具体问题:这条信息以后按语义找,还是按字段查?新记录出现后,旧记录怎么处理?当前请求究竟需要哪段历史?
这些问题有答案,一周前的对话就不必整段重放。应用取回相关语义、明确事实和必要的近期上下文,再交给模型。