返回
RSS ThoughtSpot Blog 精选 发布 2026-08-13 13:23 56

ThoughtSpot AgentQL:SQL形态意图,不直接生成SQL的工程路线

ThoughtSpot 工程博客介绍了 AgentQL——一种以 SQL 语法表达分析意图、但不用 LLM 直接生成 SQL 的能力。其背景是 Spotter 的搜索令牌(token)存在表达力缺口,无法覆盖多步对比、层级计算等复杂查询。AgentQL 选择 SQL 语法作为意图语言,同时拒绝 SQL 执行模型,以统一查询引擎执行。文章详述了背后的工程取舍与设计原则。
推荐理由:数据从业者可从中了解 ChatBI/Text-to-SQL 的一种架构思路:用 SQL 形状的中间意图而非直接生成 SQL,兼顾表达力与可执行性,对构建分析 Agent 有借鉴价值。
ChatBIData AgentThoughtSpot

译文 AI 逐段翻译

ThoughtSpot 博客

分类:

最新文章

最新文章数据与AI负责人客户故事最佳实践产品工程公司

SQL形态的意图:AgentQL背后的工程

作者:Dushyant Bansal,ThoughtSpot 工程总监

发布于

订阅

我们的 CEO 最近撰文重申了 ThoughtSpot 在 LLM 刚出现时做出的架构决策:我们不使用 LLM 直接生成 SQL

我的团队花了将近一年时间构建AgentQL:这一能力进一步强化了我们的决策。

所以让我解释一下我们实际构建了什么,为什么它不仅遵从了那个架构决策,而且依赖于它,以及底层的工程选择。

我们面临的问题:表达鸿沟

Spotter 通过搜索令牌回答大多数问题:这是一种结构化、可读的意图表示,业务用户无需了解任何查询语言即可检查和更正。令牌是正确的默认选择,并且仍是主要路径。

但我们不断遇到一堵墙,我们称之为表达鸿沟。我们看到了这样的查询:“显示本财年支出同比下降的客户,按下降幅度排序。”以及“比较每个地区对公司的贡献毛利与公司平均水平。”多步骤比较、详细级别计算、队列逻辑。

我们的查询引擎能够回答每一个此类问题,而且多年来一直如此。令牌语法只是无法表述它们。每次我们扩展语法并重新训练 Spotter 输出,新的分析功能就会出现,鸿沟再次打开。

我们需要一种更丰富的语言来表达意图,这就是我们构建 AgentQL 的原因。我们不需要——也拒绝构建——第二条执行路径。

设计决策:SQL形态的意图

我们选择 SQL 语法作为意图语言,基于两个实际的工程原因:

  • 它是迄今为止为分析问题创建的最精确、最广泛理解的符号。
  • 这是 LLM 训练最充分的语言。我们发明的任何定制 DSL 在这两方面都会更差。

但我们采用了 SQL 的语法并拒绝了 SQL 的执行模型。这就是整个设计。这也是 AgentQL 的首要原则:意图和执行是分离的层。

AgentQL 语句是针对 ThoughtSpot 模型编写的:分析师策划的业务名称。不是物理表或仓库列。

而且它永远、在任何情况下都不会针对你的数据库执行。不存在这样的代码路径。我们知道,因为我们构建了代码路径。

实际发生的情况:AgentQL 语句被解析为查询规范,与所有 ThoughtSpot 查询变成的内部表示相同。

该规范交给我们的确定性查询生成引擎,与生成 ThoughtSpot 中每个查询的引擎相同,无论其源自 Liveboard、搜索还是 Spotter 对话。该引擎编写运行的 SQL。LLM 的输出是编译器的输入,而不是对数据库的查询。

我们称之为 SQL 形态的意图。

与文本到 SQL 的区别并不微妙:

文本到 SQL ThoughtSpot AgentQL
LLM 编写的内容 运行的查询 对所需内容的描述
引用的内容 物理表和列 模型的业务名称
执行的内容 LLM 的输出,逐字 由我们的专有引擎编译的确定性 SQL
谁强制执行安全、连接、指标、日历 LLM(希望如此,每次查询) 引擎(总是,通过构造)

一个具体的例子:“按产品类别划分的总销售额和总退货额”可能表示为:

SELECT "t1"."Product Category",
       SUM("t1"."Sales Amount") AS "Total Sales",
       SUM("t1"."Return Amount") AS "Total Returns"
FROM "Retail Sales" AS "t1"
GROUP BY "t1"."Product Category"

该语句永远不会运行,而且它隐藏了一个陷阱。在模型背后,销售额和退货额位于两个独立的事实表中,它们共享产品维度:一个典型的鸿沟陷阱

手写 SQL 直接连接它们会使行扇出并悄悄膨胀两个总数。编译器更懂,因为模型懂:它在合并之前以各自粒度聚合每个事实,解析声明的连接路径,并注入查询用户的行级安全过滤。你可以检查编译后的 SQL。意图只需几秒表达;它继承的语义我们花了十年工程。

一个值得明确说明的后果:AgentQL 刻意不是 SQL 的全部。它是一个受限的方言,限制就是契约。语句必须能完全针对模型解析,因此编译器拒绝任何无法确定性治理的构造,从 SELECT * 到会绕过模型语义的构造。

我们限制方言不是因为解析完整 SQL 很难。我们限制是因为每个接受的语句都是一个承诺,即编译的查询是受治理的,而我们只接受我们能兑现承诺的语句。

为什么我们拒绝让 LLM 做更多

这是一个合理的问题:LLM 正在快速改进,那么为什么不让前沿 LLM 编写仓库 SQL 并事后验证呢?

因为我们多年工程化企业数据的实际情况,而这些情况对 LLM 都不友好。真实的数据模型不是平面表。它们是带有鸿沟陷阱和扇出陷阱的多星型模式,比如上面的销售和退货示例:连接模式中错误数字看起来完全合理。

能干的工程师也会弄错;我们目睹过。它们携带 PII,必须在每次查询中为每个用户保持安全。它们按业务单位运行不同的财务日历。它们定义半加性度量,如库存和账户余额,其中跨时间的简单 SUM 就是错误的答案。

让 LLM 在每次问题时概率性地重新推导所有这些,你只会得到两样东西:不确定性和一笔 token 账单。

我们的引擎已经编码了那些语义。所以工程答案是显而易见的,并且它成为第二条原则:保持 LLM 的工作精简。理解问题,紧凑地表达,然后停止。所有决定数字是否正确的东西都通过构造从模型继承。

LLM无法忘记你的行级安全,因为它从不编写执行的查询。它不能选择错误的连接路径,因为模型的连接由编译器应用。它不能偏离你的收入定义,因为定义只有一个,并且每个查询都通过它编译。

失败模式同样重要,这是第三原则:一个糟糕的查询是编译错误,而不是事故。当LLM表达意图错误时,你会得到错误但受治理的答案或明确的验证错误:语句在编译时被拒绝并附有原因。

你永远不会得到一个触及数据的无治理查询。在文本到SQL系统中,幻觉是实时查询。在我们的系统中,它是编译错误。

这些原则还带来一件事,也是我们客户最关心的:信任。确定性编译器意味着相同的问题产生相同的查询规范、相同的编译SQL和相同的数字,无论哪个LLM表达意图或如何措辞。许多文本到SQL工具也会向你展示执行的SQL。

区别在于阅读它给你带来的价值。在那些工具中,你是在逐查询审计LLM的即兴发挥:它是否选择了正确的连接,应用了正确的安全,并使用了正确的收入定义?

在这里,SQL是从模型的受治理定义编译的,所以这些问题已经有了答案。验证答案意味着确认意图被理解,而不是手动重新推导正确性。

结果:不按Token计费

这种架构有一个副产品,它出现在账单上而不是演示中。因为LLM的角色刻意很小,繁重的工作由我们的确定性引擎完成,而不是按计量的推理。一个问题不会启动一个代理,燃烧token重新推理你的模式。

这是公司在Spotter 3发布时做出决定背后的工程事实:不按消耗的Token计费。我们的架构使这一选择成为可能;企业选择将利益传递下去。

没有人希望每个问题在后台都有计费表在运行。有了这种架构,就不必如此。

同样的赌注,加倍下注

行业中的许多人押注,通过足够的提示、护栏和重试,LLM将编写可信的数据仓库SQL。我们在LLM存在之前多年就做出了相反的赌注。AgentQL加倍下注:LLM永远不应该编写执行的查询。LLM理解意图。受治理的引擎产生确定性答案。

对于Spotter用户来说,回报是立竿见影的:今天就能回答更广泛的分析问题,而无需等待token语法增长或Spotter对新能力进行再训练。如果引擎能回答,AgentQL现在就能提问。

AgentQL给了意图一种更丰富的语言。信任架构没有移动一英寸:它在引擎中,在模型中,在你手中去验证。这是设计驱动的工程,而不是妥协——所以你永远不必在速度和信任之间做出选择。

开始您的个性化演示,看看如何。

订阅我们的博客

分享这条资讯
分享海报
保存图片
iOS 也可以长按图片保存