第 7 章:Retrieval、Compaction 与 Background Updates¶
1. 如果你不会把正确内容重新取出来,memory 就没用¶
当你已经把 short-term、long-term 和 profile memory 分开之后,下一个现实问题就是:agent 到底应该怎样把需要的记录重新带回 prompt?
很多系统就是从这里开始退化的:
- prompt 里塞进太多不相关上下文;
- retrieval 返回的是“相似”,却不是“有用”;
- summaries 越来越长,却没有更清晰;
- 每一次新迭代都只让上下文变得更重。
也就是说,问题已经不再是“有没有 memory”,而是 memory 已经变得太吵、太贵、太难读了。
2. Retrieval 不是“找回所有相似内容”,而是“挑出对当前任务有帮助的内容”¶
Retrieval 有一个坏习惯:如果你不限制它,它就会变得过于慷慨。结果进入 prompt 的,不是最有帮助的内容,而是 embedding 或 keyword overlap 上最相似的内容。
对 production 系统来说,更有用的思路是:
- retrieval 不需要返回很多;
- retrieval 必须是可解释的;
- retrieval 必须尊重 tenant、source 和 trust boundaries;
- retrieval 必须服从上下文预算。
一个正常的 retrieval pipeline,几乎总会同时考虑:
- tenant isolation;
- memory class;
- recency;
- confidence;
- provenance;
- policy filters。
3. 一个好的 prompt 爱的是高密度信号,不是完整性¶
人很容易以为“上下文越多,agent 越聪明”。实践里,情况往往相反:你塞进 prompt 的噪音越多,模型越难抓住真正的优先级。
所以 retrieval 回答的应该不是“我们能取出什么”,而是“什么能在此刻提高正确决策的概率”。
一个很有用的 practical rule:
- 3 条高度相关记录,通常比 20 条勉强相似记录更好;
- 一个带来源的小 summary,通常比长原始文档更好;
- 一个 profile hint,通常比整段偏好历史更好;
- 空 retrieval,通常比不可信且不可解释的 retrieval 更好。
4. Compaction 不是美容,而是保持系统可工作的手段¶
如果 memory layer 只会增长,那么 prompt assembly 迟早会变成一个没有规则的垃圾收集器。这就是为什么 compaction 必须是架构的一部分,而不是某次专项清理工程。
Compaction 可以意味着很多事:
- 把几条记录压成一个 summary;
- 删除过期的 working notes;
- 合并重复项;
- 把大 blob 替换成规范化 record 加 source link;
- 让旧记录降权,而不是永远留在前景里。
更适合把 retrieval 和 compaction 看成一整个 memory maintenance 循环
flowchart TD
A["New run"] --> B["Query memory"]
B --> C["Apply filters and ranking"]
C --> D["Assemble prompt context"]
D --> E["Model + tools"]
E --> F["Create new memory candidates"]
F --> G["Background compaction and review"]
G --> H["Normalized memory store"]
H --> B 5. 不是所有 memory 更新都应该发生在 hot path¶
这是 agent systems 里最有价值的架构转变之一。起初,几乎所有人都想把 memory 做成“立刻就好”:agent 看见了什么,就立刻重写 summary、更新 profile、保存 knowledge。
但这通常既昂贵又危险。
通常适合留在 hot path 里的:
- 最小 session state;
- 简短 working notes;
- 带清晰 TTL 的安全 transient records;
- 如果不更新,当前 workflow 就真的会断掉的内容。
通常更适合放到 background 的:
- 长会话的 compaction;
- summaries 重建;
- facts 规范化;
- deduplication;
- persistent write 前对 memory candidates 的复查。
Background updates 让 memory 变得整洁,而不只是“反应很快”。
6. 好系统会把 retrieval query 和 maintenance jobs 分开¶
在成熟架构里,几乎总会有两条不同路径:
- read path:为当前 run 快速而安全地取回上下文;
- maintenance path:不受 latency 压力地慢慢改进 memory store。
这不仅是性能问题,也是决策质量问题。当同一条链同时:
- 执行任务;
- 重建 summaries;
- 写 profile memory;
- 清理重复项;
- 更新 ranking metadata,
它很快就会变得脆弱且难以解释。
7. 一个 retrieval 与 background updates 的 policy 示例¶
下面是一个很实用的模板。它不追求万能,但很清楚地展示了哪些决定应该被写明。
retrieval:
max_records: 5
max_tokens: 1800
allowed_classes:
- short_term
- long_term
- profile
require_tenant_match: true
min_confidence: 0.75
deny_sources:
- raw_external_html
- unreviewed_summary
compaction:
run_mode: background_only
summary_max_tokens: 400
deduplicate: true
merge_similar_records: true
drop_expired_short_term: true
当这些规则是显式的,团队讨论 memory 时就不再停留在感觉,而会讨论真实限制和 trade-offs。
8. 一个 prompt assembly 前 ranking 的简单代码示例¶
下面不是一个“聪明”的 retrieval engine,而是一个故意写得可读的例子。它展示了 ranking 不应该只看 similarity,还应该看 trust、freshness 和重要性。
from dataclasses import dataclass
@dataclass
class RetrievedRecord:
text: str
similarity: float
confidence: float
recency_weight: float
trusted: bool
def score(record: RetrievedRecord) -> float:
trust_bonus = 0.15 if record.trusted else -0.2
return (
record.similarity * 0.5
+ record.confidence * 0.25
+ record.recency_weight * 0.1
+ trust_bonus
)
def select_for_prompt(records: list[RetrievedRecord], limit: int = 3) -> list[RetrievedRecord]:
ranked = sorted(records, key=score, reverse=True)
return ranked[:limit]
这套逻辑很粗,但有一个重要优点:它是可以讨论、可以测试、也可以逐步替换成更精细方案的,同时不会丢掉 explainability。
9. Summaries 应该帮助理解,而不是隐藏数据来源¶
团队常常把 summaries 当作“把更多 memory 挤进更少 token”的手段。这没问题,但有一个陷阱:summary 不能变成新的匿名真相。
一个好的 summary:
- 比原始记录更短;
- 保留 provenance;
- 不混 tenants;
- 不丢掉关键限制;
- 被标记为 derived artifact,而不是 raw fact。
一个糟糕的 summary:
- 听起来很自信,但没人知道它来自哪里;
- 把冲突事实混在一起;
- 丢失日期和数据 owner;
- 被当作 trusted instruction 喂给模型。
10. Retrieval systems 最常坏在哪里¶
这些问题通常会一遍遍重复:
- duplicates 被塞进 prompt;
- retrieval 不知道 class boundaries;
- ranking 不考虑 trust;
- summaries 变得过于泛化;
- 没有 background jobs,memory 只会膨胀;
- nobody knows why this exact chunk was retrieved.
最后这一点尤其重要。如果你已经无法解释为什么某段上下文进入了 prompt,那系统基本已经失去良好控制了。
11. 实用检查清单¶
如果你想快速检查 retrieval layer,可以问:
- 有没有 records 数量上限和 token budget?
- ranking 是否不仅考虑 similarity,也考虑 confidence、recency 和 trust?
- read path 和 maintenance path 是否分开了?
- compaction 是不是一个 регулярный процесс,而不是手工 уборка?
- summary 能不能看到 provenance?
- 有没有防止跨 tenant 或错误 class 的 retrieval?
如果连续几个问题答案都是 “no”,那说明你已经有了 memory,但还没有形成 memory discipline。
12. 接下来读什么¶
到这里,关于 memory 的基础部分已经开始成形。接下来你可以继续深入 retention 和 deletion,也可以转去看 tools 和 execution。