Short answer: Auto Ontology vs vector database is not a same-tool choice. A vector database finds nearby text. Auto Ontology stores an agreed SQL definition for a business word, then runs that query. Similar words are not the same number: in a tiny SQLite demo on this box, a cosine-on-word-counts matcher ranked targets.revenue_goal first (~0.248) and returned 800, while summing sales.amount for Pennsylvania in June returned 157.75.
I kept two small tables in one database file. One table stored money already collected on paid orders. The other stored the revenue goal the team hoped to hit. I asked, in ordinary words, what revenue was in Pennsylvania in June. A match on similar words picked the goal. Adding the collected rows for that state and month gives 157.75. Auto Ontology is an open NVIDIA library (Apache-2.0) that writes what a business word means, and the query that computes it, then lets an agent use that writing.
Related reading on this site: Zvec vs sqlite-vec is about in-process vector search, not about agreeing a metric. For summing rows in a file of commas, see xan vs csvkit. For an agent filling office files, see OfficeCLI.
What Is a Vector Database?

A vector database (a store that finds similar text by comparing number lists) answers “what text is near this text?” It does not add dollars, and it does not know a goal from cash already collected.
A piece of text is turned into an embedding (a list of numbers that stands for that text). Two texts that share meaning should get lists that point a similar way. The usual score for “near” is cosine. Nothing in that score checks that the nearby text is the definition you wanted. A vector database fits tickets, notes, or a long policy — the RAG pattern. If the passages disagree, similarity did not pick a winner.
What Is an Ontology?
An ontology (a shared map of business words, the columns they mean, and how the tables join) is the agreement that stops “revenue” from meaning two different numbers.
SQL is how you write the agreement so a machine can rerun it. SELECT SUM(amount) FROM sales WHERE region = 'Pennsylvania' AND month = 'June' is that sentence in a form the database can execute. An ontology stores the sentence and the query together, under a name people use.
Auto Ontology stores three kinds of definition: a term (business word + columns), a SQL attribute (reviewed expression under a term), and a relationship (how tables join). People call this a semantic layer. Without it, text-to-SQL is a guess dressed up as a query.

Auto Ontology vs Vector Database
Use a vector database when you want nearby text. Use Auto Ontology when you want one number that comes from one agreed SQL definition.

They can both sit under an agent, and both can use embeddings. The difference is what happens after the nearest text is found. A vector database stops and hands you the neighbors. Auto Ontology treats the neighbors as candidates for a term, then writes SQL from the term, the reviewed expression, and the joins, then runs that SQL.
| Job | Vector database | Auto Ontology |
|---|---|---|
| Find a similar paragraph or ticket | This is the job | Wrong tool |
| Return one agreed business number | Similar words are not a definition | This is the job, after a person reviews the SQL |
| What you can check | A ranked list of texts | The query, the rows, and the steps |
| Needs a human to mark a definition correct | No | Yes, or the draft can still be wrong |
| Uses number lists | The whole store is number lists | Only to pick candidate terms, then SQL runs |
Auto Ontology does not throw embeddings away. Ingestion writes them into Postgres with pgvector. At question time the agent still searches those lists to shortlist terms. The embedding step is a shortlist. The number comes from the query.

Why Does Text-to-SQL Pick the Wrong Column?
Text-to-SQL picks the wrong column when the question and a column comment share words, even when that column is the wrong kind of money.
Checked on this box (9 November 2026, Asia/Calcutta) in an in-memory SQLite file — no API key. Sales for Pennsylvania in June were 80.00, 55.50, and 22.25. The goal was 800.00. Column comments: sales.amount said “money collected…”; targets.revenue_goal shouted “revenue revenue revenue…”. The question was what was revenue in pennsylvania in june. A tiny stand-in for an embedding counted words and took cosine:

A real embedding model will not score the comments as 0 and 0.248, because it can tell that “money collected” is about revenue. It can still lose when the goal comment is long and the sales comment is thin. The fix is a definition a person has marked, plus a query you can read.
import math, re, sqlite3
from collections import Counter
db = sqlite3.connect(":memory:")
c = db.cursor()
c.execute("CREATE TABLE sales (id INTEGER, region TEXT, month TEXT, amount REAL)")
c.execute("CREATE TABLE targets (id INTEGER, region TEXT, month TEXT, revenue_goal REAL)")
c.executemany(
"INSERT INTO sales VALUES (?,?,?,?)",
[(1, "Pennsylvania", "June", 80.00), (2, "Pennsylvania", "June", 55.50),
(3, "Pennsylvania", "June", 22.25), (4, "Pennsylvania", "July", 40.00)],
)
c.executemany(
"INSERT INTO targets VALUES (?,?,?,?)",
[(1, "Pennsylvania", "June", 800.00), (2, "Pennsylvania", "July", 800.00)],
)
catalog = {
"sales.amount": "money collected on each paid order. call this actual sales.",
"targets.revenue_goal": "revenue revenue revenue target the team hoped to reach. this is not money collected.",
}
question = "what was revenue in pennsylvania in june"
def counts(text):
return Counter(re.findall(r"[a-z0-9]+", text.lower()))
def cosine(a, b):
keys = set(a) | set(b)
dot = sum(a[k] * b[k] for k in keys)
na = math.sqrt(sum(v * v for v in a.values()))
nb = math.sqrt(sum(v * v for v in b.values()))
return 0.0 if na == 0 or nb == 0 else dot / (na * nb)
ranked = sorted(
((cosine(counts(question), counts(name + " " + comment)), name)
for name, comment in catalog.items()),
reverse=True,
)
print(ranked)
c.execute("SELECT SUM(revenue_goal) FROM targets WHERE region='Pennsylvania' AND month='June'")
print("goal", c.fetchone()[0])
c.execute("SELECT SUM(amount) FROM sales WHERE region='Pennsylvania' AND month='June'")
print("collected", c.fetchone()[0])How Do I Use Auto Ontology?
Clone the project, put an API key and passwords in an env file, load a sample database, and start the stack with Docker Compose.
git clone https://github.com/NVIDIA/auto-ontology.git && cd auto-ontology
cp .env.example .envYou need Docker with Compose, uv for the sample loader, and an API key that starts with nvapi- from the NVIDIA API catalog. The default path calls hosted models — the machine running Compose does not need a GPU.
Ports: web 3000, query 3001, ingestion 3002, MCP 3003, Postgres/pgvector 5432. Keep 3001 and 3002 private. People should come in through port 3000.

Open http://localhost:3000, sign in, turn on Semantic Compilation, and read the SQL beside every answer before you trust the number. MCP tools include check_readiness, check_answerable, and ask_question. Leave KUMO_RFM_API_KEY unset unless you mean predictive uploads to leave your database.
When Not to Use Auto Ontology
Do not use it to search documents. Do not use it if nobody will review the definitions. Do not start it if you cannot run Docker or get an API key.
If the question is “which tickets sound like this bug,” stay on a vector database. If you will not open the graph and mark terms correct, skip it — the first compile is a draft and can repeat the 800 mistake in a nicer screen.
Common questions about Auto Ontology vs vector database
Does Auto Ontology replace a vector database?
No. It uses embeddings to shortlist terms, then SQL for the number. Keep a vector store for similar documents.
Can I use Auto Ontology without a GPU?
Yes on the default hosted-model path. You need the API key and network access to the endpoint.
Which databases does it connect to?
PostgreSQL, MySQL, Databricks, Snowflake, ClickHouse, Trino, Apache Kyuubi, HeavyDB, DuckDB, and SQLite. The sample path uses Postgres, which also stores the ontology map.
Is a certified definition a hard stop?
No. It is a reviewed expression the agent prefers. The useful stop is refusing when no term covers the question.