Model or dataset
robert-mcdermott/ai-knowledge-graph avatar
robert-mcdermott/ai-knowledge-graph

ai-knowledge-graph: SPO Triplets from Plain Text, Rendered as a Self-Contained HTML Explorer

AI Powered Knowledge Graph Generator

3,076 stars414 forksPythonApache-2.0

At a glance

What is it?
A Python tool that sends your documents to an OpenAI-compatible LLM, extracts subject-predicate-object triples with entity types and source sentences, then writes an interactive graph page. The design is conservative about inference, which is also where its limits sit.
Who is it for?
Adopt it if you have a corpus of prose and an OpenAI-compatible endpoint, and you want a browsable graph rather than a database schema. Skip it if you need curated ontologies, entity resolution against an external authority, or a graph that stays in sync with a changing source.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap between a document and a graph you can read

Most text-to-graph pipelines assume you already have a schema. You define entity types, write extraction rules, and then fight the long tail of sentences that do not fit. This project inverts that. It takes .txt, .md, .rst, .pdf and .docx files, or whole directories, and asks an LLM to return Subject-Predicate-Object triples directly. The README describes the output as triples with entity types drawn from a fixed list: person, organization, place, event, technology, product, work, date, concept. Every extracted relationship keeps the sentence it came from, which is the single most useful design decision here, because it lets you audit a bad edge without re-reading the source. The audience is analysts, researchers and engineers who want to see what is inside a pile of prose before deciding whether to model it properly. It is not a data integration tool and the README does not present it as one.

Chunking, parallel extraction and the on-disk cache

Documents are split on sentence boundaries rather than at a fixed character count, with a target of 500 words per chunk and 50 words of overlap, both configurable under [chunking]. Chunks are extracted in parallel, four at a time by default via the concurrency key. The overlap matters: a relationship stated across a sentence boundary survives because the neighbouring text is present in both chunks. The LLM client is where most of the engineering effort appears to have gone. The README lists truncation detection for reasoning models, retries with back-off on 429 and 5xx responses, an automatic max_completion_tokens fallback for newer OpenAI models, and a response cache in .kg-cache. That cache is the practical feature. Re-running the same input costs nothing and returns the same graph, which makes prompt and config tuning bearable when your endpoint is a hosted model you pay per token. You can disable it with an empty cache_dir or the --no-cache flag.

Entity standardization and the two inference passes

Raw LLM output is messy. The same person appears as a name, a title and a plural variant. The tool merges case, stop-word and plural variants deterministically, and offers an optional LLM pass for the residue. After that come two inference mechanisms, and the README is explicit that they are capped relative to the number of extracted edges. One is an LLM pass that bridges isolated parts of the graph and adds well-known relationships between central entities. The other is a deterministic taxonomy rule linking specific terms to general ones. Every inferred edge carries its method, so you can filter or discard them. The cap is the interesting constraint. It means inference cannot dominate the graph, which keeps the output closer to what the text actually says. The cost is that a sparse document stays sparse. If your source mentions two entities once each with no connecting sentence, the tool will not invent a rich structure around them.

Running it: uv sync, config.toml and the three commands

Installation is a clone plus uv sync --extra web, or pip install -e ".[web]" if you prefer pip. That creates three commands: generate-graph, graph-chat and graph-serve. Prefix with uv run in a uv environment, or drop the prefix after a pip install. The sample graphs in data/samples need no model at all, which is a sensible way to evaluate the output format before wiring up an endpoint: uv run graph-serve --config config.toml --graphs data/samples --open opens a library of five examples. To render one to a static page, uv run generate-graph --from-json data/samples/marie-curie.json --output marie-curie.html. Generating from your own text requires editing config.toml first. Only model and base_url are mandatory. The default base_url points at a local Ollama chat completions endpoint, and the README notes that any OpenAI-compatible URL works, listing Ollama, LM Studio, vLLM, OpenAI, Gemini, OpenRouter and LiteLLM. API keys can be inlined or read from the environment with the env: prefix. Keep personal settings in a git-ignored file such as config-working.toml and pass it with --config.

Where the model choice becomes your problem

The configuration surface is small, but one key carries real risk. max_tokens defaults to 32768 and the README warns that reasoning models need a large budget. Set it too low and the client's truncation detection fires, retries, and eventually you get partial extractions rather than an error you can act on. The temperature key is documented as something to omit for models that only accept the default, with gpt-5 named as an example, so a config that works against one endpoint can fail against another with the same file. The json_mode flag is off by default, which means the tool is parsing structured output from free-form text; the README does not describe what happens when the model returns malformed triples beyond the general retry behaviour. Non-English input is handled through extraction.language, set to "auto" by default, and the README gives "Chinese" as an example that yields entity names and predicates in that language. That is a genuine capability, but it also means downstream consumers of the JSON need to handle non-Latin labels.

Exports, and why the HTML file is the real deliverable

The tool writes JSON, CSV, GraphML and a Cypher script. GraphML targets Gephi, yEd and Cytoscape; the Cypher script is for Neo4j. Those exports are useful, but they are snapshots. Nothing in the described architecture watches a source directory or re-extracts when a document changes, so keeping a Neo4j instance current means re-running generation and handling the diff yourself. The interactive HTML file is the part that stands on its own. It is a single self-contained page with search, click-to-highlight, a relationships panel showing sources, named communities, entity-type filters, a shortest-path finder, exports and light and dark themes. Because it is self-contained, it can be committed, emailed or dropped on a static host. That is a different distribution model from a graph database, and for a report or a literature review it is usually the more useful one.

Against a hand-built spaCy and NetworkX pipeline

The obvious alternative is dependency parsing with spaCy plus NetworkX, or a dedicated relation extraction model. The difference is in where the rules live. A spaCy pipeline gives you deterministic, reproducible output with no per-token cost, and you can trace every edge back to a parse tree. It also requires you to enumerate the relation types you care about in advance, and it degrades on the kind of loose, discursive prose where the relation is implied rather than grammatical. This project trades determinism for coverage: it will find relationships a rule-based extractor misses, at the cost of a non-deterministic result that depends on the model, the temperature and the chunking. The cache mitigates the reproducibility problem for a fixed config, but change the model and the graph changes. If your corpus is uniform and your relation types are known, the rule-based route is cheaper and more predictable. If your corpus is heterogeneous and you are still exploring what is in it, this tool gets you to a readable graph faster.

Licence, maintenance and what to verify before you commit

The licence is Apache-2.0, which permits commercial use and modification and includes a patent grant, with the usual requirements to retain notices and state changes. That is permissive enough for internal tooling and for embedding the generated HTML in a product, though the licence text itself is the authority and this is not legal advice. On maintenance: the repository is not archived, and the last push was on 2026-09-12, with v0.8.0 released the same day and v0.7.0 earlier that day. Two releases in a single day suggests active iteration rather than a settled API, so pin a version if you build on the JSON schema. The README states there are 170 tests and that they need no LLM, which is a reasonable signal for the deterministic parts; the LLM-dependent paths cannot be covered that way. Verify three things first: whether your endpoint returns clean triples under your chosen model, whether the community names in the .meta.json sidecar are meaningful for your corpus, and whether the inferred-edge cap leaves you with a graph dense enough to be worth exploring. If the extracted edges alone are too sparse, no amount of inference will fix it, and a different tool will not either.

Editorial conclusion

Adopt it if you have a corpus of prose and an OpenAI-compatible endpoint, and you want a browsable graph rather than a database schema. Skip it if you need curated ontologies, entity resolution against an external authority, or a graph that stays in sync with a changing source. Before committing, run the sample library with uv run graph-serve --config config.toml --graphs data/samples, then generate one graph from your own text and inspect the .meta.json community names and the source sentence attached to each edge. That inspection tells you more about fit than any feature list.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. robert-mcdermott/ai-knowledge-graph on GitHub
Community notes

Community notes