AI Powered Knowledge Graph Generator
This system takes an unstructured text document, and uses an LLM of your choice to extract knowledge in the form of Subject-Predicate-Object (SPO) triplets, and visualizes the relationships as an interactive knowledge graph. Optional companion commands let you ask the
graph questions (graph-chat) and run everything from a local web interface (graph-serve).
Live examples (no install needed): https://robert-mcdermott.github.io/ai-knowledge-graph/
The Industrial Revolutions Marie Curie The Apollo Program Coffee, from farm to cup La Alhambra (Spanish).txt, .md, .rst, .pdf and .docx files or whole directories, in any language (extraction.language); large documents are split on sentence boundaries with overlap and extracted in parallelgraph-chat command): grounded, cited answers from the generated graphgraph-serve command): ingest, browse, explore and ask questions in the browsermax_completion_tokens fallback, environment-variable API keys and an on-disk response cachenetworkx, jinja2, requests (installed automatically)[web] for graph-serve (FastAPI, uvicorn), [pdf] and [docx] for those input formats,
[all] for everythinggit clone https://github.com/robert-mcdermott/ai-knowledge-graph.git
cd ai-knowledge-graph
uv sync --extra web # or: pip install -e ".[web]"
uv sync creates the environment and the generate-graph, graph-chat and graph-serve commands; prefix
commands with uv run (as below) or activate the environment. With pip, drop the uv run prefix.
uv run graph-serve --config config.toml --graphs data/samples --open
This opens a library with the five sample graphs from data/samples/; click one to explore it. Browsing works
without a reachable model; the Ask panel and the New graph form use the model configured in
config.toml. To render a sample to a static page instead:
uv run generate-graph --from-json data/samples/marie-curie.json --output marie-curie.html
Edit config.toml (model name, endpoint, API key; see Configuration), then:
uv run generate-graph --input your_text_file.txt --output knowledge_graph.html
That writes knowledge_graph.html (a self-contained interactive page), knowledge_graph.json (the triples)
and knowledge_graph.meta.json (community names). Keep personal settings in a file git ignores, such as
config-working.toml, and pass it with --config. From a checkout without installing, python generate-graph.py
works the same way.
uv run graph-chat knowledge_graph.json "How did the steam engine change cities?"
uv sync --extra dev --extra web # or: pip install -e ".[dev,web]"
uv run pytest -q # 170 tests, no LLM needed
uv run ruff check .
python scripts/build_docs.py # rebuild the GitHub Pages site from data/samples
The system is configured with a TOML file (config.toml by default, or --config other.toml).
Every key except model and base_url is optional; the values shown are the defaults.
…
Rule-based inference (apply_transitive, lexical) is off by default because in testing it generated
roughly 70 % of all edges and hid the relationships actually found in the text. Local overrides such as
config-*.toml and config.local.toml are ignored by git.
# OpenAI
[llm]
model = "gpt-4.1-mini"
api_key = "env:OPENAI_API_KEY"
base_url = "https://api.openai.com/v1/chat/completions"
# Google Gemini (OpenAI-compatible endpoint)
[llm]
model = "gemini-2.5-flash"
api_key = "env:GEMINI_API_KEY"
base_url = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
# LM Studio / vLLM / LiteLLM proxy (any OpenAI-compatible server)
[llm]
model = "your-model-name"
api_key = "not-needed"
base_url = "http://localhost:1234/v1/chat/completions"
Models such as DeepSeek, Qwen3, gpt-5 and the o-series "think" before they answer, and that
hidden reasoning is charged against max_tokens. With a small budget the model can spend
everything on reasoning and return no answer at all. The generator detects this
(finish_reason = "length") and aborts with an explanation instead of silently producing an
empty graph. Set max_tokens to 16k–32k for such models, lower reasoning_effort, use
smaller chunks, or pass --continue-on-error to skip failed chunks and accept an
incomplete graph.
--input PATH [PATH ...]: Input file(s) or directories. Plain text (.txt, .md, .rst), .pdf (install the [pdf] extra) and .docx ([docx] extra). With several inputs every triple is tagged with its document--output FILE: Output HTML file for visualization (default: knowledge_graph.html)--config FILE: Path to config file (default: config.toml)--debug / --verbose: Show debug output, including raw LLM responses and standardization merges--quiet: Only warnings and errors on the console (the final summary is still printed)--no-standardize: Disable entity standardization--no-inference: Disable relationship inference--continue-on-error: Skip chunks whose LLM call fails or is truncated instead of aborting--from-json FILE: Re-render the visualization from a previously saved .json triples file (no LLM calls)--no-cache: Bypass the LLM response cache for this run--library-path DIR: Reference the vis-network library from DIR (copied there if missing) instead of embedding it, so many pages can share one copy, for example on GitHub Pages--export FORMATS: Extra outputs next to the HTML, comma-separated: json (always), csv, graphml (Gephi, yEd, Cytoscape), cypher (Neo4j MERGE script)--test: Generate sample visualization using test data…
usage: graph-chat [-h] [--config CONFIG] [--json] [--no-facts] graph [question]
positional arguments:
graph Triples JSON written by generate-graph (e.g. knowledge_graph.json)
question Question to answer; omit for an interactive session
options:
--config CONFIG Path to configuration file (uses its [llm] section)
--json Print the result as JSON (single-question mode)
--no-facts Do not list the cited facts after the answer
usage: graph-serve [-h] [--config CONFIG] [--graphs DIR] [--host HOST] [--port PORT] [--open]
options:
--config CONFIG Path to configuration file (uses [llm], [query], [visualization])
--graphs DIR Directory containing the .json graphs written by generate-graph
--host HOST Bind address (default 127.0.0.1; the server has no authentication)
--port PORT Port (default 8008)
--open Open the library in your browser
Command:
generate-graph --input data/industrial-revolution.txt --output industrial-revolution-kg.html
Console Output (gemma4 via Ollama, about 20 seconds; --quiet reduces this to the summary):
…
generate-graph is unchanged: text in, static HTML (and JSON) out. The optional graph-chat command
reads that JSON and answers questions from it, using the same [llm] settings:
uv run graph-chat knowledge_graph.json "How did the steam engine change cities?"
uv run graph-chat knowledge_graph.json # interactive session; Ctrl-D or an empty line quits
uv run graph-chat data/samples/apollo-program.json "Who flew on Apollo 13?"
For each question it finds the entities the question mentions, retrieves the surrounding subgraph (and the
shortest paths between the mentioned entities), and asks the model to answer only from those facts. The
reply lists the facts it relied on, each marked extracted (with the source sentence) or inferred
(with the method), so answers stay traceable to the document. If the graph does not contain an answer it
says so. Tuning lives under [query] in the config (hops, max_triples, max_seed_entities,
history_turns); --json prints the result as JSON for scripting.
graph-serve is a small local server over the same code: it lists the graphs in a directory, opens each one in
the explorer, and adds an Ask panel that answers questions from the graph with cited facts (click a fact to
jump to it in the graph). It needs the [web] extra (uv sync --extra web or pip install -e ".[web]").
Start it with the sample graphs ready to use:
uv run graph-serve --config config.toml --graphs data/samples --open
or point it at the directory where you write your own graphs (any --config file works, e.g. your local
config-working.toml):
uv run graph-serve --config config-working.toml --graphs ./out --open
The library page also has a New graph form: paste text or upload files (.txt, .md, .rst, .pdf,
.docx, several at once), watch the phases run, and land in the explorer when it finishes. It runs the same
pipeline as generate-graph and writes the same .json and .html into the graphs directory, so the result is
usable from the command line and graph-chat too. One generation runs at a time.
It binds to 127.0.0.1:8008 by default, has no accounts or authentication, and only reads and writes the graphs
directory, so it is meant for your own machine. Static HTML output is unchanged: the chat panel only exists in
served pages. --host 0.0.0.0 exposes it on your network if you put your own access control in front.
data/samples/ contains five short texts and the graphs generated from them (.json triples pl
No open issues yet, or sync has not completed.