Ask a question that stays inside one system — "what's on order 8812?" — and you get an answer in seconds. Ask one that crosses them — "this supplier just slipped a week, which customers do I need to call?" — and someone loses an afternoon opening four tools and rebuilding the chain from memory.
That second question is why ontologies exist. Your systems are good at recording things — parts, orders, shipments. Almost none of them record how those things connect, so the connections live in the heads of the five people who've been there a decade, and nowhere a machine can read. An ontology is where you write them down.
Gruber's textbook definition — "an explicit specification of a conceptualization" — is precise and useless the first time you read it. So here's a concrete one instead. Meet Meridian, a mid-size maker of industrial equipment; this is its ontology:
Read it out loud and it's almost boring: a Supplier supplies a Part; a Part can be a subpart_of another Part; a Part is used_in a Product; an Order contains Products and is placed_by a Customer. Boring is the point. Everyone in the company now means the same thing by "part" and "order", and a machine can follow those arrows without guessing.
That's the whole idea. The rest of this post is what actually goes inside ontology, how it relates to a knowledge graph, where it pays for itself, how you build one with LLM, and — the part most write-ups skip — how you actually use it to answer questions.
If you've ever designed a database, that picture looked awfully familiar. Boxes for entities, labelled lines for relationships, a note about cardinality — that's an ER diagram, and people have been drawing them since Peter Chen's paper in 1976.
The resemblance isn't a coincidence. ER modelling and the frame/semantic-network research that turned into ontologies came out of the same 1970s push to model meaning rather than storage. "Entity type / relationship type / cardinality" and "class / object property / cardinality restriction" are the same three ideas wearing different vocabulary. And I'll be honest up front: plenty of shipped enterprise ontologies really are ER diagrams living in a graph database, with the logic layer left thin — and they still pay off, because a shared vocabulary alone solves real problems.
But four differences are genuine, and they matter later in this post:
1 · Open world, not closed world. A database assumes anything not in the table is false — no row, no fact. An ontology assumes a missing fact is unknown, not untrue. Related: databases assume unique names (two different keys mean two different things), ontologies don't — which is exactly what lets you declare that Salesforce's cust_id and the billing system's account refer to the same real customer without restructuring either system.
2 · Axioms infer; constraints reject. An axiom is just a rule declared in the model — it's the ontology world's word for one, borrowed from maths. "Every Part has exactly one primary Supplier" as a database constraint is a UNIQUE foreign key — record a second one and the insert fails. The same sentence in OWL is generative: record two, and rather than erroring the reasoner concludes the two names must denote the same supplier. Same English, opposite behaviour — and it surprised so many people that SHACL exists to bring the reject-it behaviour back.
3 · There's a reasoner. An ER diagram has no runtime. Transitivity, subclass inheritance, property chains — these get computed. The "which customers are affected" walk in §07 is a recursive query you'd hand-write per question in SQL; here it falls out of one axiom.
4 · It sits above your systems, not inside one. An ER model describes one application's storage and is prescriptive — it's a build order for tables. An ontology describes a domain across every system and is descriptive — it says what's true, not where the bytes live. Practical consequence: changing an ER schema is a migration; extending an ontology is usually additive.
The one-line version: an ontology is an ER diagram plus an open-world assumption plus a reasoner. Strip those two away and you have an ER diagram — which, again, is a perfectly respectable thing to ship.
So if you were handed an ontology file tomorrow, what would be in it? Six things. The first two are the ones everybody draws; the last four are what separate a real ontology from a picture.
Supplier, Part, Product, Order, Customer. Concepts that span every system you own, not rows in one table. Usually arranged in a subclass hierarchy: a CastingPart is a Part.supplies, used_in, placed_by. In RDF these are object properties, and each declares a domain (what it goes from) and a range (what it goes to). This is where an ontology earns its keep; a class list alone is a glossary.Part.lead_time_days, Order.value, Customer.tier. Called data properties, with a datatype and often an allowed range.subpart_of is transitive", "a Part is never a Product". Two flavours worth separating: axioms that let a reasoner derive new facts, and shapes that validate incoming data and reject what doesn't fit.Two families cover most of what you'll meet, and they're different bets rather than dialects. Here's one slice of Meridian's ontology written each way:
Same model, two philosophies. RDF/OWL (plus SHACL to validate and SPARQL to query) is the W3C stack — portable, genuinely reasoner-backed, and the only place where "transitive" is something you declare rather than a query you remember to write. The cost is verbosity and a twenty-year reputation for being academic. A vendor object model — Palantir's object / link / action types, or a metrics layer like dbt's — hands you mappings, permissions and tooling out of the box, in exchange for living on someone's platform.
One thing to notice: only the vendor column has an action type. notifyCustomer is about as simple as one gets — tell a customer their order is going to be late. It's a verb, so that model records what you can do, not just what exists. That turns out to matter, and it comes back in §05.
This is the single most common point of confusion, so let's kill it cleanly. The ontology is the schema — classes, relationships and rules. Fill it with actual suppliers and actual orders and you get a knowledge graph — the instances.
The sizes are wildly different, and that asymmetry is the useful part: the ontology is a few hundred lines a human can hold in their head and it changes slowly; the knowledge graph is millions of nodes and it changes constantly. Keeping them separate is what lets you validate a churning dataset against a small, trusted model.
1The ontology on its own is completely empty of data. It says a Supplier can supply a Part. It doesn't know a single supplier's name. This is the artifact a human writes and signs off on.
2Now pour in real instances and you have a knowledge graph. Every edge conforms to a relationship the ontology declared — that's the contract, and it's checkable.
3Two ways to fill it, and most write-ups only mention the first. Materialize and you build a real graph. Virtualize and no data moves at all — the ontology is a live view over the databases you already have, and your graph query is rewritten into SQL on the fly.
That third step deserves a name, because it's a whole discipline: ontology-based data access. You declare mappings (in RDF-land, the standard is R2RML) that say "the parts table's sku column is a :Part", and a query engine turns SPARQL over the ontology into SQL over the real tables. Nothing is copied and nothing goes stale. The trade-off is that you inherit your source databases' performance, and the heavier reasoning tricks stop being practical. Plenty of production systems run a hybrid — virtualize the transactional stuff, materialize the extracted-from-documents stuff.
Enough anatomy — what does it get you? I'd argue there are exactly four wins, and they build on each other. Every enterprise has at least the first two.
The default enterprise state: every system has its own model, "customer" in the CRM isn't "account" in billing isn't "buyer" in the order system, and joining them is a bespoke project every single time — n systems means n² point-to-point integrations. With an ontology each source maps once to shared concepts, and after that everything speaks the same language. New system? It plugs into a model that already exists.
This is the one a pile of tables genuinely cannot do. Because relationships are typed and rules are declared, a machine can follow the arrows and derive conclusions that were never stored anywhere. "Which customers are exposed if Kessler-GmbH misses a shipment?" is not in any table; it's four hops and a transitivity rule away. I'll walk that whole chain in §07.
"Active customer" gets defined once, as a rule, instead of ten times across ten dashboards that quietly disagree until someone challenges the numbers. And because the definition is machine-readable, a validator can flag the records that violate it — an ownerless part, an order with no customer — rather than waiting for a human to notice.
Point an agent at raw tables and it guesses what things mean, then confidently invents relationships. Point it at a typed graph and it traverses real, named edges — and can show you the path it took. This is the newest reason and the one driving the current wave of interest; §08 has the numbers.
notifyCustomer in the model next to Order means an agent can be handed a governed verb, not just a read-only view. Whether or not you buy the platform, it's the most useful idea in their write-up — and it's why the vendor column back in §03 had an action type in it.Being even-handed: if you have one application, one clean schema, and nobody asking cross-system questions, an ontology is pure overhead. A database already models that fine. The failure mode is real and has a name — boiling the ocean, a two-year effort to model everything perfectly before anything ships. A tiny ontology in production beats a magnificent one in a slide deck. More on the honest ledger in §09.
Here's the history in one sentence: for thirty years ontologies were right in theory and dead in practice, because building one meant knowledge engineers who spoke OWL and domain experts who knew the business, locked in a room for months. That's the wall LLMs knocked down — but how you use them splits into two genuinely different approaches, with different failure modes.
The core idea: a human authors the ontology — it's small — and the LLM is never allowed to invent a type. It reads documents and emits instances, constrained to the classes and relationships you declared. Everything it produces is validated against the schema before it lands. This is the lowest-hallucination option and the one I'd default to.
1Two inputs. On the left, the small ontology a person wrote and owns. On the right, a real email — free text, names scattered through a paragraph. Multiply the right side by a few hundred thousand and you see why humans never finished tagging these.
unmapped — do not invent a type. Emit triples.2The model reads the prose and emits typed triples — constrained by the ontology, so it can only use types that exist. That constraint is what stops it inventing a "bearing situation" class. Note the escape hatch: anything that doesn't fit goes to unmapped rather than getting forced into the nearest type.
promised_date property3A validator checks each triple before it lands. Clean ones flow in; a brand-new supplier and an unmappable date get held. The model proposes, the schema and a human dispose — and the flagged leftovers are how you learn what the ontology is still missing.
Strong option, and the one with the best evidence behind it — this is essentially what Text2KGBench measures and what ontology-grounded RAG systems assume. The limitation is right there in the name: it can only find what you thought to model. If your ontology has no concept of "regulatory hold", every mention of one becomes unmapped noise. Which is what the next approach is for.
Flip it around. Give the LLM no vocabulary at all and let it name whatever entities and relations it sees, document by document. You get a sprawling mess of near-duplicate types — supplier, vendor, parts supplier — and then a second pass clusters and generalises them into an actual schema. AutoSchemaKG is the clearest recent example of inducing a schema this way rather than authoring it. GraphRAG sits nearby but isn't quite the same thing — it ships with a short list of generic default entity types you're expected to replace, so it's loosely typed rather than genuinely schema-free.
The appeal is genuine discovery: it surfaces concepts nobody thought to model, which is exactly what a schema-first pipeline is blind to. The costs are that quality now rests entirely on the clustering step, there's no validation gate anywhere, and open-domain runs tend to over-fragment — you end up with hundreds of entity types where a few dozen would do, and collapsing them is its own project. Useful, but not something I'd point at a production graph unsupervised.
Here's the loop I'd actually run:
You've built the thing. What do you point at it? In practice the questions fall into four types, and they're answered by genuinely different machinery — which is worth knowing, because people often build an ontology expecting it to help with type 3 and are surprised when it doesn't, on its own.
"Who supplies the A40 bearing, and what's the lead time?"
A direct traversal. One or two hops from a known node. This is what a graph database is fastest at, and honestly a normal SQL join would do it too.
→ SPARQL traversal
"If Kessler slips a week, which customers are exposed?"
Multi-hop, and it needs the rules — transitivity through sub-assemblies means the chain has no fixed length. This is the one an ontology is genuinely uniquely good at.
→ reasoner + traversal
"What's our total exposed order value this quarter?"
Sums, counts, group-bys. The graph doesn't magically do arithmetic — but the ontology gives the query generator correct joins and one agreed definition of "exposed".
→ query generation over the model
"Reallocate stock from the X7 line to cover Order-8812."
Not a question at all — a governed write, back into the source systems. Only exists if your model includes verbs, per §05.
→ action type / writeback
Let's walk the inference case properly, because it's the one you can't fake with a join. A supplier emails to say a shipment slips. Nobody has ever written down which customers that affects — the fact doesn't exist anywhere. Watch it get computed:
1Five local facts and one general rule. Nowhere does it say Halden Marine is at risk — nobody connected those dots, and nobody maintains a "what-breaks-if" spreadsheet.
2The reasoner walks it. Because subpart_of is transitive, the delay ripples through however many layers of sub-assembly exist — four levels deep or one, the same rule covers it. This is inference: new true facts, computed rather than stored.
3Blast radius, customers, and the euro figure — all from traversing typed edges and applying one rule. And crucially the system can show its path, so a human can check the reasoning rather than trusting a number.
One line to keep: a database tells you what you stored; an ontology tells you what follows from it.
Now the case people ask about most, and where I want to be careful not to oversell. "What's our total exposed order value this quarter?" is arithmetic. A graph doesn't do arithmetic better than a database does. So what's the ontology actually contributing?
The answer is that it's not helping the computer compute — it's helping the LLM write a correct query. Ask a model to write SQL against 200 raw tables named ord_hdr_t and cust_mstr and it has to guess which join is right and what "exposed" means. Give it a model where Order placed_by Customer is declared and "exposed" is a defined rule, and most of the guessing disappears.
This distinction has been measured, and the numbers are the strongest argument in this whole post — which is where §08 goes.
Two separate stories here, often muddled together. One is about retrieval — feeding an LLM better context. The other is about querying — getting a correct number out of a database. The ontology helps with both, differently.
Vanilla RAG embeds your question, grabs the nearest text chunks, and hopes the answer is in there. It has no idea that Bearing-A40 and Pump-X9 are related, because relationships aren't something embeddings represent well. Graph retrieval lands on the right node and then traverses typed edges to pull in the connected neighbourhood — which is the exact thing chunk similarity can't do. I've covered the mechanics of that in the GraphRAG post, so I won't repeat it; the ontology's contribution is that the graph being traversed has meaningful, validated types instead of whatever the extractor happened to invent.
Does that grounding actually help? OG-RAG (EMNLP 2025) anchors retrieval in a domain ontology and reports +55% fact recall and +40% response correctness against standard RAG across four different LLMs, plus faster attribution back to sources. Worth reading with the usual caution about self-reported gains, but the direction is consistent with everything else here.
This is the more interesting shift. An enterprise agent doesn't want raw table access — that's both dangerous and useless. What it wants is a small set of typed tools over a model it can understand. The ontology is that surface: objects to search, links to traverse, rules to check, and (if you modelled the verbs) actions to invoke — each inheriting the same permissions a human would have.
1Start with what's actually in the prompt. The entire ontology fits — a few classes and rules is a page of text. The knowledge graph it describes never enters context at all. That asymmetry is the whole trick: the agent reasons over the model and queries the data.
Supplier is a real2First move is always resolve, never guess. The agent turns the string "Kessler" into a real object with a real ID, and every later call keys off that ID. Forty tokens back — one object, not a page of search results.
* = any depth, so a bearing3Here's what traverse really is: the agent names a path through the ontology, and the engine compiles it into a graph query. It can write the whole path in one call here because the model is tiny — five classes, one sensible route from Supplier to Customer, and all of it in context since step 1. That subpart_of* is the transitivity rule from §07, so the agent never has to know how deep the assembly tree goes.
via string is the receipt —4Only the endpoints come back, plus the path that produced them. Millions of edges were walked inside the store; ninety tokens crossed into the model. And because the traversal is recorded, every claim downstream can be traced back to it.
5The euro figure is computed, not generated. An LLM asked to total three order values will usually get it right and occasionally won't; a store asked the same question is right every time. This is the §07 aggregation case, and it's why a defined metric beats a clever prompt.
6Pause here, because this is the argument. Three tool calls put six typed facts and one number in front of the model — no prose, no chunks, nothing to misread. The agent has never read a document.
7The write is checked against the schema, the caller's own permissions, and a policy — then staged, not fired. The answer carries its traversal path, so anyone can check the reasoning instead of trusting it. The agent proposes; the model and a human dispose.
traverse call. Two honest caveats, since the shape of it is doing a lot of work here. The signature is illustrative — there is no standard traverse API — though the path string itself is real: supplies/subpart_of*/used_in/contains is SPARQL property-path syntax, where / means "then" and * means "any number of times". Neo4j's apoc.path.expand takes much the same arguments. The common alternative is a plain depth argument — "everything within three hops" — which is simpler but drags every unrelated neighbour into context; naming the path and the return types is what keeps the answer down to five objects. And it rarely composes in one call once a model has hundreds of classes. Expect instead: the agent walking a hop at a time, picking the next from whatever came back; asking the schema what links out of Supplier before planning; letting the engine solve the route with something like path_between(Supplier, Customer); or — most common in production — calling impactOf(supplier), a traversal some human authored once. That last one is the least glamorous and by far the most reliable.That staged-write pattern is the core of what Palantir calls connecting agents to decisions — proposed changes packaged into a sandboxed scenario, with the same row- and column-level policies applied to an agent as to a person. You don't need their platform to copy the shape: typed tools, permissions inherited from the caller, writes staged not executed.
Here's the evidence I find most persuasive, and it's a clean progression. Sequeda and colleagues built a benchmark on a real insurance schema — 13 gnarly tables of policies, claims and coverages — and asked GPT-4 enterprise questions two ways: writing SQL straight against the tables, or writing SPARQL against a knowledge graph with an OWL ontology over the same data. Then a follow-up added a checker that uses the ontology to catch queries that are semantically wrong, and lets an LLM repair them in a loop:
Same questions, same data, same model. The last bar includes 8% that the system answered with an honest "I don't know" rather than a guess.
Two things stand out. First, 16% to 54% is not a tweak — that's the difference between unusable and useful, purely from giving the model a semantic model instead of raw column names. Second, look at that 8%: the checker's real contribution isn't only more right answers, it's converting some wrong answers into admitted ignorance, which in an enterprise is worth a great deal more than the accuracy points suggest.
A caveat worth stating: these are single-benchmark results on one insurance schema, and frontier models have improved a lot since. dbt re-ran a similar comparison in 2026 and found raw text-to-SQL now lands at 84–90% while a governed semantic layer hits 98–100%. The gap narrowed — but their finding about how the two fail is the part that matters: the semantic layer refuses when a question is out of scope, while text-to-SQL returns a confident, plausible, wrong number. Note also that dbt's semantic layer is a metrics model, not an OWL ontology; it's a weaker artifact than what we've been discussing, which makes the direction of the result more telling, not less.
Ontologies are a 1990s idea that spent two decades being technically correct and practically ignored, because building and populating one cost more than it returned. Two things changed at once. LLMs made them far cheaper to build and populate — and, for the first time, gave us a consumer that's desperate to use one. Supply and demand for structure flipped together.
But let me be even-handed before the verdict, because I've mostly been selling the upside:
So — should you build one? The call on one screen:
| Situation | Verdict | Why |
|---|---|---|
| Recurring "whose definition is right?" fights across teams | Build one | A shared semantic layer is exactly the fix, and the pain is already paying for it |
| Questions that hop across systems — impact, exposure, dependency | Build one | Inference over typed edges is the thing a pile of tables genuinely cannot do |
| Agents answering data questions where a wrong number is expensive | Probably | Big accuracy gain, and more importantly it can say "I don't know" instead of guessing |
| Open-ended exploration across data you haven't modelled | Not yet | An ontology only answers what it covers; you'd hit "out of scope" constantly |
| One app, one clean schema, no cross-system questions | Skip it | A database already models this fine — this would be overhead with no payoff |
| You want to "model everything" before shipping anything | Stop | That's the ocean-boiling trap. Pick one question and model only what answers it |
If I compress it to one path: write down the questions first, model only the classes those questions need, let an LLM fill the graph but validate every triple on the way in, keep a human on the axioms, and put it in front of a real query before it's pretty. The teams that succeed treat the ontology as a product with an owner, not a project with an end date — and they start absurdly small.
Model the questions you have, not the world you imagine.
These are living notes — I'll keep updating as the pattern matures. Thanks for reading.