Ontology Management
SmartMemory includes an ontology management system that helps structure and organize knowledge for better extraction, validation, and retrieval. This guide covers how to define, manage, and leverage ontologies in your agentic memory system.
Overview
An ontology in SmartMemory defines:
- Entity types: The kinds of entities the system recognizes (e.g.
algorithm,person,organization), including their properties and inheritance hierarchy - Relationship types: How entity types may relate to each other, with allowed source/target types
- Rules: Validation, enrichment, and inference rules attached to the ontology
- Constraints: Required properties and per-property constraints (type, cardinality, soft/hard enforcement)
The runtime surface for building and managing ontologies is the OntologyManager class plus the Ontology model and its type-definition dataclasses. The correct imports are:
from smartmemory.ontology.manager import OntologyManager
from smartmemory.ontology.models import (
Ontology,
EntityTypeDefinition,
RelationshipTypeDefinition,
OntologyRule,
PropertyConstraint,
)OntologyManager API
OntologyManager is the entry point for ontology lifecycle operations. Its public methods are:
| Method | Purpose |
|---|---|
create_ontology(name, domain="", description="") | Create and persist a new empty Ontology |
load_ontology(ontology_id) | Load an ontology by ID (returns Ontology or None) |
set_active_ontology(ontology) | Set the ontology used for extraction guidance |
get_active_ontology() | Return the currently active ontology (or None) |
infer_ontology_from_extractions(extraction_history, ontology_name="inferred") | Build an ontology from historical extraction patterns |
migrate_freeform_to_ontology(extraction_history, base_ontology=None) | Migrate freeform extractions into an ontology-guided one |
list_ontologies() | List all stored ontologies with basic metadata |
delete_ontology(ontology_id) | Delete an ontology by ID |
The manager is backed by pluggable storage (OntologyStorage). By default it uses FileSystemOntologyStorage, which persists each ontology as a JSON file:
from smartmemory.ontology.manager import OntologyManager
from smartmemory.stores.ontology import FileSystemOntologyStorage
# Defaults to FileSystemOntologyStorage("ontologies")
manager = OntologyManager()
# Or supply an explicit storage directory
manager = OntologyManager(storage=FileSystemOntologyStorage("my_ontologies"))Defining an Ontology
Create an ontology and add entity types
Entities are described with EntityTypeDefinition. Properties are a name -> type map, and required_properties/parent_types/aliases are sets.
from datetime import datetime, UTC
from smartmemory.ontology.manager import OntologyManager
from smartmemory.ontology.models import EntityTypeDefinition
manager = OntologyManager()
# Create a new ontology (persisted immediately)
ontology = manager.create_ontology(
"technology",
domain="technology",
description="Technology and ML concepts",
)
# Define an entity type
deep_learning = EntityTypeDefinition(
name="deep_learning",
description="Deep learning techniques",
properties={"complexity": "number"}, # property_name -> property_type
required_properties=set(),
parent_types=set(), # inheritance hierarchy (type names)
aliases=set(),
examples=["ConvolutionalNeuralNetwork", "Transformer"],
created_by="human",
created_at=datetime.now(UTC),
)
ontology.add_entity_type(deep_learning)
# A child type that inherits from deep_learning
cnn = EntityTypeDefinition(
name="convolutional_neural_network",
description="CNN architectures",
properties={"complexity": "number"},
required_properties=set(),
parent_types={"deep_learning"},
aliases={"cnn"},
examples=["ResNet", "VGG"],
created_by="human",
created_at=datetime.now(UTC),
)
ontology.add_entity_type(cnn)Define relationship types
Relationships are described with RelationshipTypeDefinition. source_types and target_types constrain which entity types may participate.
from smartmemory.ontology.models import RelationshipTypeDefinition
uses = RelationshipTypeDefinition(
name="uses",
description="One technique uses another",
source_types={"deep_learning"},
target_types={"deep_learning"},
properties={},
)
ontology.add_relationship_type(uses)
similar_to = RelationshipTypeDefinition(
name="similar_to",
description="Two techniques are similar",
source_types={"deep_learning"},
target_types={"deep_learning"},
properties={},
bidirectional=True,
)
ontology.add_relationship_type(similar_to)Property constraints
Per-property constraints are expressed with PropertyConstraint and attached to an entity type's property_constraints map. kind controls enforcement: soft warns, hard rejects.
from smartmemory.ontology.models import PropertyConstraint
deep_learning.property_constraints = {
"complexity": PropertyConstraint(
required=False,
type="number",
cardinality="one",
kind="soft",
),
"application_domain": PropertyConstraint(
required=False,
type="enum",
cardinality="many",
kind="soft",
enum_values=["nlp", "computer_vision", "robotics", "speech"],
),
}Add rules
Validation, enrichment, and inference rules use OntologyRule:
import uuid
from datetime import datetime, UTC
from smartmemory.ontology.models import OntologyRule
rule = OntologyRule(
id=str(uuid.uuid4()),
name="require_complexity",
description="Encourage a complexity score on deep_learning entities",
rule_type="validation",
conditions={"entity_type": "deep_learning"},
actions={"suggest_property": "complexity"},
)
ontology.add_rule(rule)Persist changes
create_ontology() saves on creation, but mutations to the in-memory Ontology object are not auto-persisted. Save through the manager's storage after editing:
manager.storage.save_ontology(ontology)Validating Against an Ontology
The Ontology model can validate entities and relationships directly. Both methods return a list of error strings (empty when valid).
# Validate an entity instance against its type definition
errors = ontology.validate_entity("deep_learning", {"complexity": 0.8})
# [] when valid; ["Unknown entity type: ..."] / missing-required-property messages otherwise
# Validate a relationship's source/target types
rel_errors = ontology.validate_relationship(
"uses",
source_type="deep_learning",
target_type="deep_learning",
)Lookups are case-insensitive:
entity_def = ontology.get_entity_type("Deep_Learning")
rel_def = ontology.get_relationship_type("USES")Inferring an Ontology From Extractions
Rather than authoring an ontology by hand, you can infer one from prior extraction results. infer_ontology_from_extractions analyzes a list of extraction records (each with entities and relations) and builds entity/relationship type definitions for patterns seen at least twice.
extraction_history = [
{
"entities": [
{"type": "algorithm", "name": "CNN", "properties": {"domain": "vision"}},
],
"relations": [
{"relation_type": "uses", "source": "CNN", "target": "convolution"},
],
},
# ... more extraction records
]
inferred = manager.infer_ontology_from_extractions(
extraction_history,
ontology_name="inferred_tech",
)
print(list(inferred.entity_types.keys()))
print(list(inferred.relationship_types.keys()))The inferred ontology is persisted automatically. Confidence scores scale with how often each type was observed, and required properties are derived from properties present in more than 80% of instances of a type.
Note — OntoGPT engine: When
ontology.inference.ontogpt.enabledis set in config, inference is delegated to theOntoGPTInferenceEngine. If that path fails it logs a warning and falls back to the built-in frequency-based inference shown above.
Migrating Freeform Extractions
migrate_freeform_to_ontology turns a history of freeform (LLM-driven) extractions into an ontology-guided one. With no base ontology it infers a fresh one; with a base ontology it extends it and records a migration rule.
# Build a brand-new ontology from freeform extraction history
migrated = manager.migrate_freeform_to_ontology(extraction_history)
# Or extend an existing ontology
migrated = manager.migrate_freeform_to_ontology(
extraction_history,
base_ontology=ontology,
)Listing and Deleting Ontologies
# List stored ontologies (id, name, version, domain, entity_count, ...)
for meta in manager.list_ontologies():
print(meta["id"], meta["name"], meta["entity_count"])
# Delete by ID
manager.delete_ontology(ontology.id)Ontology-Guided Ingestion
SmartMemory's ingestion pipeline includes an ontology_constrain stage that validates and constrains extracted entities/relations against the active ontology. It is enabled by default and controlled by the enable_ontology constructor flag:
from smartmemory.smart_memory import SmartMemory
# Ontology constraint stage on (default)
memory = SmartMemory(enable_ontology=True)
# Disable the stage entirely
memory = SmartMemory(enable_ontology=False)
item_id = memory.ingest(
"Convolutional Neural Networks are a deep learning architecture "
"used for computer vision tasks."
)The ontology_constrain stage reads the unified :OntologyType / :OntologyRelation graph labels and routes all reads/writes through the internal OntologyService. This is the productized path that ontology definitions feed into — there is no separate ontology_config= constructor argument, and entity extraction is governed by the pipeline stage rather than by per-call search() flags.
REST API: The service exposes ontology management over HTTP under
/memory/ontology/*— includingGET /memory/ontology/status,GET/POST /memory/ontology/registries, registry snapshots/changelog/rollback, templates, patterns, import/export, andPOST /memory/ontology/inference/run. See the service API reference for the full route list.
Capabilities Not Currently Exposed
Some ontology features that might be expected are not part of the current public API. They are noted here so you don't depend on methods that don't exist:
- Per-call ontology search expansion — there is no
search(use_ontology=...)/expand_conceptsargument. Retrieval does not take ontology flags; ontology influence happens at ingestion time via theontology_constrainstage. - Concept-keyed memory listing / statistics — methods like
get_memories_by_concept(...)andget_concept_statistics()do not exist. Use standardmemory.search(...)plus graph queries to retrieve entities and their relations. - Per-memory extracted-concept readout — there is no
get_extracted_concepts(memory_id)accessor. Extracted entities are written to the knowledge graph during ingestion; query the graph to inspect them.
These are intentional gaps in the current surface, not shipped methods — treat any code that calls them as incorrect.