# 记忆系统 · 上下文、RAG 与持久存储 · Agent 实战 · 从零构建完备智能体

**作者** Aklman · **章节** 04 / 19 · **首发** 2026.07 · **语言** 中文为主, 中英双语
**原文** https://library.aklman.com/books/build-agent/04-memory
**全书 markdown** https://library.aklman.com/books/build-agent/llms.md
**上一章** https://library.aklman.com/books/build-agent/03-tool-use/llms.md
**下一章** https://library.aklman.com/books/build-agent/05-reasoning/llms.md

> 本章来自 Aklman · Library, 完整免费阅读。允许 AI 摘读、引用、问答; 转载请保留作者署名与原文链接 (CC BY-NC-ND 4.0, https://library.aklman.com/license)。

---

> 上下文窗口是工作记忆，RAG 是参考书架，持久存储是长期记忆 —— 三层记忆各司其职。

研究助手一旦真去搜、去抓，messages 就越滚越长 —— 几十个页面塞进去，上下文窗口会满、账单会涨，而且模型会变笨。这不是比喻，是 context rot：上下文越长，它从里面准确召回的能力越差。所以记忆不是「记更多」，是「在有限的注意力预算里，放对的东西」。

三层记忆，每层管对：上下文工程治窗口，RAG 治检索，持久存储治跨会话。三层混用，是大多数记忆 bug 的根源。

### I · 三层记忆，别用一层干三层的活

上下文窗口是工作记忆，RAG 是参考书架，持久存储是长期记忆。三层各司其职，错配就出 bug。

判断一条信息该放哪层，一句话：**每轮都要看的**放窗口，**偶尔按需查的**放 RAG，**跨会话要留的**落盘。用窗口当长期记忆会烧钱又撑爆，用 RAG 存当前对话会慢又检索不准 —— 错层是大多数记忆问题的真正来源。下面两节，把窗口和检索分别管对。

---

### II · 上下文工程 —— 在注意力预算里做减法

窗口不是越满越好。模型有「注意力预算」，token 越多，它越分心、召回越差 —— 底层是自注意力随序列长度的 O(n²) 代价。[^5]记忆工程的第一课是减法，不是加法。

这就是 context rot：needle-in-a-haystack 研究发现，上下文越长，模型从里面准确召回的能力越差 —— 所有模型都有，只是曲线陡缓不同。[^2]所以目标不是「装更多」，是找「最小的高信号 token 集」。具体三种减法：

- **压缩 Compaction**: 把旧历史总结成几句，保留关键决定和未解的 bug，丢掉冗余的工具输出（Claude Code 就这么做）。最轻的一种是 tool result clearing —— 工具的原始输出用完即清。

- **记笔记 Note-taking**: 把笔记记在窗口之外，按需取回。Claude 玩宝可梦能跨几小时记住「我已经练了 1234 步」，靠的就是这种外部记忆，而不是把一切塞进窗口。

- **子 agent 隔离**: 让子 agent 用干净的窗口干细活，只把 1000–2000 token 的摘要交回协调者（呼应第八章）。细节留在子窗口里，主窗口只拿结论。

还有省钱那一面：system 和 tools 每轮都不变，缓存掉，cache read 只花基础输入 token 价的约 10%。[^1]

_缓存每轮都不变的前缀（system + tools）_
```text

```python
resp = client.messages.create(
 model="claude-opus-4-8", max_tokens=1024,
 system=[{"type": "text", "text": SYSTEM_PROMPT,
 "cache_control": {"type": "ephemeral"}}], # 缓存断点
 tools=TOOLS, # tools 也一并缓存
 messages=messages,
)
assert resp.usage.cache_read_input_tokens > 0 # 验证命中
```

```

减法是有判断的，丢错了下一轮就少了关键信息。规矩是：保留决定和未解问题，丢掉冗余和已消费的工具输出。缓存省的是钱和延迟，不是窗口空间 —— 窗口还是会满，所以减法照样要做。

---

### III · RAG 要做对，长期记忆要管对

放不进窗口的，要么 RAG 检索，要么落盘长期记住 —— 但两者都比「塞进一个向量库」难。

RAG 的真问题是检索质量，不是「能不能检索」。[^4]朴素分块会丢上下文：一个 chunk 写「营收同比增长 3%」，但哪家公司、哪个季度都没了，检索自然不准。Anthropic 的 Contextual Retrieval 解法是给每个 chunk 加 50–100 token 的情境前缀，再做 embedding + BM25：单用 contextual embeddings 失败率降 35%，加 BM25 降 49%，再加 reranking（先取 top-150、重排后留 top-20）降 67%（5.7% → 1.9%）。[^3]这串数字说明一件事 —— RAG 的提升在检索管线里，不在换一个更大的模型。

长期记忆是另一回事：跨会话要留的（偏好、任务进度、学到的事实）写盘，下次会话开头加载回 system。第二节的 note-taking 既是上下文减法，也是长期记忆的载体 —— 笔记落了盘，就跨了会话。别什么都塞 RAG：检索不准就是往窗口里注入噪音，先问「这几条固定事实直接写进 system 是不是更省事」。长期记忆的坑是隐私 —— 它在你盘上越记越多，是资产也是攻击面，第九章再画这条线。

---

### IV · 带权限的检索 —— 先过滤，再检索

上面三层管的是「记得准不准」。企业里还有一条独立的线：这条记忆，当前这个用户、这个租户，有没有权限看。这不是 RAG 的一个参数，是一道必须画在检索之前的线。

差别在过滤的位置。**检索后过滤**（post-filter）：先在全库里检索，拿到 top-K，再把用户无权看的删掉。它的问题不在最终结果 —— 结果是对的 —— 在于**过程会泄露**：命中数、相关性分数、分面计数（「财务类命中 12 条」），都在告诉用户「有一份你不该知道存在的文档，和你的查询高度相关」。存在性本身就是信息。**检索前过滤**（pre-filter）：先按 `tenant_id` / ACL 把可见集合圈出来，只在这个集合里检索。用户无权看的东西，从一开始就不在候选里，连「有没有」都问不出来。企业级检索必须是后者。

_先过滤再检索：可见集合圈定在检索之前（企业篇 · 多租户）_
```text

```python
# ✗ 检索后过滤:全库检索,结果虽对,但命中数/分数泄露了存在性
hits = index.search(query, top_k=20)
visible = [h for h in hits if can_see(user, h)] # 太晚了

# ✓ 检索前过滤:先按身份圈定可见集合,只在里面检索
scope = visible_ids(user.tenant_id, user.acl) # 身份章的 tenant_id 在这里落地
hits = index.search(query, top_k=20, restrict_to=scope)
```

```

还有两条随之而来。一是**新鲜度与来源分层**：system-of-record（数据库、工单系统里的当前事实）和 memory（agent 自己攒的笔记）不是一回事 —— 前者是权威、要实时查，后者是助记、可能已过时。别让一条三个月前记进笔记的「余额」冒充当前余额。二是这条权限线是**租户隔离**的落点：第十四章会讲，多租户里最硬的一条就是租户 A 的检索永远碰不到租户 B 的数据 —— 而它就画在这里，检索之前，不在 prompt 里靠一句「别串租户」。身份章给 Principal 装的 `tenant_id`，正是为了在这一层被用上。

动手 · 亲眼看见 context rot，再治它：

- 给研究助手一个要查很多来源的问题，在第 1 轮和第 20 轮问同一个早期事实 —— 看它抓了一堆页面后还记不记得。

- 加一种上下文减法（compaction 或 note-taking）和 `cache_control`，量一下 token 用量和召回的变化。

- 如果你用了 RAG，给 chunk 加情境前缀 + 一个 reranker，对比改造前后的检索命中率。

> 记忆不是记更多，
> 是知道什么丢、什么留。

## 引用与参考

01 · Anthropic 文档 · Prompt caching —— 用 cache_control: {type: ephemeral} 缓存稳定前缀（tools → system → messages）；cache read 约为基础输入 token 的 10%，5 分钟 / 1 小时两档 TTL。示例模型 claude-opus-4-8。截至 2026-05。  (Anthropic · Prompt caching)
02 · Anthropic · 「Effective context engineering for AI agents」（2025-09-29）—— 注意力预算（attention budget）、context rot（上下文越长召回越差）；减法手段：compaction / tool result clearing、structured note-taking（外部记忆）、sub-agent 隔离。  (Anthropic · Effective context engineering)
03 · Anthropic · 「Introducing Contextual Retrieval」（2024-09-19）—— 给每个 chunk 加 50–100 token 情境前缀再做 embedding + BM25；contextual embeddings 失败率降 35%，加 BM25 降 49%，再加 reranking（top-150 → top-20）降 67%（5.7% → 1.9%）。  (Anthropic · Contextual Retrieval)
04 · Lewis et al. · 「Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks」（2020，arXiv:2005.11401）—— RAG 的奠基论文：把外部知识按需检索后注入生成。  (arXiv · RAG (2005.11401))
05 · Vaswani et al. · 「Attention Is All You Need」（2017，arXiv:1706.03762）—— Transformer 与自注意力，你编排的底座。自注意力的计算量随序列长度成 O(n²)，这正是上下文越长越贵、窗口是硬约束的架构根因。  (arXiv · Attention Is All You Need (1706.03762))

---

*记忆系统 · 上下文、RAG 与持久存储 · Agent 实战 · 从零构建完备智能体 · Aklman 著 · CC BY-NC-ND 4.0 · https://library.aklman.com/books/build-agent/04-memory*
