What it does
An ontology is a typed schema for a workspace. You declare the object types (entity kinds
like Person, Order), each with typed properties, and the directed link types
(relations like approved: Person → Order) that connect them. Then every entity and relation the
graph extracts is checked against it.
It is deliberately not RDF or OWL. It's a plain dataclass model, persisted as JSON, one file per workspace.
And validation isn't just a yes/no gate — the same pass that checks a record also normalises it, so
"$25,000" becomes 25000.0 and "20%" becomes 0.2, using the exact
same parsers as the Rules Engine.
money or percent instead of a free-text blob to regex.
The data model
An ontology document has a name, an integer version, a list of object types, and a list of link types:
{
"name": "sales",
"version": 1,
"object_types": [
{ "name": "Person", "description": "a human",
"properties": [ { "name": "email", "kind": "string" } ] },
{ "name": "Order", "description": "a deal",
"properties": [
{ "name": "value", "kind": "money", "required": true },
{ "name": "status", "kind": "enum", "enum_values": ["open","won","lost"] }
] }
],
"link_types": [
{ "name": "approved", "source_types": ["Person"], "target_types": ["Order"],
"cardinality": "1:N" }
]
}
Property kinds
A property's kind is one of nine values. Numeric kinds accept optional minimum/maximum
bounds; enum requires enum_values.
| Kind | Coerces to | Notes |
|---|---|---|
| string · text | str | Free text. |
| integer · float | number | Numeric; range-checkable. |
| money | float | Parsed from text — "$8k" → 8000.0. Numeric. |
| percent | float | "20%" → 0.20. Numeric. |
| boolean | bool | From common string forms. |
| date | ISO date | YYYY-MM-DD via date.fromisoformat. |
| enum | member | Value must be in enum_values. |
Link types
A link type constrains a relation's endpoints and can carry its own typed properties (which map onto the edge's
RelationContext). source_types/target_types list the allowed head/tail object types — an
empty list means "any". cardinality is one of 1:1, 1:N,
N:1, N:M (default N:M), and directed defaults to true.
Extraction validation
The ExtractionValidator checks extracted entities and relations against the ontology and returns a
per-item report. Two policies control how strict it is:
A type the ontology doesn't define is flagged
unknown_type but stays ok — recorded as a
warning. New kinds are tolerated.The same unknown type becomes a violation (
ok=false). Only the declared schema is allowed.What counts as a violation vs a warning
| Condition | Result |
|---|---|
Missing a required property | violation |
Enum value not in enum_values, or numeric out of range | violation |
| Relation endpoint is a known-but-disallowed type | violation |
| Relation endpoint type is unknown (can't be verified) | warning |
| A property not declared on the type | warning |
| Unknown object/link type (open-world) | warning |
The report's summary() gives you total, conforming, violations,
by_status, unknown_types, and the active policy. Each item also returns its
coerced values — the normalised form the graph should store.
The /ontology API
All endpoints are workspace-scoped via LIGHTRAG-WORKSPACE and return 503 unless the
server runs in Context Graph mode (USE_CONTEXT_GRAPH=true).
| Method · Path | Purpose | Returns |
|---|---|---|
GET /ontology | Current schema summary | OntologySummaryResponse |
POST /ontology | Save a schema (JSON) | Summary (400 if malformed) |
DELETE /ontology | Delete this workspace's schema | {deleted, workspace} |
POST /ontology/generate | NL → schema (LLM) | Generation result + saved (503 if no LLM) |
POST /ontology/validate | Validate extracted records | Report (404 if no schema) |
The summary describes the schema at a glance — object types with property counts, link types with their
source/target types and cardinality, plus any lint messages and the full ontology for
round-tripping into an editor:
# Validate a batch of extractions against the workspace schema
curl -X POST http://localhost:9621/ontology/validate \
-H "LIGHTRAG-WORKSPACE: sales" -H "Content-Type: application/json" \
-d '{
"entities": [{"entity_name":"Acme Deal","entity_type":"Order","properties":{"status":"won"}}],
"relations": [],
"closed_world": false
}'
# -> Order:Acme Deal status=invalid "missing required property 'value'"
Storage & versioning
The default store writes one atomic JSON file per workspace — ontology_<workspace>.json — holding
the workspace name, an updated_at timestamp, and the ontology itself. An in-memory store is available for
tests and the API cache.
- Validated on save. A schema whose links reference undefined object types is rejected at author time, never persisted broken.
- Monotonic version. Each save bumps an integer
version(previous + 1). The stored version overrides whatever the incoming document carried. - Single current copy. There is one file per workspace — the version counts changes; it is not a per-version history or rollback log.