Skip to main content

xgen-ontology

Backend-agnostic ontology / knowledge-graph toolkit. Turn documents or tables into a clean knowledge graph — extract, resolve, dedup, induce the is-a hierarchy, govern predicates, score quality — then search it with one-shot GraphRAG. Zero infra (the whole thing runs on a pure-Python in-memory backend), zero lock-in (load into any SPARQL 1.1 store), zero hard deps in the core.

from xgen_ontology import build_from_csv

onto = build_from_csv({                       # no LLM, no DB, no API key
    "products": "product_id,name,color_id\n1,Widget,10\n2,Gadget,20",
    "colors":   "color_id,name\n10,Red\n20,Blue",
})
print(onto.stats())          # {'classes': 2, 'instances': 4, 'relations': 2, ...}
print(onto.to_turtle())      # standards RDF/Turtle
print(onto.search("what color is Widget").answer)

A knowledge graph built with xgen-ontology (degree-sized nodes, community clusters), shown in a graph explorer:

An ontology knowledge graph built with xgen-ontology

Build from prose with any LLM, mix tables and text freely — raw documents are parsed and chunked for you:

from xgen_ontology import build_from_files, build_from_text, CallableLLM

llm = CallableLLM(lambda p, system="": my_model(system, p))     # OpenAI / Anthropic / vLLM / …

# from files on disk (txt/md/html/csv built-in; pdf/docx/xlsx via the [files] extra)
onto = build_from_files(["policy.pdf", "products.csv"], llm=llm)

# or from a single raw string (auto boundary-aware chunking)
onto = build_from_text("Rule A applies to Acme Bank since 2020. ...", llm=llm)

Two halves of the lifecycle

Build — documents/tables → a clean graph

The pipeline is a sequence of independently-importable, backend-agnostic stages:

Stage What it does
parse extract text from files — txt/md/html/csv built-in (zero-dep), pdf/docx/xlsx via [files]
chunk boundary-aware chunking (paragraph→sentence→char) with overlap, stable chunk ids for provenance
tabular table → ontology with no LLM: table→Class, FK→ObjectProperty (same-name / normalized-name / value-overlap detection), column→DataProperty, dimension rows→instances; large fact/junction tables stay schema-only
extract one LLM call per chunk batch → schema and instances, tagged to source chunks; junk (base64/degenerate) filtered first
resolve entity resolution: fold case/whitespace/unicode + similar surface forms, guarding dates/ids and number-conflicting names
govern predicate governance: fold surface variants of a relation, anchor to the schema vocabulary
dedup merge synonymous classes/properties/instances — rule keys, LLM synonym groups, and embedding cosine clusters
hierarchy keep only genuine is-a edges ("being linked is not being a subclass"), break cycles, then SCS context profiles with property inheritance
quality a graph-reviewer score: completeness · integrity · grounding · shape
community Louvain modularity clustering (pure Python)
emit Turtle (zero-dep) or OWL/RDF-XML (rdflib)

Search — one-shot GraphRAG

Not an iterative ReAct loop — fire several retrieval strategies at once and fuse:

  1. vector / lexical passages (what it says)
  2. graph label-linking → 1-hop relations (how entities connect)
  3. class enumeration — the complete "list/count" a vector index can't give
  4. HippoRAG: entities of the retrieved chunks → 1-hop expansion
  5. evidence assembled with MMR diversity + adaptive top-k (the decisive minority — a warning/exception — survives instead of being crowded out)
  6. one LLM synthesis; honest evidence_nodes = only the nodes the answer cites
res = onto.search("which regulation applies to Acme Bank", llm=llm)
res.answer          # the synthesis
res.relations       # graph relations used
res.evidence_nodes  # nodes the answer actually cites (honest highlight)

Any graph DB, or none

The algorithms only ever talk to small protocols (GraphStore, VectorStore, LLM, GraphSink, Morphology, Embedder), never to a database:

# zero infra — pure-Python in-memory (default)
onto.search("…")

# load into any SPARQL 1.1 store (Fuseki, GraphDB, Blazegraph, Virtuoso, …)
from xgen_ontology import fuseki
store = fuseki("http://localhost:3030", "ds", user="admin", password="…")
onto.push(store, graph="urn:my-graph")           # write
onto.search("…")                                  # or search a remote store via SparqlGraph

SparqlGraph is stdlib-only (urllib) and uses portable FILTER(CONTAINS(...)), so it works on any SPARQL 1.1 endpoint — not just jena-text.

Install

pip install xgen-ontology                 # core, zero deps
pip install "xgen-ontology[files]"        # + pypdf / python-docx / openpyxl (parse pdf/docx/xlsx)
pip install "xgen-ontology[rdf]"          # + rdflib (OWL / RDF-XML emit & parse)
pip install "xgen-ontology[korean]"       # + kiwipiepy (Korean morphological dedup)
pip install "xgen-ontology[vector]"       # + qdrant-client (embedding adapters)

Run the demos with no install:

python examples/build_csv.py
python examples/build_and_search.py

Design — algorithms as a library

  • dependencies = [] — the core needs nothing but the standard library. The in-memory graph indexes labels with BM25 (CJK character n-grams, so Korean/CJK search works with no morphological analyzer); the Turtle writer is hand-rolled.
  • English-neutral by default — no hardcoded language. Korean morphology, name→URI translation and the extraction/synthesis prompts are all pluggable; the defaults assume nothing about your domain or language.
  • Bring your own everything — LLM (generate(prompt, system)), embedder, morphology, graph store. The bundled EchoLLM lets the whole pipeline run with no API key.
src/xgen_ontology/
  models.py        # Class/Property/Concepts (T-Box), Instance/Relation/DataValue (A-Box), Node/Chunk
  protocols.py     # LLM / GraphStore / VectorStore / GraphSink / Morphology / Embedder
  text.py          # tokenizer + BM25 (CJK n-grams), IRI-safe slugging
  build/
    parse.py       # file -> text (txt/md/html/csv; pdf/docx/xlsx optional)
    chunk.py       # boundary-aware chunking
    tabular.py     # table -> ontology (no LLM)
    extract.py     # document -> ontology (LLM)
    resolve.py     # entity resolution
    govern.py      # predicate governance
    dedup.py       # rule + LLM + vector dedup
    hierarchy.py   # is-a cleaning + SCS inheritance
    quality.py     # graph-reviewer score
    community.py   # Louvain
    emit.py        # Turtle / OWL
    pipeline.py    # OntologyBuilder (wires the stages)
  backends/
    memory.py      # InMemoryGraph / InMemoryVector / InMemoryGraphSink (zero infra)
    sparql.py      # SparqlGraph — any SPARQL 1.1 store (read + write)
  search/          # fusion + one-shot GraphRAG
  ontology.py      # Ontology — the hub (search / emit / push / quality / communities)
  facade.py        # build_from_csv / build_from_documents / build_from_triples
examples/  tests/

Roadmap

  • async pipeline (parallel chunk extraction + parallel search seeds)
  • Neo4j / property-graph GraphStore adapter; Qdrant VectorStore adapter
  • RDF-star / qualified statements (n-ary relations, provenance) in emit
  • reranker / cross-encoder hook for search

License

MIT © jinsoo96. See LICENSE.

Metadata

Release files for xgen-ontology 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for xgen-ontology 0.3.0
File Size Uploaded
xgen_ontology-0.3.0.tar.gz 2.8 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for xgen-ontology 0.3.0
File Interpreter ABI Platform
xgen_ontology-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 2.8 MB

Release files / xgen_ontology-0.3.0.tar.gz

Download URL xgen_ontology-0.3.0.tar.gz
Size 2.8 MB
Tags Source
SHA-256 checksum
How to use checksums
178ac7699a6b3158d7cf4340c4f08f451b1d8d28b3fedbc3ddcb78b429de9656
BLAKE2b-256 checksum
How to use checksums
1c2d8a8b42a26ecd8cdcb1cc7c59ce458b0f46cbfa3700117f19c26f4500dc36
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / xgen_ontology-0.3.0-py3-none-any.whl

Download URL xgen_ontology-0.3.0-py3-none-any.whl
Size 60.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2832cb2f75b3cf39683b71d2ffe989d8897942c6205b4c33cf07e955d57fc4c8
BLAKE2b-256 checksum
How to use checksums
190208bdd87ffaec41cfac460669adabb83f316ac4e93fadbad316926baa1ce3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release history Release notifications | RSS feed

0.12.6

2 release files

0.12.5

2 release files

0.12.4

2 release files

0.12.3

2 release files

0.12.2

2 release files

0.12.1

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page