Ask a question inside one system, like "what's on order 8812?", and you get an answer in seconds. Ask one that crosses systems, like "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 record things: parts, orders, shipments. Almost none 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.
Forget Gruber's textbook definition, "an explicit specification of a conceptualization". Here's a concrete one instead. Meet Meridian, a mid-size maker of industrial equipment; this is its ontology:
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 goes inside one, how it relates to a knowledge graph, where it pays for itself, how to build one with an LLM, and how to actually use it, which is the part most write-ups skip.
If you've ever designed a database, that picture looks familiar: boxes for entities, labelled lines for relationships, a note about cardinality. That's an ER diagram, drawn since Peter Chen's 1976 paper.
The resemblance isn't a coincidence: both 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 in different vocabulary. And honestly, plenty of shipped enterprise ontologies really are ER diagrams living in a graph database, with the logic thin, and they still pay off.
But three differences are genuine, and they matter later in this post:
1 · Domain, not system. An ER diagram in practice describes one system's storage: its tables, its keys. An ontology describes the business domain across every system, independent of any database. Prescriptive for one app's tables, descriptive of what's true anywhere. Changing an ER schema is a migration; extending an ontology is usually additive.
2 · Axioms infer; constraints reject. "Every Part has exactly one primary Supplier" as a UNIQUE foreign key rejects a second one as a database constraint. But as an axiom, the same sentence makes the reasoner conclude the two names denote the same supplier. Same English, opposite behaviour.
3 · There's a reasoner. Transitivity, subclass inheritance, property chains: an ER diagram has no runtime, but an ontology computes them. The §07 exposure walk is a recursive query you'd hand-write per question in SQL; here it falls out of one axiom.
The one-line version: an ontology is an ER diagram plus a reasoner. Strip that 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. 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.The most widely used way to write one in practice is the vendor object model, and Palantir's is the reference implementation:
Three kinds of types: objects (things that exist, like Part), links (relationships like usedIn), and actions (verbs like notifyCustomer). Each object carries a key mapping back to real source data, here sku from erp.parts_tbl. You get mappings, permissions and tooling out of the box, in exchange for living on their platform.
One thing to notice: the model records an action type. notifyCustomer is about as simple as one gets: tell a customer their order is going to be late. A verb, so the model captures what you can do, not just what exists. It comes back in §05.
The 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 ontology is a few hundred lines a human can hold in their head and it changes slowly; the knowledge graph is millions of nodes that change constantly. Keeping them separate 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, but knows no 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: the ontology is a live view over your existing databases, and graph queries get rewritten into SQL on the fly.
That third step is a whole discipline: ontology-based data access. You declare mappings (the standard is R2RML) that say "the parts table's sku column is a :Part", and the query engine turns SPARQL over the ontology into SQL over the real tables. Nothing is copied, nothing goes stale; you just inherit your source databases' performance. Plenty of production systems run a hybrid: virtualize the transactional stuff, materialize the extracted-from-documents stuff.
Enough anatomy. What does it get you? Four wins, and they build on each other.
Today, "customer" in the CRM isn't "account" in billing, 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 a new system 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 derives conclusions that were never stored anywhere: "which customers are exposed if Kessler-GmbH misses a shipment?" is four hops and a transitivity rule away. Full walk in §07.
"Active customer" gets defined once, as a machine-readable rule, instead of ten times across ten dashboards that quietly disagree. A validator then flags the violations (an ownerless part, an order with no customer) instead of 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. §08 has the numbers.
notifyCustomer next to Order means an agent gets a governed verb, not just a read-only view. It's the most useful idea in their write-up, and it's why §03's model has an action type.Being even-handed: one application, one clean schema, nobody asking cross-system questions, and an ontology is pure overhead; a database already models that fine. The failure mode has a name: boiling the ocean, modelling everything perfectly before anything ships. A tiny ontology in production beats a magnificent one in a slide deck.
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 your declared classes and relationships, and everything it produces is validated against the schema before it lands. It's the lowest-hallucination option and the one I'd default to.
1Two inputs. Left, the small ontology a person wrote and owns. 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 emits typed triples, constrained by the ontology, so it can only use types that exist. That stops it inventing a "bearing situation" class. 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 new supplier and an unmappable date get held. The model proposes, the schema and a human dispose, and the flagged leftovers show what the ontology is still missing.
Strong option, and the one with the best evidence behind it: it's essentially what Text2KGBench measures and what ontology-grounded RAG assumes. The limitation is in the name: it can only find what you thought to model. No concept of "regulatory hold"? Every mention becomes unmapped noise. Which is what the next approach is for.
Flip it around: give the LLM no vocabulary and let it name whatever it sees, document by document. You get a sprawling mess of near-duplicate types (supplier, vendor, parts supplier), then a second pass clusters them into an actual schema. AutoSchemaKG is the clearest recent example. GraphRAG sits nearby but isn't quite the same: it ships generic default entity types you're expected to replace, so it's loosely typed rather than schema-free.
The appeal is genuine discovery: it surfaces concepts nobody thought to model, which a schema-first pipeline is blind to. The costs: quality rests entirely on clustering, there's no validation gate, and open-domain runs over-fragment, leaving hundreds of entity types where a few dozen would do. Useful, but not for an unsupervised production run.
You've built the thing. What do you point at it? Four types of questions, answered by genuinely different machinery. 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: what a graph database is fastest at. Honestly, a normal SQL join would do it too.
→ SPARQL traversal
"If Kessler slips a week, which customers are exposed?"
Multi-hop, needs the rules: transitivity means the chain has no fixed length. The one an ontology is genuinely uniquely good at.
→ reasoner + traversal
"What's our total exposed order value this quarter?"
Sums and 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. It's 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. Watch it get computed:
1Five local facts and one general rule. Nowhere does it say Halden Marine is at risk, 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 deep or one, same rule. This is inference: new true facts, computed rather than stored.
3Blast radius, customers, and the euro figure, all from typed edges and one rule. Crucially, the system can show its path, so a human checks the reasoning instead of trusting a number.
One line to keep: a database tells you what you stored; an ontology tells you what follows from it.
The case people ask about most, 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. So what's the ontology contributing?
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 (ord_hdr_t, 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, often muddled together: retrieval (feeding an LLM better context) and querying (getting a correct number out of a database). The ontology helps with both, differently.
Vanilla RAG embeds your question, grabs the nearest chunks, and hopes the answer is in there. It has no idea that Bearing-A40 and Pump-X9 are related: relationships aren't something embeddings represent well. Graph retrieval lands on the right node and traverses typed edges into the connected neighbourhood, which chunk similarity can't do. (Mechanics in the GraphRAG post.) The ontology's contribution: the graph has meaningful, validated types instead of whatever the extractor invented.
Does the grounding help? OG-RAG (EMNLP 2025) anchors retrieval in a domain ontology and reports +55% fact recall and +40% response correctness over standard RAG across four LLMs, plus faster attribution. Caution about self-reported gains applies, but the direction matches everything else here.
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, and 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 in the prompt: the entire ontology fits in a page of text, and the knowledge graph never enters context. That asymmetry is the whole trick: the agent reasons over the model and queries the data.
Supplier is real:2First move is always resolve, never guess: "Kessler" becomes a real object with a real ID, and every later call keys off it. 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 because the model is tiny and all of it is in context. That subpart_of* is the transitivity rule from §07, so the agent never has to know how deep the tree goes.
via string is the4Only the endpoints come back, plus the path that produced them. Millions of edges walked inside the store, ninety tokens crossed into the model. And because the traversal is recorded, every claim downstream can be traced to it.
5The euro figure is computed, not generated: an LLM asked to total three values will usually get it right and occasionally won't, a store never misses. The §07 aggregation case, and why a defined metric beats a clever prompt.
6Pause here: this is the argument. Three tool calls put six typed facts and one number in front of the model, no prose, 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. The agent proposes; the model and a human dispose.
traverse call. The signature is illustrative (there is no standard traverse API), though the path string is real: supplies/subpart_of*/used_in/contains is SPARQL property-path syntax, where / means "then" and * means "any number of times". The common alternative, a plain depth argument ("everything within three hops"), is simpler but drags every unrelated neighbour in; naming the path and return types keeps the answer 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, asking the schema what links out of Supplier before planning, 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. Sequeda and colleagues built a benchmark on a real insurance schema (13 gnarly tables) and asked GPT-4 enterprise questions two ways: SQL straight against the tables, or SPARQL over a knowledge graph with an OWL ontology on the same data. A follow-up added a checker that catches semantically wrong queries and lets the LLM repair them in a loop:
The questions, data, and model were identical across all three runs. 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 the difference between unusable and useful, purely from giving the model semantics instead of raw column names. Second, that 8%: the checker's real contribution is converting wrong answers into admitted ignorance, which in an enterprise is worth more than the accuracy points suggest.
A caveat: single-benchmark results on one insurance schema, and frontier models have improved since. dbt re-ran a similar comparison in 2026: raw text-to-SQL now lands at 84 to 90%, a governed semantic layer at 98 to 100%. The gap narrowed, but how the two fail is what matters: the semantic layer refuses out-of-scope questions, while text-to-SQL returns a confident, plausible, wrong number. And dbt's layer is a metrics model, not an OWL ontology; a weaker artifact, which makes the direction more telling.
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 desperate to use one. Supply and demand for structure flipped together.
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 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.