AI Agent 长期记忆与 PostgreSQL
Agent 记忆层选型:专用框架、向量库,还是用 PostgreSQL(pgvector + jsonb + 全文检索 + SQL/PGQ)做记忆底座
对语言模型的每次调用都是无状态的:模型不会回写任何东西,它能“记住”的只有 prompt 里的内容。一旦应用需要知道用户是谁、上周的偏好是什么、哪些事实已经变化,这份状态就必须由应用自己持有。这就是“Agent 记忆”在工程上的含义——一个写入路径由 LLM 辅助完成的数据库问题,而不是模型功能。
记忆不等于 RAG
RAG 和 Agent 记忆经常被混为一谈,因为两者都以“把相关文本检索进 prompt”结束。区别在于写入路径:
| RAG | Agent 记忆 | |
|---|---|---|
| 内容 | 外部语料(文档、工单、代码) | 交互中产生的事实、偏好与经历 |
| 写入路径 | 批量摄取,可重放,幂等 | 对话过程中的在线写入,常由模型抽取 |
| 更新方式 | 重新摄取新版本文档 | 对单条事实进行更正、取代与遗忘 |
| 典型查询 | “找与 X 相关的段落” | “我们当前对这个用户了解什么” |
| 典型故障 | 切块过期或无权限 | 错误事实以与正确事实相同的权威写入 |
因此记忆存储必须支持定向的 UPDATE 与 DELETE、按时间的有效期和冲突处理,而不只是最近邻搜索。把对话日志建成只读向量索引,是对聊天记录做 RAG,不是记忆。
记忆层的三种形态
- 专用记忆框架——SDK 与服务(Mem0、Cognee 等),在
add/searchAPI 背后接管抽取、存储与检索。原型最快,但 schema 与检索策略留在框架内部。 - 只用向量库——embedding 加元数据过滤。简单,但用户画像、实体间关系、精确匹配查询都要在别处重建。
- 直接用 PostgreSQL——一个系统同时承载 embedding(pgvector)、结构化画像(
jsonb)、关键词检索(全文检索)、实体关系(普通表,或 PostgreSQL 19 的 SQL/PGQ 属性图),外加事务与行级安全。写入策略留在你自己的代码和 SQL 里,而不是框架里。
三者并不互斥:第一类框架通常会把数据持久化到后两类存储上。真正的决策是“schema 的权威放在哪里、写入策略由谁控制”。
用 PostgreSQL 做记忆底座
一个可用的记忆 schema 把事实与它的 embedding 分开存放,并用显式的历史链代替原地覆盖:
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE agent_memory (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
tenant_id bigint NOT NULL,
user_id text NOT NULL,
kind text NOT NULL CHECK (kind IN ('profile', 'preference', 'episode', 'fact')),
content text NOT NULL,
attributes jsonb NOT NULL DEFAULT '{}',
embedding vector(1536),
search_vector tsvector GENERATED ALWAYS AS
(to_tsvector('simple', content)) STORED,
valid_from timestamptz NOT NULL DEFAULT now(),
expires_at timestamptz,
superseded_by bigint REFERENCES agent_memory(id),
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX ON agent_memory USING hnsw (embedding vector_cosine_ops);
CREATE INDEX ON agent_memory USING gin (search_vector);- pgvector 把 embedding 放在它描述的事实旁边;索引选择与带过滤条件的扫描行为遵循 RAG 管道和安装 pgvector中的同一套规则。
jsonb承载画像的结构化部分(时区、语言、套餐档位),这些字段必须能逐字段过滤和更新,而不是每次变更都重新 embedding。- 全文检索覆盖 embedding 处理不好的精确名字、ID 与错误串;两路候选集合并后融合,与混合 RAG 检索完全一致。
- 实体关系就是普通表:
entity加一张以PRIMARY KEY (src, dst, relation)约束的边表。在 PostgreSQL 19 上还可以把它们声明为属性图并用GRAPH_TABLE查询,见 SQL/PGQ 图查询;更早的版本用 join 或WITH RECURSIVE查询同样的表。
检索是一条把租户与权限过滤推进数据库的 SQL,模式见 RAG 管道。这里没有任何东西需要一台“记忆专用服务器”。
候选框架对比
以下能力声明于 2026-08 对照官方仓库与文档核对。厂商发布的基准分数属于厂商自报数据,本站未独立验证。
| Mem0 | Cognee | |
|---|---|---|
| 自我定位 | “记忆层” SDK、自托管 server 与托管云 | “AI 记忆平台”,从摄取的数据构建知识图谱 |
| 记忆模型 | 按 user、session、agent 三个层级组织的记忆 | 文档 → 图中的实体/关系加 embedding;remember / recall / forget API |
| 存储后端 | 可插拔向量库,支持列表包含 PGVector | 可插拔的关系、向量与图后端;文档给出 PostgreSQL + pgvector 配置 |
| 与 PostgreSQL 的关系 | PostgreSQL 是多种可选向量存储之一 | 其 README 明确标注 Postgres 图存储目前是 demo 特性,生产图负载建议使用图原生后端或其付费产品 |
| 抽取策略 | 基于 LLM 的事实抽取与更新决策在框架内完成 | 基于 LLM 的流水线(cognify)在框架内构建图谱 |
两个框架都可以把部分存储放在 PostgreSQL 之上,所以“框架 vs PostgreSQL”通常是“框架的写入策略跑在 PostgreSQL 上”与“你自己的写入策略跑在 PostgreSQL 上”之间的选择,而不是两个不同的数据库。
观点:框架是暂时的中间层
冯若航(vonng)在一篇 2026 年的文章中主张:记忆框架是被模型和数据库两头挤压的中间件——抽取策略会迁入模型(或一个简短的 skill 文件),存储会回到 PostgreSQL,持久的护城河在数据层。这是一位从业者的个人观点,不是可核实的事实;把它当作一个假设,对照你自己的写入路径复杂度去检验,再决定采用还是放弃框架。
生产关注点
记忆写入的一致性
最危险的写入是模型抽取的那一条。要给它加约束:记忆走固定 schema 和 CHECK 约束;执行抽取的模型使用不能触碰业务表的受限角色(安全 SQL 护栏);更正操作是 INSERT 加 superseded_by 链接,而不是原地改写,这样“Agent 回答时我们相信什么”始终可审计。如果某条记忆派生自一笔业务事务,要么两者在同一事务中写入,要么显式记录来源版本。
遗忘与 TTL
没有过期机制的记忆会积累成噪声,再被检索放大。领域允许时给事实加 expires_at,定期清理过期行;用户主动发起的删除要执行硬 DELETE(连同 embedding 行),而不是打标记。pgvector 索引不会让已删除的行从备份里消失——PITR 保留期要与删除策略对齐。
用 RLS 做多租户隔离
记忆是带 prompt 注入爆炸半径的用户数据:在某个租户被投毒写入的记忆,绝不能被另一个租户检索到。隔离必须做在数据库里,而不是检索代码里:
ALTER TABLE agent_memory ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON agent_memory
USING (tenant_id = current_setting('app.tenant_id')::bigint);每个请求从已认证身份设置 app.tenant_id。这样即使 Agent 或 MCP 工具发出你未曾手写的查询,隔离保证依然成立。
评估记忆质量
检索召回率是必要条件而非充分条件:记忆层还可能因为抽取了错误事实、保留了互相矛盾的条目、返回了过期状态而失败。保留一组带版本的对话轨迹,标注它们应产生的记忆和检索应返回的答案;把抽取准确率与检索召回率分开度量;每次改 prompt、换模型、动 schema 都重跑。评测框架与数据库 Agent 评估相同;框架发布的基准是厂商自报数字,不能替代用你自己流量构建的测试集。
AI prompt:起草记忆 schema
帮我在 PostgreSQL 19 上设计一个 Agent 长期记忆 schema。 1. 我的 Agent 需要记住什么:(如用户偏好、历史决策、未结问题) 2. 规模:(用户数、每用户记忆条数、每天写入量) 3. 请做到: - 事实(文本 + jsonb 属性)与 embedding(pgvector)、实体关系(边表)分表 - 更正用 INSERT + superseded_by 链接,不做原地 UPDATE - 需要自动遗忘的地方加 expires_at - 包含 tenant_id 隔离的 RLS 策略 - 写出混合检索查询(租户过滤 + 全文 + 向量候选) 4. 指出哪些内容应该留在业务表而不是记忆里。
相关页面
- RAG 管道——读取路径复用的混合检索、索引与权限过滤
- 安装 pgvector——向量扩展的安装与验证
- 上下文契约——模型允许看到什么,以及如何表达“上下文不足”
- 安全 SQL 护栏——模型发起写入的角色与语句限制
- 数据库 Agent 评估——记忆质量的评测框架
- SQL/PGQ 图查询——PostgreSQL 19 上的实体关系查询
Last updated on