0. 引言

想象这样一个场景:你让 Agent 帮你调研一个开源项目。第一轮,你告诉它「只关注 Python 实现,忽略 JS 版本」。第三轮,它兴高采烈地给你推荐了一个 Node.js 库。你纠正了它。到了第五轮,它又忘了。

你忍不住问:你的记性为什么这么差?

这个问题背后,是 AI Agent 领域一个被严重低估的核心挑战——上下文工程(Context Engineering)。大多数人以为,只要上下文窗口足够大(比如 Gemini 的 1M tokens),Agent 就能「记住一切」。但真实情况是:上下文窗口是 Agent 的 RAM,记忆系统才是 Agent 的硬盘——两者缺一不可,且各自有各自的工程难题。

本文将系统性地拆解 Agent 记忆系统,从问题定义到工程方案,分为六个层次逐步深入。


1. 问题定义:上下文窗口的幻觉

长上下文是必要条件,但它带来的问题远比解决的问题多。我们来看四个核心挑战:

1.1 注意力稀释:Lost in the Middle

2023 年,Liu 等人在论文 Lost in the Middle: How Language Models Use Long Contexts 中揭示了一个反直觉的发现:当信息位于上下文窗口的中间位置时,模型的检索准确率会显著下降。

Lost in the Middle 效应

这个发现的重要性怎么强调都不为过。模型不是均匀地「注意」所有上下文——它天然倾向于关注开头(首因效应)和结尾(近因效应),中间部分的信息被严重稀释。当你把 100K tokens 的上下文一股脑塞给模型时,中间 40K-60K 位置的关键指令可能已经被「淹没」了。

1.2 成本爆炸

以 GPT-4 级别模型为例,输入价格为 $10/1M tokens。1M token 上下文的一次推理就要 $10,而一个复杂的 Agent 任务可能需要十几轮甚至几十轮对话。成本不是线性增长,而是飞轮效应——每轮都把历史带上,上下文越来越长,成本越来越高。

上下文长度 单轮成本(估算) 10 轮对话成本
32K tokens $0.32 ~$5
128K tokens $1.28 ~$25
500K tokens $5.00 ~$80+
1M tokens $10.00 ~$150+

1.3 幻觉加剧

上下文越长,无关信息越多。模型在多轮对话中会逐渐被早期噪声干扰,产生「上下文幻觉」——用错误的记忆覆盖正确的信息。这不是模型本身的幻觉问题,而是上下文工程的问题。

1.4 延迟不可控

KV Cache 的大小与上下文长度成正比。1M token 上下文的 prefilling 阶段可能需要数秒甚至数十秒,首 token 延迟(TTFT)从毫秒级膨胀到秒级。对于需要快速响应的 Agent 场景,这是致命的。

结论: 上下文窗口大 ≠ 记忆好。你需要一套工程体系来管理 Agent 的「注意力预算」。


2. 上下文分层架构

Agent 记忆系统的核心设计理念是分层——不是一层记忆,而是三层。

Agent 记忆系统三层架构

2.1 工作记忆(Working Memory)

定义: 当前对话窗口中的全部信息,4K–32K tokens,严格顺序保留。

工作记忆是 Agent 的「意识」。它包含系统提示(角色定义、行为规则)、对话历史(用户输入和 Agent 回复的完整序列)、工具定义(函数签名和参数 schema),以及从长期记忆中检索到的相关上下文。

关键工程挑战:

  • 触发压缩的时机: 当 token 预算达到阈值(如 70%)时,必须触发压缩,而不是等 OOM 再处理
  • 压缩策略选择: 摘要(保留语义,丢失精确细节)vs 截断(保留最新信息,丢失历史)vs 关键对话提取(保留决策点和纠正,丢弃过程噪音)
  • 压缩粒度: 对早期轮次进行激进压缩(只保留摘要),对近期轮次保持原始内容

2.2 情景记忆(Episodic Memory)

定义: 历史会话的结构化摘要,向量化存储,支持语义检索。

情景记忆是 Agent 的「短期记忆」。当一次会话结束后,不是把原始对话全部丢掉,而是提取关键信息——决策、纠正、偏好变化——并以向量的形式存储。

存储什么:

  • 用户在这次会话中的偏好表达(「以后用 pytest 不要用 unittest」)
  • Agent 在这次会话中的关键决策及其原因
  • 用户对 Agent 行为的纠正(「上次你说 X,实际是 Y」)
  • 会话最终产出的摘要

不存储什么:

  • 过程性讨论和试探性尝试
  • 工具调用的中间结果
  • 用户明确表示「不要记」的内容

2.3 语义记忆(Semantic Memory)

定义: 长期累积的结构化知识,包含用户画像、领域知识、工具经验和固化技能。

语义记忆是 Agent 的「长期记忆」,也是最稳定的一层。它不随会话结束而消失,而是逐步累积和更新。

类别 示例 存储方式
用户画像 角色、编程风格偏好、时区 结构化标签
领域知识 项目文件结构、常用 API 端点 文档化存储
工具经验 「该 API 超时设为 30s 而非 5s」 结构化经验库
固化技能 从多次重复操作中提取 SOP 可执行技能定义

核心原则: 语义记忆必须是结构化的,不能是纯文本堆砌。因为它在每次推理时都会被注入到系统提示中,结构化的信息更容易被模型有效利用。


3. Token 预算管理

如果把上下文窗口比作 Agent 的「预算」,那么 Token 就是 Agent 的「货币」。你需要一个精打细算的财务管理系统。

Token 预算分配策略

3.1 静态预算分配

以 128K 上下文窗口为例,建议的分配策略:

组件 建议占比 说明
系统提示 10-15% 角色定义、行为规则、语义记忆注入
工具定义 10-15% 函数签名、参数 schema、工具描述
对话历史 40-50% 工作记忆核心内容
检索上下文 15-20% 从情景记忆中检索到的相关信息
预留余量 5-10% 工具调用返回结果的空间

3.2 动态调度机制

静态分配只是起点。真正的挑战在于动态调度:

工具返回截断: 当工具调用结果超过预留空间时,不直接截断到固定长度,而是提取关键信息——比如从 10000 行的日志中只保留 ERROR 和 WARNING 级别的内容。

递进式压缩: 不是一次性压缩所有历史,而是递进式处理。早期轮次(第 1-5 轮)高度压缩为摘要,中期轮次(第 6-10 轮)保留关键对话,近期轮次(最近 5 轮)完整保留。

记忆外化: 当上下文即将耗尽时,主动将部分信息「外化」到外部存储,并在需要时通过检索召回。这类似于操作系统的虚拟内存机制。

3.3 实践建议

1
2
3
4
5
6
7
8
9
10
# 伪代码:Token 预算检查
def before_each_turn():
tokens_used = count_tokens(system_prompt + history + tools)
tokens_left = max_context - tokens_used - RESERVE

if tokens_left < SAFETY_THRESHOLD:
if oldest_rounds_not_compressed():
compress_oldest_rounds() # 递进式压缩
else:
externalize_to_memory() # 记忆外化

重要提示: 不要信任模型自报的 token 计数。始终使用独立的 tokenizer 维护精确计数,在每次工具调用前后检查预算。


4. 记忆检索:Agent 的搜索引擎

存得好不如取得好。如果检索系统不能在海量记忆中精准召回相关信息,那记忆系统就是个昂贵的摆设。

混合检索流程图

4.1 Agent 场景的检索特殊性

相比传统 RAG,Agent 的记忆检索有三个独特挑战:

  • 时间敏感性: 上一条消息中用户说的「不要用 unittest」比三个月前说过的话重要得多
  • 上下文依赖性: 同样的查询「跑一下测试」,在不同项目、不同阶段含义完全不同
  • 精确匹配需求: 用户可能明确提到实体名(如「那个叫 hermes-agent 的项目」),需要关键词级别的精确匹配

4.2 混合检索公式

单一维度无法满足 Agent 的需求。我们需要混合检索:

1
score = α × 语义相似度 + β × 时间衰减 + γ × 关键词匹配 + δ × 重要性权重

各维度详解:

  • α × 语义相似度(权重 0.40): 基于 embedding 的 cosine similarity,捕捉语义层面的相似性
  • β × 时间衰减(权重 0.25): 指数衰减函数 e^(-λ × Δt),让近期记忆有更高的召回率
  • γ × 关键词匹配(权重 0.20): 使用 BM25 算法,确保用户提到的精确实体能被命中
  • δ × 重要性权重(权重 0.15): 在存储时由 LLM 对记忆的重要性进行预打分

4.3 检索时机

Agent 不应该只在用户明确要求时才去检索记忆。三种触发时机:

  1. 主动检索: 每轮对话开始时,根据用户最新输入检索相关记忆,注入工作记忆
  2. 被动检索: 当 Agent 对自己的回答不确定时,主动查询记忆进行校验
  3. 触发词检索: 用户说「上次」「之前」「我记得你说过」时,强制触发跨会话检索

5. 终身学习:让 Agent 越用越聪明

三层记忆架构解决的是「记住什么」和「怎么取」的问题。但还有一个更深刻的问题:Agent 能不能从经验中学习,而不是每次都需要用户重新教一遍?

这就是终身学习(Lifelong Learning)——Agent 记忆系统的最上层。

5.1 学习什么

Agent 可以从以下几个维度持续学习:

学习维度 触发条件 示例
用户偏好 用户明确表达或行为暗示 「回复简洁一点」→ 更新用户画像
纠正学习 Agent 犯错后被用户纠正 「你说的 X 不对,实际是 Y」→ 更新知识
工具经验 任务执行中遇到问题并解决 「此 API 并发限制 10 req/s」→ 更新工具使用经验
项目约定 用户多次使用相同模式 连续 5 次用 pytest -n 4 → 固化为默认
成功模式 某个任务流程多次成功执行 「这种调研任务分 3 步做最快」→ 固化为技能

5.2 学习机制

显式学习: 用户明确纠正 Agent → 立即更新相关记忆。这是最高优先级的学习信号。

隐式学习: Agent 从成功完成的任务中提取模式。不需要用户干预,但需要足够多的样本(连续 3-5 次相同模式)才会触发固化。

反思学习: 任务失败后,Agent 进行根因分析(Root Cause Analysis),将教训以「反模式」的形式存入记忆,避免下次犯同样的错误。

5.3 防止灾难性遗忘

记忆系统最大的敌人不是「记不住」,而是「记错了」或者「新知识覆盖了旧知识」。

三大防御机制:

  1. 冲突检测: 新记忆与旧记忆矛盾时,优先信任用户最新表达,但保留旧记忆作为上下文参考
  2. 衰减而非删除: 长期未使用的记忆降低检索权重,但不删除。因为「很久没用的知识」可能只是暂时不需要
  3. 定期审计: 定期让 Agent 自查记忆一致性。例如:用户说他是「Python 开发者」,但某条记忆写的是「主要写 Rust」——这种矛盾应该标记出来

6. 工程实践与总结

6.1 架构全景

完整的 Agent 记忆系统架构可以总结为三层 + 两个管道:

  • 三层: 工作记忆 → 情景记忆 → 语义记忆
  • 向下管道(压缩沉淀): 工作记忆过期 → 压缩为情景记忆 → 长期知识提取为语义记忆
  • 向上管道(检索召回): 语义记忆 + 情景记忆通过混合检索 → 注入工作记忆

6.2 选型建议

场景规模 推荐方案
个人开发者 / 原型验证 SQLite + ChromaDB + 简单摘要策略
小团队 / 内部工具 PostgreSQL + pgvector + Redis 缓存 + 混合检索
生产级 Agent 系统 自研记忆服务 + 专用向量数据库 + 事件溯源 + 持续评估管道

6.3 关键启示

回顾全文,我想强调三个核心理念:

  • 「上下文窗口是 Agent 的 RAM,记忆系统是 Agent 的硬盘」——两者缺一不可,且各自需要精心设计
  • 「好的记忆系统让 Agent 从工具变成伙伴」——它不需要你反复交代,能从过往交互中学习成长
  • 「不要等到上下文不够用了才想记忆——在设计的第一天就要考虑三层架构」

6.4 展望

Agent 记忆系统还远未成熟。展望未来,有几个值得关注的方向:

  • 多模态记忆: Agent 不仅要记住文本,还要记住图片、代码片段、结构化数据
  • 联邦记忆: 多个 Agent 共享部分记忆,形成集体智能
  • 自适应记忆架构: 根据用户使用模式自动调整各层容量和检索策略
  • 隐私感知记忆: 用户可以选择性地「遗忘」某些信息,符合 GDPR 等隐私法规

本文首发于 jackzhu.top。如果你在大厂 Agent 团队工作或有相关实践经验,欢迎在评论区交流讨论。