土法炼钢兴趣小组的算法知识备份

【数据库研究前沿】数据库作为 LLM 记忆体:语义缓存、RAG 与一致性

文章导航

分类入口
database
标签入口
#llm-memory#semantic-cache#rag#gptcache#memgpt#pgvector#consistency

目录

大语言模型(Large Language Model, LLM)本身是无状态的。它只记得 prompt 里出现的内容,超出 context window 就遗忘。“记忆”是外挂进去的,而最常见的外挂形态就是数据库——向量库、关系库、KV 库,或者三者组合。

当我们把数据库当 LLM 的记忆体,很快就会遇到一组熟悉的老问题:读到旧值、写丢失更新、会话之间互相污染、多轮对话里的”事实”前后矛盾。这些问题在数据库教科书里已经被讨论了四十年——linearizability、causal consistency、read-your-writes——只是在 LLM agent 场景里换了名字叫 “semantic drift”、“hallucinated memory”、“context leak”。

本文上半梳理 LLM 记忆体的系统视角:GPTCache 的语义缓存、MemGPT 的分层记忆、向量记忆与事实记忆的分工;下半给出一个用 pgvector + 触发器实现的会话一致性语义缓存工程样例。


一、为什么需要 “数据库式” 记忆

直接把对话历史拼进 prompt 是最朴素的记忆方案。它的极限是 context window——今天最大的开源模型也才 1M token 级,而且长 context 下注意力质量显著衰减(lost-in-the-middle 现象)。更重要的是:

把历史挪到数据库就同时解决这三点。但挪进去的瞬间也继承了数据库的一切麻烦——事务、一致性、并发、GC。

1.1 两类记忆,不要混为一谈

一个常见的工程误区是把 “LLM 记忆” 当成单一概念。实际上至少要分两类:

这两类记忆的一致性要求完全不同。向量记忆容忍”有点过时”(毕竟 top-k 本身就是近似),事实记忆通常要求”至少读到自己写的”。把两者放在一个库一个一致性模型里是常见踩坑源。


二、GPTCache:语义缓存的第一性原理

GPTCache(Bang et al., NLP-OSS @ EMNLP 2023)是第一个被广泛讨论的 LLM 语义缓存开源项目。它的核心问题很小:同样的问题被反复问,没必要每次都让 LLM 重算

2.1 语义键匹配

传统 HTTP / DB 缓存的键是”字符串完全匹配”。LLM prompt 字符串每次都略有不同(用户会换个说法),所以需要语义键

原始 query:   "how many orders last week?"
同语义 query: "tell me the count of orders in the past 7 days"

GPTCache 的做法:

  1. 把 query encode 成 embedding。
  2. 在向量库里找 top-k 最近的历史 query。
  3. 如果最近的距离 ≤ 阈值,就返回历史 query 对应的 LLM 答案。
  4. 否则调用 LLM,并把 (query, embedding, answer) 写回缓存。

2.2 语义缓存的一致性陷阱

语义缓存看起来很美,但在真实系统里会出几类问题:

解决这些的方法依然是传统数据库方法:加 key、加租户隔离、加 TTL、加回归测试,没有银弹。GPTCache 的价值在于把问题暴露出来,让工程师意识到 “语义缓存不是缓存,是一种近似数据库”。


三、MemGPT:把 OS 的分级存储搬进 LLM

MemGPT(Packer et al., arXiv 2310.08560, 2023, “MemGPT: Towards LLMs as Operating Systems”)把 LLM 当成 CPU,上下文窗口当成 RAM,外部数据库当成磁盘,构建了一个分级存储。它的几个核心抽象:

模型自己决定什么时候把 main context 里的内容 “write-back” 到 archival,什么时候把 archival 的内容 “page-in” 到 main。这套抽象解决了单会话里的长期记忆问题。

3.1 MemGPT 的工程启发

MemGPT 本身论文关注的是”让 LLM 自己管理记忆”。对工程师而言可迁移的抽象是:


四、一致性模型:把经典结论映射到 agent memory

这是本文最关键的一节。很多 LLM agent 项目的 bug 本质是用了一个连 DBA 都不会接受的一致性模型

4.1 线性化(Linearizability)

线性化要求所有操作看起来是按某个全局顺序一次发生,而且顺序与实时时间一致。它是强一致的金标准。

在 agent memory 场景:如果用户刚说”我讨厌番茄”,紧接着问”你记得我讨厌什么吗”,应该回答”番茄”。这是一个典型的 read-your-writes 要求。没有任何理由放弃这个保证,否则用户体验直接塌方。

工程实现:同一会话的读写必须走同一个数据库连接 / 同一个主副本。这是所有以”多副本 + 最终一致性”为默认的系统(ES、DynamoDB、大多数向量库)需要注意的地方。

4.2 因果一致性(Causal Consistency)

用户 A 的会话里告诉 agent”把我搬到伦敦”,用户 A 后续的会话应该看到这条记录;但用户 B 是否同步看到,不需要。只要会话内、用户内因果一致即可。

这是一个比线性化弱、但对分布式向量库更可行的保证。实现要点:

4.3 会话隔离(Session Isolation)

跨用户 / 跨 session 的污染是生产事故的常见源:

隔离姿态:每一条记忆记录都带 session_id + user_id + tenant_id,查询必须带这三把筛子。这一点在下半的 pgvector demo 里会具体演示。

4.4 MVCC 的启发

数据库的多版本并发控制(Multi-Version Concurrency Control, MVCC)给 agent memory 一个非常有用的设计思路:记忆不原地改,写入新版本。这样:

关于 MVCC 的细节可参考 MVCC 原理与实践MVCC 变体。把这些经典机制复用到 agent memory 上,比重新发明一套规则划算得多。


五、RAG 与记忆的边界

Retrieval-Augmented Generation(RAG)常被和 “LLM 记忆” 混为一谈。它们有共通之处也有差异:

好的架构是把两者分库:RAG 走向量库(Milvus / pgvector / Qdrant),按 chunk 索引;Agent memory 走关系库 + 向量扩展(pgvector、Timescale),以会话 / 用户为主键,向量只是一个辅助召回通道。


六、工程样例:pgvector + 触发器实现语义缓存

下半给一个能直接跑的最小实现。目标:在 PostgreSQL 里做一个带会话隔离的语义缓存,满足:

6.1 表设计

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE sem_cache (
    id            BIGSERIAL PRIMARY KEY,
    tenant_id     TEXT NOT NULL,
    session_id    TEXT NOT NULL,
    query_text    TEXT NOT NULL,
    query_vec     vector(768) NOT NULL,
    answer_text   TEXT NOT NULL,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT now(),
    expires_at    TIMESTAMPTZ NOT NULL DEFAULT now() + interval '7 days',
    version       BIGINT NOT NULL DEFAULT 1,
    tombstoned    BOOLEAN NOT NULL DEFAULT false
);

-- ANN index on vector; filter预过滤必须用 WHERE + b-tree 复合
CREATE INDEX ON sem_cache USING hnsw (query_vec vector_cosine_ops);
CREATE INDEX ON sem_cache (tenant_id, session_id, expires_at)
    WHERE tombstoned = false;

要点:

6.2 查询:带隔离的语义命中

WITH q AS (
    SELECT $1::vector(768) AS qv
)
SELECT id, answer_text, 1 - (query_vec <=> q.qv) AS similarity
FROM sem_cache, q
WHERE tenant_id  = $2
  AND session_id = $3
  AND tombstoned = false
  AND expires_at > now()
ORDER BY query_vec <=> q.qv
LIMIT 1;

应用层拿到后判断 similarity >= threshold(典型 0.92–0.95)才算命中,否则调 LLM 并写回。注意 WHERE 里的 tenant_idsession_id 条件必须放在索引里,否则 HNSW 先召回 top-k 再过滤可能因为被 tenant 过滤后为空而漏掉结果。pgvector 0.7+ 的 iterative scan 对这个场景友好。

6.3 写入:保证 read-your-writes

-- 在同一个会话同一个连接里立刻可见,无需额外同步。
INSERT INTO sem_cache (tenant_id, session_id, query_text, query_vec, answer_text)
VALUES ($1, $2, $3, $4, $5);

关键约束:同一个 session_id 的所有请求必须路由到同一主库连接。在 PgBouncer 前面做 session affinity,用 session_id 的 hash 做一致性哈希,避免跨副本 lag 导致 “刚写完读不到” 的现象。

6.4 触发器:自动维护 TTL 与 tombstone 逻辑

CREATE OR REPLACE FUNCTION sem_cache_update_version()
RETURNS trigger AS $$
BEGIN
    NEW.version := OLD.version + 1;
    NEW.expires_at := now() + interval '7 days';
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER sem_cache_version
BEFORE UPDATE ON sem_cache
FOR EACH ROW
EXECUTE FUNCTION sem_cache_update_version();

当 agent 产生”更正”信号(比如用户说”我之前说错了”),应用层走 UPDATE sem_cache SET answer_text = $new WHERE id = $old,触发器自动 bump version、刷新 TTL。如果是遗忘指令,则 UPDATE ... SET tombstoned = true不物理删除,保留给审计和回放。

6.5 后台清理

-- 每天一次,物理删除过期且已 tombstone 的行。
DELETE FROM sem_cache
WHERE tombstoned = true
  AND expires_at < now() - interval '30 days';

过期行即使没 tombstone 也可以保留一段时间,只靠 expires_at 过滤不回给用户。物理删除放到冷窗口,避免 HNSW 索引重建引起抖动。

6.6 一致性等级总结

上述设计给出的保证(从强到弱):

场景 保证 实现手段
同会话读自己写的 read-your-writes session affinity 到主库
跨会话同用户 因果一致(读主) tenant_id + user_id 作为 partition key
跨租户 严格隔离 WHERE tenant_id = $ 强制谓词 + RLS 兜底
跨副本只读查询 最终一致 容忍 lag,必要时带 max_staleness 参数

这四档映射直接对应分布式系统教科书里的 linearizability / causal / session / eventual。2026 年没有什么新东西,只是换了场景。

6.7 真实生产里还要注意什么

6.8 真实生产里还要注意什么

6.9 运行时剖析

在一个千万级记忆条目的 pgvector 生产环境里,一条查询的典型时间构成:

 0 ─ 2 ms   客户端 -> PgBouncer -> Postgres 建连 / 复用
 2 ─ 5 ms   WHERE tenant_id / session_id / expires_at 过滤走 b-tree
 5 ─ 12 ms  HNSW ANN top-k 召回
12 ─ 15 ms  应用层阈值判断 / 返回

LLM 调用通常 300–2000 ms。如果语义缓存命中率 30%,整体延迟节省 25% 以上,这是语义缓存在生产里真正的卖点。但这个结果完全取决于前面的隔离和阈值是否做对,否则命中率再高也没意义。

6.10 一个常被忽视的场景:跨会话 “学习”

有时产品希望”agent 从所有用户的交互里学习”——比如发现大家都在问”发票怎么开”,把这条沉淀成公司级 FAQ。这个需求和隔离要求是直接冲突的,必须分两层处理:

这种设计直接映射到差分隐私(下一篇 20 号会单独展开)。对本篇而言要记住的是:跨会话学习 ≠ 跨会话共享记忆

6.11 与仓库其他文章的互链


七、把记忆架构当成一个小型数据库系统来设计

最后一节拉远一点视角:不要把”LLM 记忆”当成一个独立新问题,它其实是把传统数据库里 session、cache、audit 三件事组合起来的新形态。

7.1 记忆即 session

传统 OLTP 的 session 是”一个 TCP 连接绑一批事务”。LLM agent 的 session 是”一个用户 × 一个 agent × 一段时间”。两者共享相同的关键需求:

这决定了 agent memory 的 session 管理应该复用数据库的 session 管理,而不是另起一套。例如在 PostgreSQL 里可以用 SET LOCAL app.current_session_id = '...',把 session id 绑到 transaction 内,后续 trigger、RLS policy 都能读到。

7.2 记忆即缓存

GPTCache 一节讨论过”语义缓存”。更一般的说法是:LLM 的每一次输出都可以被看成一个带语义键的缓存项。这层抽象让我们能直接搬缓存系统的成熟做法:

Single-flight 在 Go、Rust 里都有成熟库,跟 LLM 记忆的结合几乎是粘合代码。跳过这一步会在流量尖峰时被 LLM 账单教育。

7.3 记忆即审计

合规视角下,LLM 的每一次生成都是一条审计事件。这与数据库的 WAL 非常像:

把 audit 存在独立的 append-only 表(inserts onlyno updatesno deletes),再给它开单独的只读访问权,和数据库的 WAL 管理如出一辙。这样在事后追查、合规审查时,能用熟悉的数据库工具(pgBadgerpg_wal 分析工具)直接工作。

7.4 开放问题:跨模型的记忆兼容

到 2026 年仍没解决的一个开放问题是:embedding 空间不兼容。换一个 embedding 模型(比如从 OpenAI text-embedding-3 换到 BGE-M3),所有历史向量失效,必须重写入。这对已经存了几 TB 语义缓存的团队极其痛苦。

当前的折中方案:

这个问题短期内没有通解。把 embedding 模型换代看作一次全量重写,是比较务实的心态。

7.5 小结

“数据库作为 LLM 记忆体”表面上是一个新命题,往里看会发现所有经典问题都回来了:一致性、隔离、审计、版本、GC。过去四十年数据库社区攒下的工程智慧并没有被 LLM 冲走,反而换了一副外壳继续发挥作用。

这也是为什么这个系列从第 3 篇开始花五篇篇幅讨论 AI 原生数据库——AI 原生的 “新” 实际上是 “旧问题在新场景下的重组”。看透这一点,工程决策就会稳很多。

八、RAG × Agent Memory 的产品形态

本文前半把 RAG 和 agent memory 分开讲。产品落地时两者必须协作,这里补充一个完整的产品形态参考。

8.1 三层知识栈

一个成熟的 LLM 应用的知识栈往往长这样:

┌─────────────────────────────────────────────┐
│ Long-term Knowledge (RAG)                    │ 静态 / 准静态文档、代码
│  - 文件入库:chunk + embed + index           │
│  - 查询:topk ANN + rerank                   │
│  - 更新:按源文件版本差异                     │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ User / Session Memory                        │ 本文焦点
│  - 写:会话过程中自动 write-back              │
│  - 读:会话开头 load, 每轮按需 recall          │
│  - 隔离:tenant / user / session 三把筛子     │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Short-term Context (prompt)                  │ 本轮 prompt
│  - system prompt + few-shot + current turn   │
│  - rotating window,by-token budget          │
└─────────────────────────────────────────────┘

三层的 一致性预算 完全不同:顶层是最终一致(文档两天后更新也没事),中层是会话级一致(当前对话不能互相矛盾),底层是线性化(本次请求内的顺序严格保证)。

8.2 跨层通信的陷阱

跨层通信时常见 bug:

8.3 产品化清单

把一个 “能用” 的 LLM 记忆产品化需要的东西(按优先级):

  1. tenant / user / session 三元组的严格隔离与 RLS。
  2. 每条记忆 append-only + 版本化 tombstone。
  3. embedding 模型的版本字段,所有检索都带过滤。
  4. TTL + 后台回收 job。
  5. 管理后台:搜索、导出、删除(GDPR 合规)。
  6. 观测:命中率、命中相似度分布、跨 session 污染告警。
  7. A/B 框架:阈值与 prompt 的 A/B。

缺了其中任何一条,你都可能在线上吃到教训。这个清单本质上就是把数据库运维那一套 “ACID + audit + capacity + backup” 搬到 LLM 记忆层。认识到这一点,就不会再把 LLM 记忆当成一个”新问题”。

九、关于”遗忘”的设计

一个容易被忽视但在合规语境下极重要的问题:agent memory 的遗忘机制

9.1 GDPR / 个人信息保护法的要求

不同法域的表述不同,核心要求一致:数据主体有权要求删除自己的数据。在 LLM agent 场景这意味着:

9.2 软删 vs 硬删

“tombstone + 30 天后物理删” 是个常见折中。软删保留审计能力,硬删满足合规。实现上要注意:

9.3 选择性遗忘

比整体删除更麻烦的是”记住 A 不记得 B”。比如用户希望 agent 记得自己的偏好但不记得某次失败对话。这在产品上需要:

2026 年这方面还没有业内标准,属于产品和合规共同发展的领域。但提前留好 category 字段几乎零成本,后面需要时能省下重构工作量。

十、读者扩展阅读建议

如果你想深入本文涉及的每条线,这里给一个阅读建议:

这几条路径有些偏工程、有些偏合规,拼在一起覆盖了本篇的全部侧面。读完之后如果你只记得一句话,希望是:“LLM 记忆是一个被重新命名的数据库问题,不是一个新问题。” 带着这句话再去看后续所有 agent memory / LLM 记忆的新工作,你会更快辨别哪些是真创新、哪些是把 1990 年代的 session management 换了个名字重新卖一遍。

参考文献

  1. F. Bang, “GPTCache: An Open-Source Semantic Cache for LLM Applications”, NLP-OSS @ EMNLP 2023, https://aclanthology.org/2023.nlposs-1.24/.

  2. C. Packer et al., “MemGPT: Towards LLMs as Operating Systems”, arXiv:2310.08560, 2023, https://arxiv.org/abs/2310.08560.

  3. P. Lewis et al., “Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks”, NeurIPS 2020, https://arxiv.org/abs/2005.11401. RAG 的原始论文。

  4. N. F. Liu et al., “Lost in the Middle: How Language Models Use Long Contexts”, TACL 2024, https://arxiv.org/abs/2307.03172. 长 context 注意力衰减实证。

  5. M. Herlihy and J. M. Wing, “Linearizability: A Correctness Condition for Concurrent Objects”, TOPLAS 1990, https://dl.acm.org/doi/10.1145/78969.78972. 一致性模型经典论文。

  6. P. Bailis et al., “Highly Available Transactions: Virtues and Limitations”, VLDB 2014, https://www.vldb.org/pvldb/vol7/p181-bailis.pdf. 会话级 / 因果一致性的系统讨论。

  7. zilliztech/GPTCache, GitHub, https://github.com/zilliztech/GPTCache.

  8. cpacker/MemGPT, GitHub, https://github.com/cpacker/MemGPT.

  9. pgvector/pgvector, GitHub, https://github.com/pgvector/pgvector. PostgreSQL 向量扩展。

  10. PostgreSQL Row-Level Security 官方文档, https://www.postgresql.org/docs/current/ddl-rowsecurity.html.


上一篇: Text-to-SQL 与 Agentic Query:DIN-SQL、C3、DAIL-SQL 工程复盘 下一篇: 向量索引深度解读:HNSW、DiskANN、SPANN 对比

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-04-23 · database

【数据库研究前沿】GraphRAG:图增强检索的理论与工程

系统梳理 Microsoft GraphRAG(2024)的动机、算法与工程实现:多跳问答为什么让向量 RAG 失效、图作为 evidence path 的优势、社区检测与报告生成、Neo4j / NebulaGraph / KuzuDB 的落地差异,以及一个 NetworkX 最小实现。


By .