关于 amu-pgvector
amu-pgvector 是面向 Agent 系统的 PostgreSQL 与 pgvector 记忆存储,依据缓存结果所用的敏感列控制访问。行级安全策略适用于 SQL、库集成和其 MCP 服务。
主要功能
- 01按数据来源实施访问控制
- 02PostgreSQL 行级安全
- 03语义记忆搜索
- 04检查指标定义冲突
- 05提供 SQL、LangChain 和 MCP 接口
适用场景
- 01在不同部门间共享缓存结果
- 02阻止复用源自受限列的结果
- 03按数据库角色权限搜索记忆
MCP 相关
可选 MCP 服务将 `amu_search`、`amu_record` 和 `amu_check_conflict` 暴露为工具。这些操作受同一 PostgreSQL 行级安全策略约束。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx amu-pgvectorAMU_PGVECTOR_DSN密钥Postgres DSN for the role this server runs as. Results are gated by row-level security under this exact role -- use an amu_writer-member role for amu_record/amu_check_conflict, or an amu_agent_base-member role for read-only amu_search.AMU_PGVECTOR_EMBEDDING_DIMEmbedding vector dimension, used only by the built-in deterministic fallback embedder when sentence-transformers (the amu-pgvector[st] extra) isn't installed. Must match the dimension sql/amu_pgvector.sql was installed with. Default: 1536.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
3收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| k | integer | 否 | |
| query | string | 是 | |
| metric_name | any | 否 |
详细介绍
amu-pgvector
基于 PostgreSQL + pgvector 实现的具备谱系感知能力的记忆治理 (Sangaraju & Vissa,IEEE Access,10.1109/ACCESS.2026.3730363)。
问题
假设 Finance 为一个客户细分群体计算 avg(income),并缓存结果,这样下一个询问相同问题的 Agent 就不必重新计算。之后,Marketing Agent 提出一个语义相似的问题——“各细分群体的客户平均收入是多少?”——而一个仅按指标名称或内容标签进行门控的朴素共享记忆,会返回 Finance 缓存的结果。Marketing 从未获准查看 income。结果本身看起来并不像收入——它只是一个数字——但它是根据 Marketing 无权访问的列推导出来的,而仅按指标名称或内容进行匹配无法发现这一点。本项目要解决的正是这种泄漏:根据结果的推导方式来门控复用,而不是根据结果看起来是什么。
60 秒快速入门
git clone https://github.com/sangaraju1988/amu-pgvector.git
cd amu-pgvector
docker compose up -d
psql -h localhost -p 5433 -U amu_owner -d amu_dev -f sql/amu_pgvector.sql
# password: amu_owner_password
uv sync --all-packages --all-extras # or: pip install amu-pgvector
from amu_pgvector import AMUStore
from amu_pgvector.embeddings import fake_embedder
DSN = "postgresql://amu_owner:amu_owner_password@localhost:5433/amu_dev"
embed = fake_embedder(dim=1536) # swap for a real embedding model in production
admin = AMUStore(DSN)
admin.register_sensitive_column("income")
admin.grant_department_permission("Finance", "income")
admin.create_agent_role("finance_agent", "Finance", "finance_pw")
admin.create_agent_role("marketing_agent", "Marketing", "marketing_pw")
admin.record(
"SELECT avg(income) FROM customers",
{"avg": 82000},
metric_name="avg_income",
description="average customer income",
owner_department="Finance",
embed_fn=embed,
)
finance_dsn = "postgresql://finance_agent:finance_pw@localhost:5433/amu_dev"
marketing_dsn = "postgresql://marketing_agent:marketing_pw@localhost:5433/amu_dev"
AMUStore(finance_dsn).search("average customer income", k=5, embed_fn=embed)
# -> [SearchResult(metric_name='avg_income', ...)]
AMUStore(marketing_dsn).search("average customer income", k=5, embed_fn=embed)
# -> [] -- Marketing was never granted `income`, so Postgres itself
# never returns the row, regardless of how the query is asked.
上面的每一行在写入本文档前,都已针对这个确切的仓库运行过(从头开始安装的实际情况请参见 docs/design.md)。amu_owner/amu_owner_password 是 docker-compose 的默认值——除本地开发外,请务必更改。
门控机制
amu.memory_units 是一个启用了 FORCE ROW LEVEL SECURITY 的普通 Postgres 表。每次写入都会经过一个触发器,由它提取实际生成缓存结果的 SQL 的谱系(通过
amu-governance 的
sql_lineage 模块提取——而不是由 Agent 自行报告),将谱系扩展至已注册的物化视图/派生表边,并计算 S(a):该谱系实际触及的敏感列集合。SELECT 策略会针对每条查询强制执行 S(a) ⊆ P(d)——仅当 S(a) 中的每一列都属于请求角色获准访问的集合 P(d) 时,该行才可见——对所有客户端发出的每次表查询都如此:原始 SQL、amu.search()、Python 客户端、LangChain 集成和 MCP 服务都遵循同一策略,因为策略属于该表,而不是任何特定客户端的过滤器。
sequenceDiagram
participant Writer as amu_writer role<br/>(trusted interception layer)
participant PG as Postgres: amu.memory_units<br/>(FORCE ROW LEVEL SECURITY)
participant Trigger as BEFORE INSERT trigger
participant Finance as finance_agent role
participant Marketing as marketing_agent role
Writer->>PG: INSERT ... lineage = {"steps":[{"table":"customers","columns_used":["income"]}]}
PG->>Trigger: compute lineage_columns, S(a), lineage_status
Trigger-->>PG: sensitive_columns = {income}, resolved
Finance->>PG: SELECT ... (session_user = finance_agent)
PG->>PG: S(a)={income} subset P(Finance)={income,...}? yes
PG-->>Finance: row returned
Marketing->>PG: SELECT ... (session_user = marketing_agent)
PG->>PG: S(a)={income} subset P(Marketing)={...}? no
PG-->>Marketing: row not returned
请参阅 docs/design.md,了解论文中的每个概念如何对应到具体的 SQL 对象;另请参阅 docs/sql-reference.md,获取所有表、函数、角色和策略的完整参考。
安全模型与限制
**保护范围:**防止跨部门泄漏缓存结果的推导列(核心保障,由 RLS 强制执行);防止指标定义冲突未被察觉(amu.check_conflict());防止在 AMU 已存在后将某列重新分类为敏感列(触发器会重新计算受影响的行,无需重写);防止谱系闭包在长链或循环推导链上悄然截断(采用默认拒绝策略——将 AMU 标记为未解析并设为不可见,而不是返回仅部分追踪的结果)。
**明确不在范围内:**谎报谱系的写入方(按设计,SQL 门控会信任 amu_writer 的输入);通过组合多个单独获准的 AMU 进行推断;Postgres 超级用户(始终绕过 RLS);时序侧信道;“便捷模式”身份选项(默认关闭),其安全性仅取决于连接池连接上可信应用代码与受 Agent 影响的代码之间的边界。
完整说明:docs/threat-model.md。
基准测试
以下所有数字均直接摘自
results/SUMMARY.md,该文件由
benchmarks/generate_summary.py 根据已提交的 results/<name>/<timestamp>/
运行结果生成(每次运行的 manifest.json 中记录了 git SHA、Postgres/pgvector 版本、硬件、随机种子和参数)。你可以自行重新运行基准测试脚本来复现或质疑这些结果;这里没有任何估算值。
泄漏率(针对 600 个合成 AMU 的 2000 次请求,涉及 Finance/Marketing/Support):
| 条件 | 已处理 | 跨部门泄漏 | 泄漏率 |
|---|---|---|---|
| 朴素方式(按内容门控,不检查溯源关系) | 2000 | 1010 | 50.5% |
| amu-pgvector(RLS 门控) | 990 | 0 | 0.0% |
延迟(k=10 时的 p50/p95;RLS 和 hnsw.iterative_scan 分别启用/关闭,每行使用相同角色、查询和数据):
| n | RLS | iterative_scan | p50 (ms) | p95 (ms) |
|---|---|---|---|---|
| 10,000 | 启用 | 启用(amu.search() 默认值) | 66.8 | 70.2 |
| 10,000 | 启用 | 关闭 | 81.9 | 88.2 |
| 10,000 | 关闭 | 启用 | 19.5 | 21.8 |
| 10,000 | 关闭 | 关闭 | 49.2 | 52.3 |
| 100,000 | 启用 | 启用(amu.search() 默认值) | 712.9 | 851.2 |
| 100,000 | 启用 | 关闭 | 43.4 | 65.7 |
| 100,000 | 关闭 | 启用 | 376.8 | 418.5 |
| 100,000 | 关闭 | 关闭 | 46.6 | 70.9 |
如实解读:hnsw.iterative_scan=relaxed_order(amu.search() 默认使用的设置,可确保即使大多数行被隐藏,筛选后的结果仍能达到 k 个)在大规模下会带来明显延迟——在本次运行中,100k 行时的速度约比关闭 iterative 慢 16 倍。这是下文召回率保证所付出的代价;如果可见数据占比始终较高,你或许更适合不启用它。本次未尝试 1M 行规模:仅构建 100k HNSW 索引,在本次运行使用的机器上就耗时约 7 分钟(macOS 上的 Docker Desktop,与其他无关工作负载共用主机)——我们如实记录此结果,而不进行外推。
筛选后召回率(针对同一角色实际可见的行,以精确暴力搜索为基准,对门控 HNSW 搜索计算 recall@10,n=20,000):
| 可见比例 | recall@10(平均) | recall@10(最小) |
|---|---|---|
| 50% | 100.0% | 100.0% |
| 10% | 100.0% | 100.0% |
| 1% | 100.0% | 100.0% |
集成
- 纯 SQL ——
sql/amu_pgvector.sql是最重要的产物:具备幂等性,可由普通数据库所有者(无需超级用户权限)安装到托管 Postgres 上,除vector外无需其他 C 扩展。在 Supabase 和 Neon 上的运行方式完全相同(参见submissions/supabase-neon-guide.md,其中提供了涵盖两者的从零开始教程)。 - LangChain ——
langchain-amu提供AMUVectorStore和AMURetriever。每次读取都使用存储自身的 Postgres 角色,因此 RLS 对 LangChain 的门控方式与对原始 SQL 相同。参见packages/langchain-amu/。 - MCP ——
pip install amu-pgvector[mcp]会添加一个amu-pgvector-mcp控制台脚本,将amu_search、amu_record和amu_check_conflict作为工具提供,并采用相同的门控方式。参见packages/amu-pgvector/src/amu_pgvector/mcp_server.py。
引用
@article{sangaraju2026lineage,
title = {Lineage-Aware Memory Governance: A Derivation-Gated Framework
for Privacy-Preserving Column-Level Access Control in
Enterprise AI Agents},
author = {Sangaraju, Venkata and Vissa, Sudhir},
journal = {IEEE Access},
year = {2026},
doi = {10.1109/ACCESS.2026.3730363}
}
另请参阅 CITATION.cff,以便直接引用此软件。
许可证
MIT。参见 LICENSE。
相关内容
- 论文:Sangaraju 和 Vissa,IEEE Access,DOI 10.1109/ACCESS.2026.3730363
- 参考库:amu-governance(PyPI)
docs/design.md—— 将论文概念映射到 SQL 对象,并介绍构建过程中发现的所有实际问题docs/threat-model.md—— 说明受保护和未受保护的内容docs/sql-reference.md—— 介绍每张表、每个函数、角色和策略
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。