Text-to-SQL with a semantic layer: NVIDIA Auto Ontology tested

On this page
NVIDIA Auto Ontology is an open-source library that aims to make text-to-SQL reliable. It reads the metadata of your databases and builds a semantic layer from it: business terms such as "customer" or "invoice line", the paths by which tables join, and reviewed SQL expressions for metrics. An agent then answers natural-language questions through that layer instead of guessing from the raw schema.
We tried Auto Ontology on Microsoft's Wide World Importers sample database with the hosted models from build.nvidia.com. The short version: the automatically generated ontology is impressive, and questions that span three to five tables work. With the hosted models, though, it currently needs three code changes, and two of four answers were wrong in a way the answer itself didn't show. This post explains the concept, walks through the setup and its pitfalls, and shows our results.
Why text-to-SQL needs a semantic layer
A language model asked to write SQL starts out seeing only tables and columns.
It doesn't know that "revenue" in your database means extendedprice on the
invoice lines and not the amount in the accounting table. It doesn't know how a
state connects to an invoice either. With a small schema you can explain that
in the prompt. With dozens of tables, archive copies, history tables and
similar-sounding columns, the model guesses, and the result still looks
plausible.
The usual answer is a semantic layer: a model of the business concepts that defines what a metric means and how it is calculated. In projects this is usually maintained by hand, for example as metrics in dbt or a BI tool. We described the manual approach in our post on a text-to-SQL agent for BigQuery. Auto Ontology tries to generate this layer automatically and then have people review it.
How Auto Ontology works
The ontology holds three kinds of definitions:
- Terms: business concepts such as Customer, Invoice or Stock Item, each with a description, synonyms and the columns that hold them.
- Relationships: how tables join, including bridge tables, inferred from keys and from the data.
- SQL attributes: reviewed SQL expressions under a term, such as a margin or a rolling total. The agent reuses them, so the same metric is always computed the same way.
The work happens in three stages:
How Auto Ontology works: generate, certify, answer
- Generate: an ingestion service reads schemas, column profiles and sample values, derives terms table by table, detects join paths and suggests SQL attributes. Everything is stored in Postgres, with embeddings for retrieval in pgvector.
- Certify: domain experts test with real questions, correct terms and SQL attributes in the web UI and mark them as certified.
- Answer: for each question the agent works out the intent and the terms it mentions, finds matching terms, columns and SQL attributes by embedding search, writes SQL, checks filter values against the database, repairs the SQL when a check fails and runs it. It returns the answer, the SQL and the steps it took.
On top of that there is a web UI, a REST API and an MCP server that lets other agents use the ontology, for example to check up front whether a question can be answered from the available data at all. Our FastMCP guide covers how MCP servers work in general.
In the web UI you can explore the generated ontology as a graph. Each circle is a term, each line a detected relationship:
The generated Wide World Importers ontology as a graph
For knowledge that lives in documents rather than database schemas, the Neo4j LLM Knowledge Graph Builder builds a similar graph from PDFs and web pages.
The project is Apache 2.0 licensed, has no tagged release yet and, according
to its README, does not accept external contributions at the moment. We tested
the state of 4 November 2026 (commit
2a24f5d,
package version 1.1.0).
Setup with Docker Compose
The official path in the README is Docker Compose. You need Docker with
Compose v2, uv and an API key from
build.nvidia.com. The key values in .env:
Then start Postgres, load the sample database and build the rest:
Open http://localhost:3000, sign in with the admin account from .env and
turn on compilation under Settings, Semantic Compilation. Ingestion runs at
startup and compilation right after it.
The defaults are nvidia/nemotron-3.5-lightning-30b-a3b for all language model
tasks and nvidia/nemotron-3.5-embed-1b for embeddings. Each role (reasoning,
extraction, embeddings, reranking) can have its own endpoint, model and key,
including self-hosted NIMs.
Three pitfalls with NVIDIA's hosted models
With the hosted models on build.nvidia.com, Auto Ontology did not get through at first. The causes sit between the code and the hosted endpoints, so they affect the Compose setup too. We reproduced each one directly against the API.
1. Ingestion reports success but creates no embeddings. The log says "Data
ingestion finished successfully", next to zero embeddings and hundreds of
"HTTP 500, service inference failed" errors. Auto Ontology sends 32 texts per
embedding request. In our tests, the hosted endpoint for
nemotron-3.5-embed-1b answered most requests with several texts with a 500,
while one text per request worked reliably, even with 16 requests in parallel.
Very long single texts also failed despite truncate: END.
2. Structured output is rejected. For NVIDIA models, Auto Ontology uses
LangChain's ChatNVIDIA client. It sends the requested JSON schema as
nvext.guided_json, and the hosted endpoint answers with HTTP 400: "unknown
field guided_json". The OpenAI-compatible route, response_format with
json_schema, works.
3. The model thinks its way into the token limit. Nemotron 3.5 reasons
before every answer. For a small JSON answer that took more than 900 tokens in
our test, and on larger tasks it ran into the 8,192-token limit
(LengthFinishReasonError). Compilation became very slow as a result. With
chat_template_kwargs: {"enable_thinking": false} the same answer took around
40 tokens and less than a second.
Our workarounds target exactly these points: one text per embedding request
with 16 requests in parallel, texts cut to 4,000 characters, NVIDIA models
routed through the existing ChatOpenAI branch, and thinking turned off. These
are workarounds for the tested commit, not official fixes. Compose builds the
services from the local source, so apply them in the repository before
docker compose up -d --build:
After that, the sample database's 640 embeddings went through in 14 seconds without errors. The run was not entirely free of token limits: a few steps still hit them, but Auto Ontology recovered with retries and a second attempt through the reasoning client.
What the test showed
Compiling the 51 tables of Wide World Importers took eight and a little over ten minutes in two runs (504 and 621 seconds) and produced 51 and 52 terms, including Customer, Invoice, Invoice Line, Order and Stock Item. One thing stood out: archive tables became terms of their own, for example "Buying Group Archive" next to "Buyinggroups". That kind of duplicate has to be cleaned up during certification, or the agent may pick the wrong table when in doubt. In the term list, every generated term starts as "Pending Approval":
Generated terms in Auto Ontology, none of them certified yet
We then asked four typical analytics questions and checked the generated SQL against the database ourselves. Each question took between half a minute and almost seven minutes.
| Question | SQL | What happened |
|---|---|---|
| Revenue for a specific product in Pennsylvania in June 2015 | wrong | state filter missing |
| Top five customers by invoice value in 2015 | correct | |
| Orders per month in 2016 | correct | |
| Top five stock items by quantity sold in 2016 | wrong | counted from the wrong table |
The first question is the example from the README. The agent's SQL (line breaks added for readability):
Product and period are right, the state is missing. The result was revenue across all states: $5,225.60 instead of $588.80. The correct answer needs the path from invoice through customer and city to state, which the README shows in its example. The agent's answer described product and period correctly and simply didn't mention the state. If you only read the answer, you won't notice.
For the quantity question the agent used the stock movements table, which also contains goods received, instead of the invoice lines. That is a textbook case for a certified SQL attribute "quantity sold": once it is defined, the agent stops working it out from scratch each time.
The two correct answers show what works well: the agent writes clean joins across several tables, monthly grouping and sorting with a limit, and it always returns the SQL. That is what makes checking the answer possible in the first place. Here is the answer to the orders-per-month question in the chat:
An Auto Ontology chat answer with SQL and the result table
Below each answer, Auto Ontology lists the agent's steps, from classifying the question and picking tables to validating the SQL. If you need to check an answer, that is where you see why the agent chose a table:
The agent's steps behind an answer
What to settle before you use it
The test and the README point to four things:
- Read-only database access. Auto Ontology does not check by itself whether
the generated SQL only reads. When we asked "Delete all invoices from
2013.", the agent generated and ran
DELETEstatements in our test. Nothing was deleted only because of the sample database's foreign keys. The quickstart connects the agent as the Postgres superuser. In a real deployment,CONNECTION_STRINGSshould use a user that can only read, or a read replica. - Protect the internal services. According to the README, the backend (port 3001) and the ingestion service (3002) belong on a private network. The backend trusts the user identity the frontend forwards in a header, and the ingestion service has no authentication of its own. People and agents should only get in through the frontend on port 3000.
- Plan for certification. The generated terms are a draft. Before numbers go into reports, domain experts should check the most important terms and metrics against reference queries and certify them.
- Be realistic about response times. With the hosted models some questions took several minutes. We haven't tested whether self-hosted NIMs or another endpoint speed this up significantly.
Our take
The most interesting part of Auto Ontology is the automatic generation. In eight to ten minutes, 51 tables turned into an ontology with terms and join paths that an agent could use right away. That modeling is otherwise tedious manual work.
In our view the project is not ready for production yet: there is no release, the hosted models need code changes, and half of our test questions got wrong SQL behind a plausible-sounding answer. That is not specific to Auto Ontology; it applies to text-to-SQL in general. Auto Ontology does bring the right tool against it, though: certification of terms and SQL attributes by domain experts. It is already worth evaluating on your own data, as long as you take that certification step seriously.
If you want to bring text-to-SQL to your company's data, we're happy to help with tool selection, the data model and setting up the review process. Get in touch. Our post on the BigQuery MCP server shows how to make BigQuery data available to agents over MCP.
Further reading
- RAG, embeddings and vector search with Google BigQuery
- Using AI directly from your PostgreSQL database with pgai
Interested in building high-quality AI agent systems?
We prepared a comprehensive guide based on cutting-edge research for how to build robust, reliable AI agent systems that actually work in production. This guide covers:
- Understanding the 14 systematic failure modes in multi-agent systems
- Evidence-based best practices for agent design
- Structured communication protocols and verification mechanisms



