We Built a Text-to-SQL Agent for SAP. Here’s Why We Had to Rethink Everything.

We Built a Text-to-SQL Agent for SAP. Here’s Why We Had to Rethink Everything.

我们为 SAP 构建了一个 Text-to-SQL 智能体,以下是我们必须彻底重构的原因。

How governed SQL, a medallion semantic layer, and three query engines make enterprise data actually queryable — without hallucinated column names. 通过受控 SQL、奖章式语义层和三个查询引擎,我们实现了企业数据的真正可查询性,且不会产生虚构的列名。

Most Text-to-SQL demos look great until you try them on real enterprise data. You ask “what were our top 10 materials by revenue last quarter?” and the model confidently returns a query that joins ORDERS to PRODUCTS — tables that don’t exist in your SAP system. Or it invents a column called revenue when the real one is buried inside VBAK.NETWR, a field whose meaning you’d only know if you’d spent years as an SAP consultant. 大多数 Text-to-SQL 的演示看起来都很棒,直到你将其应用到真实的企业数据上。当你问“上季度按收入排名前 10 的物料是什么?”时,模型会自信地返回一个将 ORDERS 与 PRODUCTS 连接起来的查询——而这些表在你的 SAP 系统中根本不存在。或者,它会凭空捏造一个名为“revenue”的列,而真正的收入数据却隐藏在 VBAK.NETWR 中——这是一个只有拥有多年 SAP 顾问经验的人才能理解其含义的字段。

That’s the problem we set out to solve with Onibex ASK — Agentic Semantic Knowledge, an open platform that turns natural language into governed SQL over SAP data. The word “governed” is doing a lot of work in that sentence, and it’s worth unpacking exactly what it means and why it changes everything. 这就是我们着手通过 Onibex ASK(Agentic Semantic Knowledge,智能体语义知识)解决的问题。这是一个将自然语言转换为 SAP 数据受控 SQL 的开放平台。句中的“受控”(governed)一词承载了重要含义,值得我们深入剖析其确切定义以及它为何能改变一切。

The LLM Should Be a Compiler, Not an Inventor

大模型应该是编译器,而不是发明家

Most Text-to-SQL systems give the LLM a database schema and ask it to “figure it out.” That works surprisingly well for simple schemas — a handful of tables with obvious names. But SAP HANA schemas are not simple. A real S/4HANA system might have thousands of tables, cryptic four-letter field names, and join conditions that were designed for performance, not readability. 大多数 Text-to-SQL 系统只是给大模型一个数据库架构,然后让它“自己琢磨”。对于简单的架构(即少数几个命名直观的表),这种方法效果出奇地好。但 SAP HANA 的架构并不简单。一个真实的 S/4HANA 系统可能拥有数千张表、晦涩的四字母字段名,以及为了性能而非可读性设计的连接条件。

Our approach is different: the LLM never invents structure. It only maps business terms to a curated semantic layer. The semantic layer — a set of YAML files we call Data Products — is the single source of truth. Every field in every query must trace back to a real column in a real table, with the exact join predicate that connects it. 我们的方法则不同:大模型从不发明结构。它只负责将业务术语映射到经过精心策划的语义层。这个语义层(我们称之为“数据产品”的一组 YAML 文件)是唯一的真理来源。查询中的每一个字段都必须追溯到真实表中的真实列,并带有连接它的精确谓词。

The LLM is a compiler: it takes a natural-language question, looks up the matching business terms in the layer, and emits SQL from those resolved mappings alone. If a term isn’t in the layer, the agent asks for clarification rather than guessing. When a user asks “what’s our revenue by material?”, ASK maps “revenue” to VBAK.NETWR via the synonyms field. It knows the join from VBAK to VBAP because the Data Product defines it. It never touches any other table. The SQL is reproducible, auditable, and deterministic — not because the LLM is unusually smart, but because it operates inside tight guardrails. 大模型充当了编译器的角色:它接收自然语言问题,在语义层中查找匹配的业务术语,并仅根据这些已解析的映射生成 SQL。如果某个术语不在语义层中,智能体会要求澄清,而不是进行猜测。当用户问“按物料划分的收入是多少?”时,ASK 会通过同义词字段将“revenue”映射到 VBAK.NETWR。它知道从 VBAK 到 VBAP 的连接方式,因为数据产品中已经定义了它。它从不触碰其他任何表。生成的 SQL 是可复现、可审计且确定性的——这并非因为大模型特别聪明,而是因为它在严格的护栏内运行。

The Medallion Model, Applied to SAP

应用于 SAP 的奖章模型

One of the structural decisions that made everything else work was adopting a Bronze / Silver / Gold medallion model for the semantic layer. 促成这一切成功的结构性决策之一,是为语义层采用了“铜/银/金”奖章模型。

  • Bronze is raw SAP tables — columns and primary keys, no join logic. VBAK (sales order header), VBAP (sales order item), MARA (material master). These exist so ASK understands the physical schema.
  • **铜层(Bronze)**是原始的 SAP 表——包含列和主键,没有连接逻辑。例如 VBAK(销售订单抬头)、VBAP(销售订单行项目)、MARA(物料主数据)。它们的存在是为了让 ASK 理解物理架构。
  • Silver is where the business logic lives. A Silver entity joins several Bronze tables into a coherent business concept, owns the complete join topology for that concept, and defines field roles: measure, dimension, identifier, timestamp. The Silver plane is the agent’s fallback — if no Gold entity covers a question, ASK resolves from Silver and computes the joins.
  • **银层(Silver)**是业务逻辑所在之处。一个银层实体将多个铜层表连接成一个连贯的业务概念,拥有该概念的完整连接拓扑,并定义了字段角色:度量、维度、标识符、时间戳。银层是智能体的后备方案——如果没有任何金层实体覆盖某个问题,ASK 会从银层解析并计算连接。
  • Gold is denormalized analytics — a pre-joined, pre-aggregated entity that the agent can query in a single scan. When a Gold entity covers the exact metrics and dimensions a question needs, ASK answers from Gold alone. No joins, no planning overhead, minimal latency.
  • **金层(Gold)**是去规范化的分析层——一个预先连接、预先聚合的实体,智能体可以通过单次扫描进行查询。当金层实体涵盖了问题所需的精确指标和维度时,ASK 直接从金层回答。无需连接,没有规划开销,延迟极低。

Question: “top 10 materials by net value, Q1” 问题:“第一季度按净值排名前 10 的物料” │ ▼ Does a Gold entity cover this? │ ▼ 金层实体是否覆盖此问题? ├─ Yes → single query against Gold table ├─ 是 → 对金层表进行单次查询 └─ No → resolve via Silver entity (VBAK + VBAP join) └─ 否 → 通过银层实体解析(VBAK + VBAP 连接)

This Gold-first resolution is what keeps query latency reasonable at scale. Well-modelled Gold entities cover the 80% of questions your business users actually ask. Silver handles the long tail. 这种“金层优先”的解析策略保证了大规模查询下的延迟在合理范围内。建模良好的金层实体可以覆盖业务用户 80% 的常见问题,而银层则处理剩下的长尾需求。

Three Engines for Different Tradeoffs

三种引擎,应对不同权衡

One of the questions we wrestled with longest was: how much planning should the agent do per query? More planning means better SQL — but it also means more LLM calls, more latency, and more cost. We ended up shipping three engines that let users and administrators make that tradeoff explicitly. 我们纠结最久的问题之一是:智能体在每个查询上应该进行多少规划?规划越多,SQL 质量越好,但同时也意味着更多的大模型调用、更高的延迟和更高的成本。最终,我们推出了三种引擎,让用户和管理员能够明确地进行权衡。

  • Flash: 1 LLM call · ~15 s · Low cost. Searches the schema as free-text chunks and writes SQL in a single shot. No semantic plan, no join verification, no scope check. Fast and cheap — good for exploratory questions. Least reproducible: the same question asked twice may produce slightly different SQL.
  • Flash(闪电引擎):1 次大模型调用 · ~15 秒 · 低成本。将架构作为自由文本块进行搜索,并一次性编写 SQL。没有语义规划,没有连接验证,没有范围检查。快速且廉价,适合探索性问题。可复现性最差:同一个问题问两次可能会产生略有不同的 SQL。
  • Precise: 3 LLM calls · ~60 s · High confidence. Extracts a Semantic Plan IR, runs hybrid kNN+BM25 search with Medallion re-ranking, plans joins with Dijkstra’s algorithm, generates SQL, then audits it against the allowed table set — retrying once if it strays outside. Fully deterministic Data Product selection. Use for compliance, audit trails, or when Flash fails.
  • Precise(精确引擎):3 次大模型调用 · ~60 秒 · 高置信度。提取语义计划 IR,运行带有奖章模型重排序的混合 kNN+BM25 搜索,使用 Dijkstra 算法规划连接,生成 SQL,然后根据允许的表集进行审计——如果超出范围则重试一次。数据产品选择完全确定。适用于合规性、审计追踪或 Flash 引擎失败的情况。
  • Smart: 2 LLM calls · ~40 s · Default. Shows the LLM a compact catalog and lets it pick the relevant Data Products — selection is model-driven. But join planning after selection uses the same Dijkstra graph as Precise. Balances speed and accuracy for everyday production use.
  • Smart(智能引擎):2 次大模型调用 · ~40 秒 · 默认。向大模型展示一个紧凑的目录,让它选择相关的数据产品——选择过程由模型驱动。但在选择后的连接规划中,它使用与 Precise 相同的 Dijkstra 图。在日常生产使用中平衡了速度与准确性。

The insight behind this design is that where you put the determinism matters. Precise makes the selection of Data Products deterministic. Smart makes the join planning deterministic. Flash leaves both to the model. Users who need auditability use Precise; users who need throughput use Smart; users who need speed use Flash. 这一设计背后的洞察是:确定性放置的位置至关重要。Precise 使数据产品的选择具有确定性;Smart 使连接规划具有确定性;Flash 则将两者都交给模型。需要可审计性的用户使用 Precise;需要吞吐量的用户使用 Smart;需要速度的用户使用 Flash。

What Happens When the Question Is Ambiguous?

当问题存在歧义时会发生什么?

Real enterprise data has vocabulary problems. “Sales” might mean VBAK in the SD module or EKKO in MM, from a procurement perspective. “Revenue” might mean gross or net depending on whether the user is in Finance or Sales. ASK handles this with a three-level disambiguation system backed by a semantic dictionary index in OpenSearch. 真实的企业数据存在词汇问题。从采购角度看,“Sales”可能指 SD 模块中的 VBAK,也可能指 MM 模块中的 EKKO。“Revenue”可能指毛收入或净收入,具体取决于用户是财务部门还是销售部门。ASK 通过一个由 OpenSearch 中的语义字典索引支持的三级消歧系统来处理这个问题。

  • Level 1: if a term maps to exactly one entity, the agent auto-resolves. No interruption.
  • 一级:如果一个术语精确映射到一个实体,智能体会自动解析,无需干预。
  • Level 2: if a term maps to multiple entities across different SAP modules, the agent surfaces a disambiguation message — “Did you mean the SD sales order or the MM purchasing order?” — and waits. It doesn’t guess.
  • 二级:如果一个术语映射到不同 SAP 模块中的多个实体,智能体会弹出消歧消息——“您是指 SD 销售订单还是 MM 采购订单?”——然后等待。它不会进行猜测。
  • Level 3: if the term has no mapping at all, the agent returns a clear message directing the user to…
  • 三级:如果该术语完全没有映射,智能体会返回一条清晰的消息,引导用户前往……