你明明告诉过 Agent「这个项目不要新增依赖」,下一次它还是装了新包。
这时先不要急着认为模型没有记忆。那句话可能还在聊天历史里,只是没有进入本次模型输入;也可能被压缩成摘要时遗漏了。
理解记忆,要同时看信息保存在哪、怎样取出来、这次有没有交给模型。
七个词,先各放一个例子
| 名称 | 关注什么 | 例子 |
|---|---|---|
| Prompt | 当前指令与输入,有时泛指整份模型输入 | 「修复登录 Bug,不要新增依赖」 |
| Context | 本次模型调用实际可用的信息 | 当前问题、相关历史、代码和工具定义 |
| History | 过去的交互记录 | 上个月的聊天和工具结果 |
| State | 当前执行状态 | 测试失败,等待修复;某工单已创建 |
| Memory | 为后续使用保存的信息 | 用户偏好、项目约束、历史经验 |
| Knowledge Base | 可检索的外部知识资料集合 | 接口文档、产品手册 |
| Cache | 为复用与性能保存的状态或结果 | 某次检索结果、嵌入向量 |
它们会互相转换。历史里可以提炼出记忆,记忆可以被取出放进上下文,工具结果可以保存为缓存。
「不要新增依赖」是约束;「已经修改 login.ts,测试尚未运行」是任务进度。压缩时需要保留两者,但保存目的不同。
Context Engineering,每次到底给模型什么
Context Engineering,上下文工程,管理哪些信息、在什么时候、以什么形式进入模型。
本次模型输入可能包括系统规则、用户目标、最近对话、工具定义、工具结果、检索资料和记忆。界面显示的内容、数据库保存的内容、模型实际收到的内容,不一定相同。
例如任务是修登录 Bug,可以先给模型文件路径和日志摘要,再按需要读取具体代码。如果一开始把整个仓库和所有日志都放进去,增加的既有资源开销,也有无关信息。
上下文的选择与按需读取,参见 Anthropic 的上下文工程文章。
历史太长时,有哪些处理方法
Selection 选择当前相关内容;Trimming 移除低价值或过期内容;Sliding Window 保留最近一段历史。它们可以很简单,但不能盲目删除更早的关键约束。
Summarization 做摘要;Compaction 把长上下文压缩成继续工作所需的材料。摘要可以服务于阅读,Compaction 更关注任务能否接着做。具体实现也可能把两者合并。
Offloading 把大量内容放到文件或外部存储;Just-in-time Retrieval 需要时再取;Context Packing 在预算内选择、去重和排列证据。
比如测试输出有十万行,可以把完整日志存到文件,给模型失败摘要和读取入口。存到文件之后,若没有留下路径和读取方法,后续模型仍然拿不到它。
Compaction 应该留下什么
设想新的一次模型调用只拿到了摘要。它至少应当知道,当前目标、用户约束、已作决定、完成与未完成事项、验证结果、关键对象标识以及恢复位置。
一个为解释结构而写的示例如下。
1 | 目标:修复登录失败,不新增依赖。 |
「研究了登录问题,进展顺利」读起来更短,却不能指导继续工作。
压缩仍然可能丢失细节。关键事实要能回到原文核查,实际文件和测试状态也要重新确认,摘要不能覆盖已经变化的环境。
已有的 Pi Agent 上下文工程从真实实现解释了工具截断、项目规则和历史压缩。
Overflow、Pollution、Rot
Context Overflow 是超出容量或请求限制。Context Pollution 是无关、错误或冲突信息进入上下文。Context Rot 常用来描述信息变长、变杂之后利用质量下降的现象,不是一个统一指标。
比如日志末尾显示数据库权限错误,旧摘要却说「已确定网络故障」,两条信息冲突,可能让模型继续沿过时假设行动。
Lost in the Middle 是关于信息位置影响的研究,讨论了部分模型在部分任务中,中间位置的信息更难利用。不能从这项研究推出所有新模型都有同样的下降曲线;可以阅读 原始论文,具体系统还应自己测。
Memory,两种分类不要混成一种
Short-term Memory 通常指当前任务或会话中的短期信息,Long-term Memory 跨任务或会话保留,Working Memory 是当前处理任务时使用的工作信息。边界依实现定义。
另一个维度按内容分类。
| 类型 | 保存什么 | 示例 |
|---|---|---|
| Semantic Memory,语义记忆 | 事实、偏好 | 用户希望用中文;项目使用 PostgreSQL |
| Episodic Memory,情景记忆 | 事件、经验 | 上次部署失败是环境变量缺失 |
| Procedural Memory,程序性记忆 | 方法、规则 | 发布前先检查迁移,再执行部署 |
一条长期记忆可以是事实,也可以是方法。这些分类帮助设计使用方式,不规定必须对应三个数据库表。LangGraph 的记忆文档使用了相关分类。
记忆不一定要用向量数据库
文件可以存项目约束,关系数据库可以存带来源和版本的事实,向量索引可以辅助查找相似经历,图结构可以组织实体关系。
小项目只有几条约束时,直接读取一个文件就可能足够。更多历史经验需要按任务查找时,再考虑相应检索方式。
「使用向量库」描述存储与检索选择,「有记忆」描述信息怎样被保留和再使用。二者不是等号。
记忆有写入、更新和遗忘
一条记忆至少要考虑来源、作用域和时效。
用户说「这个仓库暂时不要升级 Node」,作用域是当前仓库,时间上可能只是暂时限制。若直接变成「用户永远不升级 Node」,就扩大了解读。
Write 决定什么值得保存;Extraction 从记录中提炼;Merge / Update 处理新旧信息;Retrieval 取出当前需要的内容;Scope / Namespace 限定用户、项目或任务范围;Provenance 保留来源;Expiration / Forgetting 处理过期和遗忘。
新旧记录冲突时,应该查时间和来源,必要时向用户确认。临时猜测不能不加标记地写成长期事实。
Hot-path Write 在当前请求中写入,较及时但增加前台工作;Background Write 后台提炼,前台负担较小,但最新记忆可能尚未可用。两种方式仍需避免重复、冲突和作用域串线。
Memory 和 RAG 怎样合作
Memory 关注后续保留什么,RAG 关注回答时如何检索外部资料。
检索上次部署经验,可能同时涉及 Memory 和 RAG;检索产品手册,可以只有 RAG;读取固定的用户偏好文件,可以有 Memory,但没有复杂检索。
判断「Agent 为什么忘了」时,可以顺着查,原始记录是否存在、是否提炼、作用域是否匹配、是否取出、是否进入本次上下文、内容是否过期或冲突。这样才能知道要修存储、检索,还是输入组织。