随着 AI Agent 执行复杂任务的能力日益增强,它们访问和理解企业数据的能力仍然是重要的瓶颈。虽然模型上下文协议 (MCP) 等工具使 Agent 更容易与外部系统交互,但查询数据库等结构化数据仍然带来了重大挑战。而这正是由 Wren Engine (由 Apache DataFusion 提供支持) 发挥重要作用的地方。通过将语义层与高性能、基于 Rust 的 DataFusion 查询引擎相结合,Wren Engine 不仅使 AI Agent 能够理解数据背后的逻辑和关系,而且无论底层数据库如何,都能确保查询执行快速且可靠。
Wren Engine 是一个专为模型上下文协议 (MCP) 构建的强大语义引擎,使 AI Agent 能够通过下一代语义层与企业数据交互。通过直接嵌入到 MCP 客户端中,它提供了深入的业务上下文、精确的数据访问和治理能力。Wren Engine 设计上注重语义优先、互操作性和可嵌入性,将 AI 转化为真正理解您的数据模型和逻辑的上下文感知系统 — 从而在整个企业范围内释放可扩展、可信赖的 AI 能力。
Wren Engine 也是 Wren AI(一个开源的下一代商业智能 (GenBI) AI Agent)的强大 SQL 骨干。Wren AI 旨在赋能数据驱动型团队,使用户能够通过自然语言无缝地与数据交互。无论是生成复杂的 Text-to-SQL 查询,通过图表可视化洞察,构建电子表格,还是创建详细报告和仪表板,Wren Engine 都确保每一次交互都准确、高效且可用于生产环境。借助 Wren AI,业务用户和分析师可以充分释放其数据的价值 — 无需 SQL 专业知识。
在本文中,我们将探讨 Wren Engine 如何弥合 AI 与数据之间的鸿沟,使 AI 驱动的数据交互更具语义化、更高效、更适合生产环境。让 AI Agent 真正理解您的数据。
模型上下文协议 (MCP) 为 AI Agent 与各种工具交互建立了标准化接口,使它们能够利用外部知识回答问题或请求更准确的响应。然而,在数据库查询方面,如果 AI Agent 无法理解您的数据,它又如何提供快速准确的答案呢?
为了更好的性能,大多数 AI Agent 依赖基于云的大型语言模型 (LLMs),每次问答交互都会产生显著的成本。减少往返次数对于提高效率至关重要。准确性仍然是提供有意义结果的关键因素。关于 Text-to-SQL 的研究强调,清晰和语义化的元数据以及数据库模式对于提高答案性能至关重要。
作为语义层,Wren Engine 提供了一种结构化的方法来描述您的数据,并为 AI Agent 提供统一的 SQL 接口。这使得 AI Agent 更容易理解您的数据并提供准确的响应。
有关语义重要性的更多详细信息,请参阅 Howard 的文章:赋能下一波 AI Agent:为未来的 MCP 客户端和企业数据访问奠定基础。
在下一节中,我们将深入探讨 AI Agent 有效交互结构化数据所需的关键要求 — 并探索 Wren Engine 如何通过强大的语义层和统一的 SQL 接口有针对性地满足这些需求。
Wren Engine 通过语义层和统一的 SQL 接口弥合了 AI 与数据之间的鸿沟。它简化了数据建模,并确保了跨各种 SQL 方言的兼容性,使 AI 能够提供准确高效的查询结果。
为了使 AI 能够有效理解您的数据,最关键的方面是通过语义层弥合 AI 与数据之间的鸿沟。我们开发了一种统一的数据描述方法,称为 建模定义语言 (MDL),它使用结构化且易于人类阅读的 JSON 格式。MDL 的主要概念是在逻辑层描述您的数据。通过将表定义为 Model
(一个仅包含您希望暴露的列的虚拟表),您可以在不影响实际数据的情况下使数据更具语义化。此外,您可以定义 Relationships
并描述模型之间的连接,这对于帮助 AI 理解这些关系至关重要。
model
用作包装物理表的逻辑层。它可用于控制 AI 可以访问的内容或对物理列应用预处理。
例如,Wren Engine 动态重写以下 SQL 查询
SELECT * FROM wren.public.orders
为带有子查询的另一个 SQL 查询
SELECT * FROM
(
SELECT o_orderkey, o_custkey
FROM postgrs.public.orders
)
子查询根据 MDL 定义动态生成。有关更多详细信息,请参阅 Wren Engine 数据建模文档。
为了促进与各种数据库的通信,AI Agent 经常由于方言差异而遇到 SQL 语法问题。Wren Engine 提供统一的 SQL 接口,允许 AI Agent 使用通用 SQL 语法查询多个数据库。然后 Wren Engine 将 SQL 转译为目标数据库所需的特定方言。
此外,使用 AI Agent 回答问题通常是即席 SQL 场景。在这种情况下,提供低延迟的 SQL 接口非常有益。提供清晰的错误消息和建议也至关重要,因为 AI 通常需要服务器的迭代反馈来优化其查询和响应。
为了实现语义引擎,我们首先分叉了 Trino 的 SQL 层,以构建 Wren Engine SQL 层的基础。一个关键组件是 SQL 重写器,它使用 Antlr4 Visitor 实现,接收 WrenMDL 和输入的 SQL,生成一个包含必要信息的 SQL 查询,例如为模型构建子查询和为列构建表达式。然后将规划的 SQL 转译为特定方言,并由数据源执行。利用 sqlglot,我们实现了无缝的 SQL 方言转换,而 ibis-project 为查询各种数据库提供了统一接口。为了获得最佳性能,生成的 SQL 完全下推到数据源执行,确保了效率和可伸缩性。
实现 SQL 重写器需要处理数据库之间巨大的 SQL 语法差异。为不同用例应用重写规则非常耗时,并且将 SQL 基础与每个数据库的独特规范对齐也十分困难。例如,遗留的 MySQL 版本(8.0 之前)不支持公用表表达式 (CTEs),这使得将基于 CTE 的查询转换为兼容形式具有挑战性。类似地,UNNEST
语法在不同方言中各不相同 — 虽然它通常可以用作选择项或表因子,但 BigQuery 只支持将其用作表因子。
纯粹在 SQL 层将一个抽象语法树 (AST) 转换为另一个本质上是复杂的。一个更健壮和可扩展的解决方案是在重写之前将查询规划为中间表示 (IR),但这需要大量的架构投入。
SQL 重写器的原始实现依赖于 Trino 的 SQL 解析器,该解析器是用 Java 构建的。这在生产环境中引入了优化和性能问题。由于遗留代码库并非为高性能执行而构建,它在实际工作负载下表现不佳,因此需要更高效和可扩展的解决方案。
Apache DataFusion 是一个用 Rust 编写的可扩展查询引擎,使用 Apache Arrow 作为其内存格式。它为构建快速且功能丰富的数据库和分析系统的开发者提供了库和二进制文件,可根据特定工作负载进行定制。DataFusion 的原生性能非常出色,使我们能够专注于实现数据建模的功能。
如前所述,纯粹在 SQL 层转换 SQL 存在许多挑战。LogicalPlan 层是用于语义重写的优秀中间表示 (IR)。将 SQL 查询规划到 LogicalPlan 中起到 SQL 标准化的作用,不同的 SQL 结构可以映射到相同的逻辑表示。例如,CTE 表和子查询在 LogicalPlan 层是等效的,都表示为 Subquery
计划。这大大减少了我们需要处理的 SQL 语法范围。
DataFusion 的另一个关键优势是其 Unparser,它可以将 LogicalPlan 转换回 SQL 文本。此功能与 Wren Engine 将完整 SQL 查询下推到远程数据库的目标完美契合。此外,DataFusion 支持将 LogicalPlan 转换为 protobuf 或 substrait 等格式,进一步增强了其灵活性和可用性。
在规划 SQL 查询时,DataFusion 执行严格验证以确保查询的正确性。这些验证包括检查表或列是否存在,以及验证列类型对于指定的函数或运算符是否有效。这使我们能够在无效的 SQL 查询在数据源上执行之前检测并验证它们,从而减少查询延迟并提高效率。
此外,DataFusion 的逻辑规划器提供的错误消息更清晰、更标准化。DataFusion 社区正在积极改进错误消息。例如,改进措施包括将节点跨度附加到错误 (将诊断信息附加到更多错误) 以及在未找到预期函数时提供候选函数建议。这些改进对于 AI Agent 特别有益,因为它们有助于更有效地纠正查询和优化其行为。
Apache DataFusion 提供了强大的工具,例如 UserDefinedLogicalNode 和 AnalyzerRule,用于实现自定义逻辑计划策略。Wren Engine 利用这些特性有效实现了其建模策略。例如,ModelPlanNode 用于在逻辑计划中表示 Model
,而 ModelAnalyzeRule 和 ModelGenerationRule 则根据特定模型动态生成子查询 SQL。
这些自定义规则还有助于弥合 SQL 方言之间的差异。我们来看几个案例。
处理带时区的时间戳字面量是一个常见的挑战,原因在于 SQL 方言的差异。虽然许多数据库支持带时区信息的时间戳字面量,但语法和行为在不同系统之间可能存在显著差异。这种不一致性在处理多个数据库时造成了必须解决的差异。
例如,大多数数据库支持以下用于带时区时间戳字面量的 SQL 语法
SELECT TIMESTAMP WITH TIME ZONE '2011-01-02 08:03:14 America/New_York';
然而,ClickHouse 不直接支持解析带时区的时间戳字面量。相反,您需要使用 DateTime([time zone])
类型或特定的解析函数(例如,parseDateTimeBestEffort
),尽管即使这些也无法直接解析字面量
SELECT '2011-01-01 08:00:12'::DateTime('America/New_York');
另一个例子是 Microsoft SQL Server (MSSQL),它使用 AT TIME ZONE
关键字为时间戳字面量分配时区
SELECT CAST('2011-01-02 08:03:14' AS DATETIME2) AT TIME ZONE 'Eastern Standard Time' AS datetime_with_tz;
另外,MSSQL 提供了 DATETIMEOFFSET
类型,但它只接受偏移量,而不是时区名称
SELECT CAST('2011-01-01 08:00:12 -04:00' AS DATETIMEOFFSET(7));
这些例子突出了不同方言之间 SQL 语法的结构性差异。为了解决这种差异,一种方法是将字面量解析为其日期时间和时区组件,然后为每个特定方言构建所需的 SQL。然而,一个更通用的解决方案是在查询数据库之前将所有时间戳字面量评估为 UTC
时区。这使我们能够保持一致的结构,例如
SELECT TIMESTAMP '2011-01-02 13:03:14';
使用这种方法,我们只需处理无时区时间戳的类型名称差异。
类型强制转换是指数据库在某些条件下自动执行的隐式类型转换。然而,类型强制转换的规则在不同数据库之间各不相同。因此,具有相同表模式的同一 SQL 查询可能在某些数据库中有效,但在其他数据库中无效。
例如,考虑以下 SQL 查询
WITH temp_cte AS (
SELECT
CAST(current_date AS DATE) AS date_col,
CAST(current_timestamp AS TIMESTAMP WITH TIME ZONE) AS tsz_col
)
SELECT date_col > tsz_col FROM temp_cte;
此查询在 Postgres 和 DuckDB 中有效,但在 BigQuery 中无效。在 BigQuery 中,它将返回类似以下的错误消息
No matching signature for operator > for argument types: DATE, TIMESTAMP Signature: T1 > T1 Unable to find common supertype for templated argument <T1> Input types for <T1>: {DATE, TIMESTAMP} at [6:8]
此外,在 BigQuery 中,TIMESTAMP WITH TIME ZONE
被称为 TIMESTAMP
。因此,BigQuery 的等效 SQL 将如下所示
WITH temp_cte AS (
SELECT
CAST(current_date() AS DATE) AS date_col,
CAST(current_timestamp() AS TIMESTAMP) AS tsz_col
)
SELECT date_col > tsz_col FROM temp_cte;
根据 BigQuery 的转换规则,它不支持从 DATE 到 TIMESTAMP 的隐式转换。但是,支持显式转换
WITH temp_cte AS (
SELECT
CAST(current_date() AS DATE) AS date_col,
CAST(current_timestamp() AS TIMESTAMP) AS tsz_col
)
SELECT CAST(date_col AS TIMESTAMP) > tsz_col FROM temp_cte;
虽然可以理解为什么 BigQuery 不允许 DATE 和 TIMESTAMP WITH TIME ZONE 之间的隐式类型强制转换,但对于寻求统一 SQL 体验的用户来说,此限制可能令人沮丧。
DataFusion 提供了一个名为 Type Coercion 的默认规则来解决此问题。这是一个使用 Rust 程序演示 DataFusion 如何处理此问题的示例
use datafusion::error::Result;
use datafusion::execution::SessionStateBuilder;
use datafusion::prelude::SessionContext;
use datafusion::sql::unparser::Unparser;
#[tokio::main]
async fn main() -> Result<()> {
let state = SessionStateBuilder::new()
.with_default_features()
// Disable the default optimizer rules to simplify the example
.with_optimizer_rules(vec![])
.build();
let ctx = SessionContext::new_with_state(state);
let sql = r#"
WITH temp_cte AS (
SELECT
CAST(current_date() AS DATE) AS date_col,
CAST(current_timestamp() AS TIMESTAMP) AS tsz_col
)
SELECT date_col > tsz_col FROM temp_cte;
"#;
// Plan the SQL, then apply AnalyzerRule and OptimizationRule
let plan = ctx.sql(sql).await?.into_optimized_plan()?;
println!("plan: {plan}");
let unparser = Unparser::default();
// Unparse the logical plan to SQL text
let sql = unparser.plan_to_sql(&plan)?.to_string();
println!("sql: {sql}");
Ok(())
}
输出结果将如下所示
plan: Projection: CAST(temp_cte.date_col AS Timestamp(Nanosecond, None)) > temp_cte.tsz_col
SubqueryAlias: temp_cte
Projection: CAST(current_date() AS Date32) AS date_col, CAST(now() AS Timestamp(Nanosecond, None)) AS tsz_col
EmptyRelation
sql: SELECT (CAST(temp_cte.date_col AS TIMESTAMP) > temp_cte.tsz_col) FROM (SELECT CAST(current_date() AS DATE) AS date_col, CAST(now() AS TIMESTAMP) AS tsz_col) AS temp_cte
如所示,DataFusion 自动为 date_col 添加显式转换。在进行简单的函数名称映射(例如,将 now 替换为 current_timestamp)后,生成的 SQL 对 BigQuery 有效。
通过利用 DataFusion,我们可以轻松地将各种规则应用于逻辑计划,从而减少不同 SQL 方言之间的语法差异,并为 AI Agent 提供统一的 SQL 接口。
DataFusion 是一个纯 Rust 项目,通过 PyO3 提供了与 Python 的无缝集成。这使得开发者可以轻松构建 Python 绑定,实现与强大的基于 Python 的工具的互操作性。例如,Wren Engine 利用 sqlglot 和 ibis-project 等 Python 库(它们都是纯 Python 项目)来连接各种数据源。
此外,通过利用 FastAPI,开发者可以创建健壮的 HTTP 服务,而 MCP Python SDK 则有助于构建专为 AI Agent 定制的 MCP 服务器。这种集成确保了 Wren Engine 能够无缝弥合 Rust 的性能与 Python 广泛生态系统之间的鸿沟,使其成为现代数据系统的多功能选择。
DataFusion 社区非常活跃且不断壮大,定期有新的贡献者加入,每天有大量提交被合并。这个充满活力的生态系统确保了项目得到良好维护并快速发展以满足新兴需求。
对于 Wren Engine 而言,这个活跃的社区提供了坚实可靠的基础,确保了长期的可持续性并能够访问尖端功能。通过基于 DataFusion 构建,Wren Engine 受益于协作和创新的环境,使其成为面向未来数据系统的选择。
Wren Engine 在 Apache DataFusion 的支持下,通过语义层和统一的 SQL 接口连接 AI 和数据。通过利用 DataFusion 的 LogicalPlan,它克服了 SQL 方言挑战,确保了准确性和效率。凭借强大的社区支持和卓越的性能,Wren Engine 是面向未来数据系统的解决方案。
访问 🔗我们的 GitHub 仓库(根据 Apache 2.0 许可),亲身体验 Wren Engine 的功能。
连接您的 MCP 客户端到 Wren Engine,亲自尝试,见证语义化数据访问的魔力。Wren Engine MCP 服务器仍处于早期阶段,我们正在积极改进。我们热烈邀请您加入我们的社区,帮助加速 MCP 的未来。
立即用 AI 为您的数据赋能?!