方案使用Denodo与Amazon Bedrock AgentCore,将Aurora、Redshift和本地PostgreSQL联邦整合为统一客户视图,供智能体通过VQL查询。身份传递及行列级访问控制均在语义层执行。
智能体式 AI 应用需要以受治理的方式访问实时企业数据。这些数据可能分布在业务系统、分析型数据仓库、SaaS 应用、其他云或本地环境中。在本系列的上一篇文章中,我们使用 Stardog 知识图谱,在 Amazon Aurora 和 Amazon Redshift 之上构建了 AWS 上的语义层。运行在 Amazon Bedrock AgentCore 上的 Strands 智能体负责查询该语义层。Amazon Bedrock AgentCore 是一个支持使用任意框架或模型、大规模构建、连接和优化智能体的平台。本文沿用相同的客户 360 模式,但采用另一种语义层实现,并扩展数据源的组成。
这里有两处变化。首先,语义层改用 Denodo Platform:这是一个 AI 数据层,能够提供动态上下文,并以零复制方式实时访问分布式企业数据。智能体通过 Denodo 的 SQL 方言 VQL 与其交互。其次,除 Amazon Aurora 和 Amazon Redshift 外,数据源还包括一个本地 PostgreSQL 数据库,因此联邦查询所要解决的问题不再局限于 Amazon Virtual Private Cloud(Amazon VPC)内部。
其余架构模式保持不变。Amazon Bedrock 上的基础模型负责规划和编写查询。Denodo MCP Server 通过 Model Context Protocol(MCP,模型上下文协议)向智能体提供受治理的视图。Amazon Bedrock AgentCore 托管智能体,处理入站身份验证,并管理智能体向 Denodo 出示的出站凭证。模型推理所依据的所有内容都位于语义层中,而非提示词中:包括连接关系、指标定义,以及适用于调用者的行和列过滤条件。
阅读本文后,你将了解:
我们假定你已经熟悉上一篇文章介绍的语义层架构:它是什么、有什么用途,以及为什么模型负责规划查询,却不负责维护连接关系。如果你对其中任何一点还不熟悉,上一篇文章已经做了介绍。
我们继续沿用上一篇文章中的客户 360 模式。上一篇文章使用的 Stardog C360 Knowledge Kit 为一家电商零售商建模,围绕两个用例展开:了解客户流失情况,以及找出适合自动加入奖励计划的客户。本文的数据模式保持不变。变化在于其中一张表的位置:rewards_account 位于本地 PostgreSQL 集群中,而不是与其他客户档案数据一起存放在 Amazon Aurora 中。
这种部署方式并非特例。企业数据源可能位于 AWS 之外:本地环境、CRM 之类的 SaaS 工具,或其他云中。无论是哪一种情况,语义层都必须能够访问相应数据源。在本演练中,我们使用本地 PostgreSQL 来代表来自第三方应用的数据。“扩展到其他数据源”一节将介绍,当数据源是 SaaS 工具、CRM 或大型机时,需要做哪些调整。该节还会介绍 Denodo 原生支持的其他数百种数据源。
共享标识符是 cid,它是一个普通整数,在 Aurora 的 customer 表中作为主键出现。它也出现在 Amazon Redshift 的 order 表和本地 rewards_account 表中,但在这两处都不是外键。在 Aurora 内部,customer.location 列是一个指向 address.id 的整数外键,客户档案正是通过它与地址记录连接起来。两个引擎之间不存在跨引擎外键,也没有 ETL 作业来建立这样的关联。要将客户与其购买记录及奖励计划加入情况关联起来并给出答案,就必须在查询时通过 cid 匹配记录。
这套架构可以回答的一个典型问题是:“按累计消费金额排名前 20 的客户中,哪些还没有加入奖励计划?”这对应 Stardog 套件中的自动加入奖励计划场景,需要结合 Aurora 中的客户档案数据、Amazon Redshift 中的累计消费金额,以及本地集群中的加入状态才能作答。
Denodo 在执行时规划联邦查询,决定哪些操作下推至 Aurora、哪些下推至 Amazon Redshift、从本地集群获取哪些数据,以及如何合并结果。数据不会在数据源之间迁移,语义层只需定义一次,即可供所有使用方复用。
Denodo 以数据虚拟化平台的形式实现语义层。Denodo Virtual DataPort(VDP)是其核心查询引擎:语义层对象存放于此,VQL 在此执行,访问策略也在此求值。Design Studio 是 VDP 基于浏览器的建模界面。本文建模的每个对象都在其中定义。
下文会反复涉及三种对象类型。
基础视图(base view)是源系统中的物理表、API 或文件与 VDP 中逻辑视图之间的映射。一张 Aurora 表对应一个基础视图。
派生视图(derived view)是针对一个或多个基础视图或其他派生视图执行的 VQL 查询。本文中的 customer_360 视图就是一个派生视图。
指标视图(metric view)将业务度量统一定义一次,例如 lifetime_customer_value,并允许其他派生视图引用它。指标视图将度量的定义与使用该度量的具体查询分离。
VQL 是 Denodo 的 SQL 方言。它以符合 ANSI 标准的 SQL 为基础,增加了一组 Denodo 专用结构,尤其是用于表示数据源的 DDL 结构,以及用于语义指标视图的语法。在智能体场景中,VQL 的具体语法由一项技能提供;大语言模型在使用 Denodo 工具时会使用该技能,以便正确使用 Denodo 语法。
全局安全策略(Global Security Policy,GSP)是一种运行时访问控制规则,适用于带有特定标签的视图或列。GSP 按调用者分别求值,从而在查询时强制实施行过滤和列掩码。
更完整的参考信息,请参阅 Denodo Platform 文档。
运行时包含两条流程。入站流程:客户端通过 Amazon Bedrock AgentCore Gateway 向智能体发送用户请求。Gateway 依据企业身份提供商(IdP)验证标识该用户的 JSON Web Token(JWT),然后将请求路由至 Amazon Bedrock AgentCore runtime,后者托管着 Strands 智能体进程。智能体调用 Amazon Bedrock 上的基础模型(本演练使用 Anthropic Claude Sonnet 4.6),以理解提示词并规划查询。
出站流程:AgentCore Gateway 同时充当智能体工具调用的出站代理。Denodo MCP Server 在 Gateway 上注册为一个 MCP 目标,因此,智能体为获取企业数据而发起的工具调用会经由 Gateway 路由至 MCP Server。在请求到达 Denodo 之前,AgentCore Identity 会执行 On-Behalf-Of 令牌交换,将用户的入站令牌转换为一个权限范围受限的访问令牌;该令牌代表同一用户,并以 Denodo 为受众。Denodo MCP Server 接受交换后的令牌作为 bearer 凭证,并通过 JDBC 将 VQL 请求转发至 Denodo Virtual DataPort(VDP)。VDP 独立验证令牌,将调用者映射到 Denodo 角色,应用访问策略,并规划针对 Amazon Aurora、Amazon Redshift 和本地 PostgreSQL 集群的联邦查询。
只有 VQL 请求会向下传递到 VDP,随后结果集向上返回。源数据不会在引擎之间迁移。Aurora、Amazon Redshift 和本地集群执行的都是由 VDP 联邦查询优化器改写生成的原生 SQL。后续章节将详细介绍身份传播与策略执行机制,其他章节还会介绍 MCP Server 注册和智能体部署步骤。
图 1:调用者、Amazon Bedrock AgentCore 各组件、Denodo MCP Server、Denodo Virtual DataPort 和三个数据源之间的入站身份验证路径与出站查询路径
Denodo 中的语义模型并不是一个单一产物。它由 VDP 中的一组基础视图、派生视图、指标视图和标签组成,共同向使用方提供具有业务含义的数据。本文所说的构建语义模型,就是创建其中的每个组成部分。
我们分三个阶段构建:首先,为每张源表创建基础视图;然后创建派生视图(customer_360),通过 cid 在客户粒度上联接基础视图;最后创建指标视图(lifetime_customer_value),定义可复用的消费金额聚合,供查询在需要时联接使用。
在实际操作中,这些建模工作通过 Denodo Design Studio 以可视化方式完成。你可以将 Aurora、Amazon Redshift 和本地 PostgreSQL 数据源拖到画布上,在它们之间绘制联接关系,并通过表单重命名字段或修改字段类型(例如,将 cust_ref 映射为 customer_id),无需手写 DDL。本文后面介绍的安全策略也在同一个 UI 中附加。
指标视图与引用它们的派生视图并列存在,定义一次即可复用。如果两个团队基于相同的基础数据构建了两个不同的客户级视图,这两个视图都会提供相同的指标定义。
每张源表都会在 VDP 中成为一个基础视图。对于 Aurora 中的 customer 表,这意味着在 Design Studio 中使用专用连接器接入 Aurora,指定相应的 schema,再由 VDP 自动探查列信息。Design Studio 会负责这一探查过程。生成的基础视图在物理列与对应的 VDP 列之间建立一一映射,不会转换源数据。
创建过程中还需要完成两项配置:
用于治理的列标签。在 customer 表的基础视图中,为 ssn 添加 pii_sensitive 标签。在 credit_card 表的基础视图中,为 card_num 添加相同的标签。“受治理的访问”一节定义的全局安全策略正是通过这些标签绑定到相应列的。
主键和联接字段。在 aurora_customer 中,将 cid 标记为主键;在 redshift_order 和 postgres_rewards_account 中,将 cid 标记为联接字段。如果源元数据中包含主键信息,Design Studio 会据此推断主键。否则,只需在基础视图定义中设置一次。
对前面介绍的源表重复这些操作,最终得到六个基础视图:基于 Amazon Aurora 的 aurora_customer、aurora_address 和 aurora_credit_card;基于 Amazon Redshift 的 redshift_order 和 redshift_product;以及基于本地 PostgreSQL 的 postgres_rewards_account。
Design Studio 还支持通过 Denodo Assistant 使用自然语言创建视图。开发者可以用普通英语描述一个视图(例如,“通过 cid 将 Aurora 中的客户资料与 Amazon Redshift 中的订单总额联接起来”),获得一份候选 VQL 定义,然后在同一个画布中审查和完善,再进行保存。完善过程可以迭代进行:通过后续提示词调整筛选条件、联接或字段映射,直至最终确定定义。本节介绍的治理规则和类型规则同样适用于以这种方式创建的对象。
customer_360 是横跨三个数据源的客户级视图,每位客户对应一行。订单明细和聚合单独放在下一节定义的指标视图中。
CREATE OR REPLACE VIEW customer_360 AS
SELECT aurora_customer.cid,
aurora_customer.first_name,
aurora_customer.last_name,
aurora_customer.email,
aurora_customer.ssn,
aurora_address.city,
aurora_address.state,
aurora_credit_card.card_num,
aurora_credit_card.card_type,
postgres_rewards_account.account_id,
postgres_rewards_account.create_date AS rewards_since
FROM (
(
aurora_customer AS aurora_customer
LEFT OUTER JOIN aurora_address AS aurora_address
ON aurora_customer.location = aurora_address.id
)
LEFT OUTER JOIN aurora_credit_card AS aurora_credit_card
ON aurora_customer.cid = aurora_credit_card.cid
)
LEFT OUTER JOIN postgres_rewards_account AS postgres_rewards_account
ON aurora_customer.cid = postgres_rewards_account.cid;
这一定义有两个特性,对架构的其余部分很重要。首先,联接定义位于 Denodo Platform 中,而不是数据流水线中。没有 ETL 作业负责维护一张物化的 customer_360 表。VDP 在执行时完成联接:Aurora 返回客户资料和银行卡信息,本地集群返回奖励计划注册记录,VDP 再通过 cid 将它们合并。其次,派生视图保留了所有列,包括 ssn 和 card_num。
为了支持治理和 AI,我们还添加了元数据:为个人身份信息(PII)字段添加列标签,并提供说明视图及各个字段的描述。Denodo Assistant 可以使用 LLM 为这些内容提供建议。后续章节将说明这些元数据为何重要。
图 2:Denodo Design Studio 中的 customer_360 派生视图。画布上展示了来自三个数据源的四个基础视图,通过 cid 和 location 联接。aurora_customer 中的 ssn 列和 aurora_credit_card 中的 card_num 列带有 pii_sensitive 标签,“受治理的访问”一节中的全局安全策略会引用该标签。
指标视图采用特定的 SOURCES/DIMENSIONS/METRICS 结构定义可复用的业务度量。完整语法请参阅 VQL 指南中的“定义指标视图”参考文档。lifetime_customer_value 并不包含在 customer_360 内部,而是作为独立对象与其并列存在:
CREATE OR REPLACE METRIC VIEW lifetime_customer_value
(
first_name, last_name, state, rewards_since, lifetime_spend, order_count, product_id,product_name, product_brand,product_dept, units_sold
)
SOURCES (
customer_360 AS customer_360,
redshift_order AS redshift_order,
redshift_product AS redshift_product
)
ASSOCIATIONS (
customer_360 redshift_order assoc_customer360_orders,
redshift_product redshift_order assoc_product_orders
)
DIMENSIONS (
customer_360(
first_name AS customer_360.first_name,
last_name AS customer_360.last_name,
state AS customer_360.state,
rewards_since AS customer_360.rewards_since
),
product(
product_id AS redshift_product.id,
product_name AS redshift_product.name,
product_brand AS redshift_product.brand,
product_dept AS redshift_product.dept
)
)
METRICS (
lifetime_spend AS sum((redshift_order.price*redshift_order.quantity)),
order_count AS count(redshift_order.id),
units_sold AS sum(redshift_order.quantity)
);
其他视图和外部报表工具可以引用 lifetime_customer_value,就像它引用其他视图一样。当业务规则发生变化时(例如,lifetime_spend 应排除已取消的订单),只需在指标定义中更新一次。所有使用方都会在下一次查询时应用这项变更,无需修改派生视图或下游应用。不同团队可以建立各自的派生视图,表达其业务线看待业务的方式。基础数据保持共享,语义解释则相互独立,因此任何一个团队的修改都不会干扰另一个团队。
图 3:Design Studio 中的 lifetime_customer_value 指标视图,展示了用于定义 lifetime_spend、order_count 和 units_sold 的 SOURCES、DIMENSIONS 和 METRICS 面板。
当智能体执行“示例”一节中的自动注册问题(“按终身消费金额排名前 20 的客户中,哪些尚未加入奖励计划?”)时,对应的 VQL 会使用指标视图计算结果集,并求取所需指标的值:
SELECT first_name, last_name, state, EVALUATE_METRIC(lifetime_spend) AS lifetime_spend
FROM lifetime_customer_value
WHERE rewards_since IS NULL
GROUP BY first_name, last_name, state
ORDER BY EVALUATE_METRIC(lifetime_spend) DESC
LIMIT 20;
虽然这条查询只引用了指标视图,但 VDP 基于成本的优化器会规划跨三个源数据引擎的联邦执行过程。生成的执行计划大致如下:
下推至 Amazon Aurora:Denodo 将 customer、address 和 credit_card 的联接下推至 Aurora,返回客户资料字段,包括 first_name、last_name、state 和 cid。
下推至本地 PostgreSQL:Denodo 将对 rewards_account 的投影操作下推至 PostgreSQL,返回 cid 和 create_date。
下推至 Amazon Redshift:Denodo 将消费金额聚合下推至 Amazon Redshift,按 cid 分组计算 SUM(price * quantity)。
在 Denodo 内部合并:Denodo 先通过 cid 将 Aurora 的客户资料结果与 PostgreSQL 的奖励计划结果进行左联接,再通过 cid 将该结果与 Amazon Redshift 聚合后的消费金额进行右外联接。Denodo 筛选出 rewards_since IS NULL 的行,按 first_name、last_name 和 state 分组,以外层分组聚合(sum(sum) AS lifetime_spend)计算指标,按 lifetime_spend 降序排列,最多返回 20 行。
这一执行计划发挥了各个数据源的优势。Amazon Redshift 负责聚合;Aurora 负责客户资料联接,因为三张客户资料表都存储在那里;本地集群则返回规模较小的奖励计划记录集。VDP 负责最终的跨引擎联接和 Top-N 筛选,处理的是三个紧凑的中间结果集,其中每位客户对应一行,而不是每笔订单对应一行。手工编写的数据流水线通常也会采用近似的处理结构,但随后就必须持续维护其同步。
VDP 还会在成本最低的位置处理类型协调。如果同一个标识符在一个数据源中存储为整数,在另一个数据源中存储为字符串,VDP 会将类型转换下推到转换后仍能根据相应谓词进行过滤的数据源,而不是先跨引擎拉取数据,再协调类型。
图 4:从 C360 智能体到 Amazon Aurora、Amazon Redshift 和本地 PostgreSQL,再返回智能体的查询流程。VDP 将一条针对 customer_360 与 lifetime_customer_value 联接的 VQL 请求,重写为适用于各引擎的原生 SQL,收集中间结果集,在 VDP 内部按 cid 联接,然后将最终数据行返回给智能体。
除了查询下推和按需联邦查询,VDP 还提供缓存、聚合感知加速和点对点复制功能。在需要预先计算复杂转换的用例中,这些技术可以补充查询下推能力,同时保留访问控制规则和数据血缘。
如果一个语义视图仅以可查询端点的形式存在,就会留下可发现性方面的缺口。下一个需要“客户终身价值”指标的团队,无从得知 lifetime_customer_value 已经存在、它基于哪些数据构建,或还有谁依赖它。将 customer_360 和 lifetime_customer_value 发布到 Denodo Data Marketplace,可以把它们转变为可复用、受治理的企业数据产品,弥补这一缺口:这两个对象都会展示各自的 VQL 定义、所有权、业务描述、自定义属性,以及回溯至基础视图的数据血缘。使用者可以根据业务含义进行搜索,无须事先了解模式。Denodo Data Marketplace 还提供面向非技术用户的其他自助服务功能,包括数据准备向导、管理员提供的背书和弃用说明,以及向数据产品负责人提交请求和提问的功能。
Denodo 通过 360 graph 进一步扩展了这一能力,它提供围绕某个业务概念的关系视图。例如,该图会关联已经使用 customer_360 的报表、仪表板、notebook 或智能体工具,以及定义表中数据含义或使用条件的术语表。使用者可以先查看数据集的相关上下文,再编写查询。
图 5:Denodo Data Marketplace 中的 customer_360 图视图条目。详情面板显示了一个使用该视图的 Tableau BI 工具,以及关联到该视图的术语表定义。
Denodo 中的语义模型使用 VQL 定义,但 Denodo 原生支持通过多种开放协议对外提供任意视图。同一个 customer_360 视图可以通过 JDBC、ODBC 或 ADBC 以 SQL 方式访问,通过 Denodo GraphQL Service 以 GraphQL 方式访问,通过 Denodo OData Service 以 OData 2.0 或 4.0 方式访问,也可以通过 Denodo MCP Server 作为 MCP 工具访问。本演练选择 MCP,是因为它适合与 AgentCore 配合使用。同一视图也可以供 Power BI 仪表板、Tableau 工作簿或 Java 应用使用,无须额外建模。
Denodo 还于 2026 年 3 月加入了 Apache Ossie(孵化中),其前身为 Open Semantic Interchange(OSI),这是一项厂商中立的语义元数据开源规范。Apache Ossie 尚处于早期阶段,但其目标是让语义定义能够在采用该规范的应用之间移植。不过,Denodo 已经可以通过 Denodo Connects 与 SageMaker Catalog、Collibra、Purview 等其他数据目录集成,共享元数据。
广泛覆盖各类数据源是企业级语义层的核心特征之一,但如果缺少运行时访问控制,同样的覆盖能力也会带来切实的风险。如果按用户进行过滤的逻辑位于智能体代码中,一次提示词注入就可能绕过它。如果这套逻辑位于 LLM 中,那实际上就等于没有落实。如果仅在各个源系统中强制执行,策略可能不一致,也可能无法涵盖跨数据源形成的业务含义。Aurora 不知道语义层中的“最高消费客户”是什么意思,位于堡垒机后方的本地 PostgreSQL 集群同样不知道。而且很多时候,尤其是在混合使用本地和云端系统的场景中,甚至无法在所有系统之间统一使用身份提供商。
这一架构采用的方法是在语义层强制执行访问控制,依据的是发起请求的人类用户的身份,该身份从 IdP 经 Amazon Bedrock AgentCore 端到端传递至 Denodo Virtual DataPort。
图 6 放大展示了图 1 参考架构中的身份部分,将从应用到 Denodo VDP 的出站路径展开为一个包含八跳的序列。下面的编号步骤与图中的编号箭头一一对应。
图 6:从用户登录开始,经 Amazon Bedrock AgentCore 到 Denodo(MCP Server 和 VDP)及底层数据源的身份传递与查询流程。黑色箭头表示出站的身份与查询路径。绿色虚线箭头表示携带过滤后结果集的返回路径。
用户通过企业 IdP 向应用进行身份验证。IdP 返回一个 JWT,其中包含用户身份及属性声明——角色、区域、部门,以及 IdP 配置为输出的其他属性。
应用通过 AgentCore Gateway 调用智能体,并将用户的 JWT 用作 bearer token。
Gateway 将请求路由至 AgentCore runtime,后者托管 Strands 智能体进程。
当智能体发起出站工具调用时,AgentCore Identity 执行 On-Behalf-Of 令牌交换,并返回一个新的访问令牌,其中 sub 声明对应人类用户,aud 声明对应 Denodo。
智能体在 MCP 请求中通过 Authorization: Bearer <access_token> 将新的访问令牌提交给 Denodo MCP Server。
Denodo VDP 根据配置的 JWKS URL 验证 JWT,检查颁发者和受众,提取 scope 声明,并将调用方映射到一个 Denodo 角色。
VDP 在查询时评估 Global Security Policies,并向智能体返回经过过滤的结果集。
VDP 查询各数据源以满足请求,并在返回结果之前将其合并。
步骤 2 中 Gateway 的 JWT 验证是可选的,因为 VDP 会重新验证