「AI学习笔记」Agent Memory(一)会话内记忆

会话内的事算记忆吗

有人说不算。理由是:工作记忆就是 prompt 本身,模型读一遍就完事了,压根没存下来,那算什么记忆。

也有人说,这就是短期记忆。

其实会话内真正在做的事不是"存",是"取舍":什么留在窗口里、什么换出去、什么等要用的时候再拉回来。

举两个例子你就明白为什么这事要紧。你在会话内把工具结果全清光了,回头就没法从里面提炼出"这个工具到底该怎么用"的经验;你压缩的时候把用户那句纠正当噪声丢了,那它就是真的没了,找不回来。

所以哪怕你只关心长期记忆,也得关心会话内这层------它在整条链路的最上游。

一、窗口变大并没有解决问题

先破除一个直觉:上下文都到百万 token 了,是不是把东西全塞进去就行?

通常不行。有两个常见失效模式挡在前面。

Context rot(上下文腐蚀)。 当上下文很长、噪声较多,或任务需要跨越多个位置整合信息时,模型从新增 token 中获得的有效收益可能逐渐下降,甚至出现幻觉、自相矛盾和含糊回答。它不意味着"上下文一长就必然失效",具体程度仍取决于模型、任务、内容组织和提示方式。Anthropic 在工程指南里强调:在碰到硬上限之前,每增加一个 token 的边际收益就可能开始下降

Lost-in-the-middle。 长 prompt 中段的信息往往比头尾更难被稳定召回,但影响程度会随模型架构、训练方式、窗口长度、提示布局和任务类型变化,并不是"跟模型和窗口都没关系"。对一个跑了几十轮的 Agent 来说,用户偏好、早先的承诺、上个问题怎么处理的,恰好容易落到这段不利位置。

Anthropic 给的框架很适合拿来做工程判断:上下文是有限的、边际收益递减的资源,核心纪律是找到足够完成任务的高信号 token 集合。

把它当 RAM 看就对了。RAM 变大能缓解压力,但有没有换页策略,仍然决定它好不好用。

二、三个手段

很多人把这三件事糊成一个模块,结果三边都做不好。

手段 做什么 解决什么问题 会话结束后
压缩 把窗口内容蒸馏成高保真摘要,Agent 带着摘要继续跑 对话变长后的性能衰减 通常消失
清理 丢掉旧的、可重新获取的工具结果,同时保留调用记录 工具输出膨胀 消失
记忆 结构化记笔记,写到持久外部存储 跨任务、跨会话的进度追踪 留下

三者的区别一句话就能记住:压缩是维持有效上下文,清理是去噪,记忆是留档。 压缩有时也能降低 token 成本,但那是结果,不是首要目标。

工具结果清理这条里有个细节特别容易被跳过:只丢结果,留住调用记录。 因为对推理来说,"我查过这个了"和"结果是什么"是两种不同的信息------前者防止 Agent 白干一遍,后者才是真占地方的那部分。很多自己写清理逻辑的实现,一刀把整条 tool call 连根删掉,然后 Agent 就开始转圈重查。

Anthropic 公布过一组实测数据(link):

  • 内部检索类任务评测上,清理 + 记忆组合相比基线提升 39%
  • 只做清理提升 29%
  • 一个 100 轮网页搜索评测里,清理让原本会因上下文耗尽而失败的工作流跑完,token 消耗降低 84%

这些数字说明特定评测中的收益,不应直接当成所有模型和业务的预期值。

三、压缩的四种思路:多维对照,不是单轴排序

压缩不是一件事,而是一组处在不同维度、不同抽象层的思路:截断 / 滑窗和滚动摘要是内容处理方式,分级渐进是调度策略,自主折叠则同时涉及触发机制与训练方案。下面按触发、输出、可逆性和训练要求做多维对照,不把它们解释成代价或可逆性单调递增的四级阶梯。

方案 1:截断 / 滑动窗口

留最近 N 轮,其余全扔。实现成本很低,也基本不判断信息价值。

它更适合短对话、没有长程依赖的客服问答。放到长任务里风险很高------因为它扔掉的可能就是最早出现的任务目标。

方案 2:滚动摘要 / 分块读 + 状态更新

不一口吞下整个文档,而是分块读,每读完一块就更新一份紧凑的状态。

这条路研究做得比较系统。MemAgent 的做法是一块块读文档、更新一份紧凑记忆、最后拿累积记忆生成答案,效果是从 8K 上下文训练外推到 350 万 token 的 QA 任务、性能损失不到 10%,512K 的 NIAH / RULER 测试上 95%+(arXiv:2507.02259)。QwenLong-L1.5 是同一思路的完整后训练配方:先把一个 30B 推理模型做到能稳定吃下 256K,再靠外部记忆 Agent 扩到 100 万--400 万 token 区间(arXiv:2512.12967)。

工程上真正值得抄的是它的状态结构:不光存"读到了什么"(Memory),还存"接下来要读什么"(Plan)。 只有摘要没有计划,Agent 在长文档里更容易迷路;有 Plan,相当于给滚动压缩装了个方向盘。

这类结果至少提示了一件事:在某些任务上,小窗口 + 合适的压缩策略,可能优于大窗口 + 没有策略。窗口大小不是唯一变量,换页策略同样重要。

方案 3:分级渐进压缩

一次压缩可以由一组策略逐级兜底:前一级不足以释放所需空间时,再进入下一级。

AgentScope 的 AutoContextMemory 给出了一套框架特定的六级顺序:先处理历史工具调用,再扩大消息卸载范围,最后摘要当前轮。

  1. 历史工具调用压缩(要调 LLM,token 超阈值触发)
  2. 大消息卸载(不调 LLM,保护最近 N 条)
  3. 卸载范围扩大(不调 LLM)
  4. 历史轮次 LLM 摘要
  5. 当前轮大消息 LLM 摘要
  6. 当前轮整体按比例压缩(兜底)

这套顺序表达的是该框架的逐级兜底流程,不是严格的代价排序,也不能推出所有实现都应先避开 LLM。落地时应测量自身消息分布、模型调用成本、卸载与回取延迟,再按评测结果安排顺序。所有压掉的内容都按 UUID 存档,配专门的工具随时把原文拉回来------这是懒加载,不是截断。

这也说明它跟第一种处理方式的关键差别:信息离开了窗口,但没离开系统。

方案 4:自主触发的结构化折叠

这个方案把部分触发权交给 Agent 自己。

DeepAgent 的记忆折叠(memory folding)就是这一路:Agent 在推理过程中自己判断时机,把过往交互压成结构化的情景(episodic)、工作(working)、工具(tool)三类记忆 ,然后拿压缩后的结构替代原始历史,接着往下推。论文把目标归纳为两个问题------工具调用导致的上下文长度增长,以及交互历史堆积带来的错误累积。项目 README 的说法是让 Agent 暂停一下,重新整理策略再继续,内容经改写)。

它还配了一套端到端 RL(ToolPO),用 LLM 模拟的 API 来训练,把奖励归因到工具调用的 token 上。

"自主触发"为什么重要? 固定阈值压缩是在 token 数达标时触发,不一定碰巧对应推理陷进死胡同 的时刻。而后者也可能需要重新组织历史------这时候目标不是单纯减少 token,而是从已经跑偏的路径上退出来。DeepAgent 的三类记忆分区(发生了什么 / 现在要干什么 / 工具怎么用),本质上是给下一轮推理准备一份交接文档。

4 个方案的多维对照

思路及定位 触发时机 输出形态 可逆 需训练 适合
截断/滑窗(处理方式) 固定阈值 短对话
滚动摘要(处理方式) 每块读完 Memory + Plan 通常需要 超长文档处理
分级渐进(调度策略) 框架特定的逐级兜底 摘要 + UUID 存档 通用 Agent 框架
自主折叠(触发与训练方案) Agent 自己决定 结构化 JSON 三分区 取决于实现 需要(RL) 长时序工具型推理

工程上的默认起点可以是:分级渐进 + 可逆卸载。它不要求额外训练,原文仍可回取,代价也相对容易控制。等 Agent 频繁出现"在错误路径上原地打转"的症状,再评估是否需要自主触发与相应训练方案。

四、卸载:让不必进窗口的内容留在窗口外

上面四种思路都在处理"已经进了窗口的东西"。更直接的做法,是让不需要立即参与推理的内容先别进来。

两条路:

大结果落盘,窗口里只留引用。 工具返回 50 万字的日志,进窗口的可以是一个文件路径加一句摘要;模型真需要细节时,再用文件工具去读。Anthropic 把这类做法归到"programmatic tool calling"------让大结果不直接进入模型上下文。

大消息按需回取。 就是上面第 3 种思路说的 UUID 存档机制。差别在于,卸载可以是主动的(预判这部分短期内大概率用不到),而不是等超过阈值再被动执行。

这条思路推到更远,就是 Anthropic 的 memory tool:记忆可以表现为一个目录里的文件,模型用普通文件工具增删改查。 存储在自己的基础设施上,通过工具调用在客户端执行。它本身是跨会话机制,但本文只取它在会话内的一个用途:把窗口当索引,把文件系统当可回取的外部存储。

五、KV cache:它不是记忆,但会约束记忆怎么注入

KV cache 不是记忆本体:它不决定记住什么,也不负责压缩、卸载或回取。对记忆注入来说,初中级开发者先掌握下面三条工程规则即可。

规则一:稳定前缀放前面

system prompt、工具定义、长期人设、团队规范这些每轮相对稳定的内容,适合放在前面。

规则二:动态内容后置或按需查询

检索结果、时间戳、动态状态等高频变化内容尽量往后放,避免反复改写稳定前缀。对于每轮都可能增删改的原子记忆,也可以提供只读查询工具,在模型需要时再调用,并把结果追加到当前历史末尾。

按需查询会多一次工具调用往返,因此要结合查询延迟和调用频率判断是否划算。

规则三:以实际平台测试为准

不同推理服务的缓存匹配、保留和路由方式并不相同。工程上应查看所用平台的文档,并实测命中率、延迟和成本,不要把某一种实现假定为通用规则。
进阶:自建推理服务中的实例亲和与共享缓存可以组合

因果掩码使 token 只能依赖前文,因此稳定前缀在 prefill 阶段的计算有机会复用;中间内容变化后,后续位置通常需要重新计算。在多实例服务中,可以同时使用会话实例亲和与共享缓存后端来提高复用机会,它们不是二选一。托管 API 用户通常无需、也未必能够控制这些底层后端,应以平台提供的能力和实测结果为准。

六、注入预算:从小预算开始,用评测调参

缺少业务数据时,先设保守的小预算,再根据任务成功率、召回质量和延迟逐步调整,不把起始配置当作通用定律。

成熟实现一般会让三重限制同时生效:条数上限、字符/token 预算上限、检索超时上限。召回变慢时,可以减少返回内容,避免卡住主链路。

当注入内容占窗口显著比例时,应优先排查是否大段搬入原文、是否缺少摘要和按需回取、是否真的需要这么多内容;最终边界仍由具体模型、任务和评测决定。

七、这些取舍会传导到下游

最后提醒一件事:会话内这三个决策,会直接决定之后还能做什么。

  • 清理工具结果时丢了什么 → 决定能不能从这个会话里提炼出"这个工具到底该怎么用"的经验
  • 压缩摘要保留了什么维度 → 决定沉淀下来的东西是有结构的(发生了什么 / 现在要干什么 / 工具怎么用),还是一段难以复用的自然语言
  • 压缩是截断还是可逆卸载 → 决定事后还能不能回去核对原文。派生内容可能失真,因此需要保留可追溯的原始层

所以下面清单的最后一条,服务的不只是当前会话,也是后续提取长期记忆时的可追溯性。

八、会话内落地清单

  • 分清三类动作:压缩维持有效上下文,清理移除可重取噪声,持久记忆留给跨会话层处理
  • 先定保留规则:任务目标、用户纠正、关键决策、未完成事项和工具调用记录优先保留
  • 给压缩设触发条件:同时考虑 token 压力、工具结果膨胀和推理是否跑偏,不只盯固定阈值
  • 大结果先卸载:原文落盘,窗口保留摘要、引用和回取工具;删除前确认内容可重取
  • 摘要带状态与计划:至少说明已经完成什么、当前结论、下一步和未决问题
  • 稳定前缀与动态内容分开:减少在 prompt 中段反复重写,并按实际服务验证缓存收益
  • 保留可追溯原始层:让摘要、结论和后续长期记忆都能回到原始工具结果或对话片段核对

可观测性:记录"压过什么",也记录"能不能继续做"

每次压缩或卸载至少记录:触发原因、被卸载内容的引用、后续回取次数、压缩前后 token,以及任务在压缩后是否恢复并继续完成。这样才能区分"窗口确实变短了"和"Agent 仍然知道自己在做什么"。如果只看 token 降幅,很容易把丢任务状态误当成优化成功。

参考来源

相关推荐
“AI国潮设计-小江”2 小时前
【Python/SDXL实战】潮汕国潮IP视觉落地:普宁英歌舞猫IP & 创意甜品设计(附ComfyUI工作流与商业授权说明)
开发语言·人工智能·python·prompt·aigc
染指11103 小时前
113.Agent-LangChain核心组件-大模型Short-term_memory短期记忆和PostgreSQL记忆存储
人工智能·langchain·agent·agents
用户283209679373 小时前
Function Calling 只是开始:Agent 工具系统到底难在哪
agent
Rocky Ding*4 小时前
一文读懂LLM Agent Skills 的运行时本质:从能力路由到渐进式披露
论文阅读·人工智能·深度学习·机器学习·aigc·ai-native·agent skills
AaronLou4 小时前
Effect 的类型报错怎么读:认全 `Effect<A, E, R>` 这三个位置,一半报错自己就解释了
agent
AaronLou4 小时前
TypeScript 后端那些你自己手写的样板,Effect 一次性收掉
agent
TunerT_TQ4 小时前
智能体评测的哲学——当“跑分”不再等于“能力”|第0期 · 序章
安全·架构·agent
JouYY4 小时前
我用DSH高效管理了我的prompt收藏
架构·llm·agent
烬羽4 小时前
单 Agent 是直线代码,多 Agent 是一张会分岔、循环、暂停的图:LangGraph 工作流编排
agent·ai编程