把智能体的数据语义与权限放进 Postgres
教程在 EDB Postgres AI 内构建受治理的语义层,将业务含义、表关联路径及访问控制统一放入数据库。运行于 Bedrock AgentCore 的 Strands 智能体查询该层,由 GRANT 和行级安全限制可读数据。
AI 深度解读
让 AI 查数据库,最难的往往不是写出能执行的 SQL,而是理解字段背后的业务口径。订单金额被当成单价,查询照样成功,答案却可能错出一个数量级。AWS 这篇文章给出的方案,是把业务解释、关联路径和访问权限一起放回 Postgres。
作者用 EDB Postgres AI 的 AIDB 扩展构建语义层,再通过 Amazon Bedrock AgentCore 接入 Agent。案例展示了金额纠错和列权限拦截,但距离证明复杂业务下的整体准确率,还有一段距离。
SQL 能跑通,为什么答案还是错的
案例使用 Stardog C360 Knowledge Kit,在 c360 schema 中加载四张表,再建立一个派生视图。客户关联地址、购买记录和商品,结构并不复杂,却已经足够暴露三个问题。
第一,客户所在州不在 customers 中,而在 locations.state,需要沿 customers.location 外键查过去。第二,purchases.price 记录整笔订单金额,并非商品单价。第三,「大客户」是业务定义,不能靠模型临场猜测。
作者展示的错误很直观:缺少金额解释时,Agent 将 price 乘以 quantity,把消费最高客户 Carolyn Inworth 的金额算成约 502,529 美元;正确结果是 27,991.66 美元。
SQL 执行成功,只能证明数据库接受了查询,不能证明查询理解了业务。
这里的语义层,就是把「这个字段到底表示什么」「这些表怎么关联」「这个业务词如何计算」变成 Agent 能检索的上下文。它不负责替模型思考,而是减少模型需要猜的部分。
为什么业务口径要写进数据库
AIDB 的语义知识库叫 SemKB。它索引的是 schema 元数据,不是业务数据行:表、视图、列的定义及其 COMMENT ON 文本被嵌入向量库,外键则被整理成关联路径。
下面这段 SQL 同时解决金额歧义和「大客户」口径统一的问题:
COMMENT ON COLUMN c360.purchases.price IS
'Total amount the customer paid for the entire order, in US dollars. Not the unit price.';
COMMENT ON COLUMN c360.purchases.cid IS
'Customer who placed the order. Joins to customers.cid.';
COMMENT ON COLUMN c360.customers.location IS
'Home address of the customer. Joins to locations.id. State is in locations.state.';
COMMENT ON COLUMN c360.customers.ssn IS
'US Social Security number. Sensitive, column-level grant required.';
CREATE VIEW c360.big_spender AS
SELECT c.cid, c.full_name, l.state,
count(*) AS large_orders,
max(pu.price) AS largest_order
FROM c360.purchases pu
JOIN c360.customers c ON c.cid = pu.cid
JOIN c360.locations l ON l.id = c.location
WHERE pu.price > 250
GROUP BY c.cid, c.full_name, l.state;
COMMENT ON VIEW c360.big_spender IS
'Big spenders. A big spender is a customer with at least one order over 250 US dollars. '
'Use this view for any question about big spenders.';
关键是 WHERE pu.price > 250:这里的大客户是「至少有一笔订单超过 250 美元」,不是累计消费超过某个金额。按州统计时,Florida 和 Texas 各有 46 人,California 有 42 人,District of Columbia 有 24 人,New York 有 23 人。
如果以后改成累计消费超过 5,000 美元,作者建议用 CREATE OR REPLACE VIEW 修改统一定义,待 SemKB 刷新后让 Agent 获取新口径。
接着创建知识库:
SELECT aidb.create_semantic_kb(
name => 'c360_kb',
model => 'bge-small-en-v1.5-f16',
schemas => ARRAY['c360'],
auto_processing => 'Live'
);
这里要盯住 auto_processing => 'Live'。它通过 Postgres event triggers 响应 schema 变化;Background 交给后台 worker 异步处理;Disabled 则等待显式调用 aidb.refresh_semantic_kb()。
示例使用 AMI 自带的本地 llama.cpp embedding 模型,类型为 llamacpp_embeddings,每个 SemKB 使用一个 embedding 模型。也可通过 aidb.create_model 注册 Amazon Titan Text Embeddings 等远程模型。
AMI 默认已有覆盖 public 的 semkb。新增 c360_kb 后,调用 aidb.semantic_kb_search 必须显式传入 kb_name,否则知识库选择会出问题。
对于反复出现的问题,还可以用 aidb.create_semantic_alias 注册带自然语言描述的只读 SELECT。示例别名 big_spenders_by_state 按州统计大客户,params => '[]' 表示不需要参数。这比每次重新生成同一种统计 SQL 更容易统一口径。
相同的 Agent,为什么能返回不同的数据
链路由三部分组成:Claude on Amazon Bedrock 负责规划与回答,SemKB 提供业务含义,AgentCore runtime 托管 Agent。示例用 Strands Agents 的 BedrockModel 和 MCPClient 连接它们,先调用 semantic_kb_search 并指定 kb_name => 'c360_kb',再调用 execute_sql。
用户通过 Amazon Cognito 获取 JWT,以 Bearer token 调用 AgentCore Gateway。Gateway 验证 JWT,并通过 Cedar policy 判断可调用的工具。出站访问时,AgentCore Identity 注入 Postgres 用户名和密码,作为 HTTP Basic authentication 凭据;Agent 代码不接触数据库密码。
AIDB 的 edb-endpoints 已支持 streamable HTTP MCP,经 Application Load Balancer(ALB)直接注册为 Gateway 的 MCP server target,因此这条链路不需要 AWS Lambda。
数据库侧要设置 edb.endpoints_mcp_enabled = on,将 aidb 加入 shared_preload_libraries 并重启。对外监听可设置 edb.endpoints_mcp_host = 0.0.0.0,默认 edb.endpoints_mcp_port 为 8765;非回环监听需要通过 edb.endpoints_mcp_tls_cert 和 edb.endpoints_mcp_tls_key 配置 TLS。
ALB 使用 HTTPS listener 和 ACM 证书,后端也走 HTTPS。文中说明 ALB 不验证后端证书链,因此开发测试可用自签名证书;生产建议使用 internal ALB 和 AgentCore Gateway VPC egress。
权限验证用了两个角色:mcp_agent_full 能读取全部列,mcp_agent_restricted 无权读取 customers.ssn。两者都需要 aidb_users 来列出 MCP 工具,并配置对应的 pg_hba.conf 密码认证。
询问五位客户的 Social Security number 时,完整角色返回数据;受限角色收到 permission denied for column ssn,MCP 原样转发错误,Agent 再说明无法读取。
真正阻止敏感数据被读取的,是 Postgres 权限,而不是提示词。
行级安全(RLS)同样通过各角色的 USING policy 生效。AIDB 自带的 purposes 则服务于 aidb.create_agent、aidb.agent_converse 这条数据库内 Agent 路径,不是本文外部 AgentCore 接入的权限机制。
审计也分两处:AgentCore 将工具调用、模型调用和 token 使用记录到 CloudWatch Transaction Search;数据库配置遥测后,AIDB 将 SQL 执行的 OpenTelemetry traces 写入 aidb_otel,可直接用 SQL 查询。
我的判断
这套方案最有价值的,是把业务口径和权限做成可维护、可执行的数据库资产。字段注释解释含义,视图固化口径,语义别名复用查询,GRANT 和 RLS 决定可见范围。比起把这些规则全部塞进 system prompt,职责更清楚。
但文章给出的准确率证据有限。金额纠错是具体案例,却没有多轮重复实验、成功率或延迟成本。原文一处将错误基线描述为「只有 SQL 执行工具」,另一处又强调模型、提示词和工具目录相同,对照条件没有交代完整。因此,「注释最能提高准确率」仍应视作作者经验,不能当成通用测评结论。
权限链路还有一个落地问题:文章展示了更换出站凭据后的不同结果,却没说清如何把大量终端用户的 Cognito 身份映射到数据库角色。接上 JWT 验证,不等于已经完成逐用户的数据授权。
相比固定查询 API,SemKB 加动态 SQL 更适合开放式探索;对固定报表,视图、参数化接口或 semantic alias 往往更容易验证。原文没有给这几种方式的对照数据。
业务增长后,作者提出用 PGAA 访问对象存储中的 Apache Iceberg、Delta Lake、Parquet,或用 foreign data wrappers 联邦查询外部关系库。但语义定义可沿用,不代表远程查询性能和权限配置会自动解决。提供的原文最后截断在 EC2 自托管部署部分,其他部署形态没有完整信息。
能拿来做什么
- 给 Node 数据服务或内部数据助手接入 AI 前,先补齐金额、时间、状态等易误解字段的数据库注释,并记录真实的主外键关系,再用固定业务问题检查生成的 SQL。
- 把「大客户」「有效订单」等反复使用的业务词固化成视图;高频查询进一步做成参数化接口或 semantic alias,减少每次生成 SQL 时重新解释口径。
- 验证 AI 查询权限时,用不同数据库角色执行同一个问题,检查返回列、行级过滤和错误信息。对于模型回答中的其他 PII 泄漏路径,再配合 Amazon Bedrock Guardrails 的过滤与脱敏能力。
- 上线前同时保留 Agent 调用记录和数据库执行记录,分别验证「选错了什么工具」与「实际执行了什么 SQL」,并补测复杂关联、口径变化和拒绝访问后的行为。