September 9, 2026
Arnoldo Muller-Molina
dbt Labs recently published an 11-question benchmark comparing its Semantic Layer with direct text-to-SQL over the ACME Insurance schema. Their best result was 98.2% accuracy using a modeled Semantic Layer. Direct text-to-SQL over the raw schema reached 64.5%.
We ran the same 11 questions through our PyDough-based pipeline and scored the results with dbt's own comparator. Across 20 independent runs per question, our pipeline answered 220 out of 220 correctly: 100% accuracy.

We agree with the underlying conclusion of dbt's benchmark: raw DDL is not enough for reliable AI analytics. But hand-modeling that information is not the only way to provide it.
Our pipeline profiles the schema and data, captures what it learns in a PyDough metadata graph, and has the LLM generate PyDough rather than SQL. Relationships such as joins are defined once in that graph instead of being reconstructed by the model for every question.
The result is an interesting alternative: derive much of the semantic context automatically, encode it in a structured and executable representation, and remove low-level SQL decisions from the LLM's job.
In this post, we'll walk through the benchmark, how the pipeline works, and why moving more of the problem into structured metadata and an executable query layer produced more accurate results.
We followed the same basic protocol: the same 11 questions, 20 independent runs per question, and dbt's comparator as the definition of a correct answer.
There was one component we could not reproduce directly. dbt's harness executes both the gold query and generated query through an ADBC Flight SQL client connected to a dbt platform Semantic Layer environment. That requires an account, service token, and environment ID, and there is no local execution path.
So we replaced the execution layer. We built the ACME schema as a local SQLite database from dbt's DDL and seed CSVs, then swapped the Flight SQL client for a read-only SQLite executor.
Four of the 11 questions need the relationship from Agreement_Party_Role to Policy. That relationship normally passes through the missing Agreement table, so the DDL cannot describe the full path. Our pipeline has to recover it from the schema, column names, and data.
Across all 220 runs, the PyDough pipeline returned the correct result.
A standard deviation of zero deserves some scrutiny. A caching bug could produce exactly that result. That is not what happened here. Each of the 20 iterations ran in its own artifact directory with its own response cache, made fresh API calls, and recorded zero cache hits. The generated outputs also varied. Across the benchmark, the system produced an average of 11 distinct queries per question, with different aliases, join orders, and, in some cases, different traversal paths. Only the two SELECT COUNT(*) questions were byte-identical across all 20 runs.
So why does this work? To understand that, it helps to look at what makes ACME difficult in the first place.
The LLM in our pipeline does not write SQL. It writes PyDough.
PyDough is our open-source Python DSL for analytics. Instead of expressing an answer directly in terms of physical tables and joins, a query operates against a logical graph of collections, properties, and relationships.
The PyDough compiler then lowers that expression into relational operations and ultimately SQL in the dialect required by the target engine.
For example, a premium belongs to a policy, and a policy has parties. In PyDough, the generator traverses those relationships as properties. It does not reconstruct the corresponding JOIN ... ON clauses from the database schema.
That changes the generation problem in a few important ways.
GROUP BY whose grouping key sits three hops from the amount being summed. Shorter distance between the English and the code means less for the model to invent.The benchmark still ultimately executes and scores SQL. The difference is that SQL is compiler output rather than model output. But changing the output language only works if the graph contains the information the model needs. That is where most of the pipeline's work happens.
The system deliberately does as much work as possible once per database rather than rediscovering the same information for every question. It is split into an offline metadata-building stage and an online query-generation stage.

~11 calls · 1.5¢
The asymmetry is intentional. A database schema is relatively fixed. The questions users may ask against it are effectively unbounded. Anything the system can learn about the database once can be amortized across every future question.
Prompt instructions do not have that property. They have to be supplied and interpreted on every request.
That is also why the prompt itself is deliberately uninteresting. The system prompt is roughly 30 lines of output conventions: use only properties the graph defines, don't add columns the question didn't ask for, prefer a top-k operation over a max subquery, and similar rules.
There is no chain-of-thought scaffolding, self-critique loop, or tool-calling agent exploring the database at question time. The core of the system is the metadata it has available before generation starts.
dbt's benchmark makes a convincing case that raw text-to-SQL over DDL is not enough. Accurate analytical queries depend on information the physical schema often doesn't provide: how tables relate, what columns and values mean, and how business concepts map onto the underlying data.
In our pipeline, much of that context is derived from the existing schema and data, captured in a PyDough metadata graph, and reused across questions. The LLM generates against that graph rather than reconstructing joins and column meaning from raw DDL on every request. The same graph is then used to compile the query to SQL.
On this benchmark, that approach produced 100% accuracy across 220 runs, without the additional hand-built models used in dbt's modeled configuration.
The result reinforces dbt's broader point that semantic context matters, while showing a different way to provide it: derive more of that context from the underlying data and make it part of the query system itself.
You can try the same approach on your own data. PyDough-CE is fully open source and available on GitHub. Check out the repository, run the quick start, and let us know how it performs.



