This llamaindex knowledge graph index tutorial shows how to turn unstructured documents into a queryable graph of entities and relationships using LlamaIndex’s KnowledgeGraphIndex. We’ll extract triplets, inspect the in-memory graph store, and run a relationship-aware query against the index.
Prerequisites
- Python 3.10 or newer
pip install llama-index openai- An OpenAI API key, or any OpenAI-compatible endpoint. If you want to avoid single-provider lock-in, you can point LlamaIndex at n4n.ai, which exposes one OpenAI-compatible endpoint fronting 240+ models and automatically falls back when a provider is rate-limited.
- A small corpus of
.txtfiles in./data(three or four short files are enough).
Set your key in the environment:
export OPENAI_API_KEY="sk-..."
Step 1: Load documents
LlamaIndex’s SimpleDirectoryReader handles local text files without custom loaders.
from llama_index.core import SimpleDirectoryReader
documents = SimpleDirectoryReader("./data").load_data()
print(f"Loaded {len(documents)} documents")
Expected output:
Loaded 4 documents
If your files are larger than a few hundred words, consider splitting with SentenceSplitter before indexing. The KG extractor works per-node, so chunk size controls how many entities it sees at once.
Step 2: Configure the LLM and graph store
The knowledge graph index uses an LLM to extract (subject, relation, object) triplets. We set the model via Settings so all components pick it up.
from llama_index.core import Settings
from llama_index.llms.openai import OpenAI
from llama_index.core.storage.graph_store import SimpleGraphStore
# Default OpenAI
Settings.llm = OpenAI(model="gpt-3.5-turbo")
# Alternative: OpenAI-compatible gateway (e.g. n4n.ai)
# Settings.llm = OpenAI(
# model="openai/gpt-3.5-turbo",
# api_key="your-gateway-key",
# base_url="https://api.n4n.ai/v1",
# )
graph_store = SimpleGraphStore()
SimpleGraphStore is an in-memory store. For production, swap it for Neo4jGraphStore or RedisGraphStore—the index API stays identical.
Step 3: Build the KnowledgeGraphIndex
Pass the documents, graph store, and LLM to from_documents. Setting include_embeddings=True lets the query engine fall back to vector similarity when a pure graph walk finds nothing.
from llama_index.core import KnowledgeGraphIndex
index = KnowledgeGraphIndex.from_documents(
documents,
graph_store=graph_store,
llm=Settings.llm,
include_embeddings=True,
max_triplets_per_chunk=5,
)
Building the index makes one LLM call per chunk to extract triplets. With four short documents this finishes in seconds. You’ll see no stdout unless you enable debug logging; the returned index object is ready to query.
Step 4: Inspect extracted triplets
A knowledge graph is only useful if the extracted relationships are sane. Pull them directly from the graph store.
rels = graph_store.get_all_relationships()
print(f"Extracted {len(rels)} relationships")
for subj, rel, obj in rels[:5]:
print(f"{subj} --{rel}--> {obj}")
Expected output (your entities will differ):
Extracted 27 relationships
Alice -- WORKS_AT --> Acme Corp
Acme Corp -- HEADQUARTERED_IN --> Springfield
Bob -- COLLEAGUE_OF --> Alice
ProjectX -- OWNED_BY --> Acme Corp
Alice -- LEADS --> ProjectX
If you see vague relations like RELATED_TO dominating, tighten your chunk size or prompt the extractor with a custom KGExtractor. The default prompt is decent but generic.
Step 5: Query the index
The query engine combines graph traversal with embedding retrieval. Ask a question that requires following a relationship:
query_engine = index.as_query_engine(
similarity_top_k=3,
graph_traversal_depth=2,
)
response = query_engine.query("Who leads the project owned by Acme Corp?")
print(str(response))
Expected output:
Alice leads ProjectX, which is owned by Acme Corp.
The engine first walks the graph from Acme Corp to ProjectX, then retrieves the LEADS edge to Alice. If the graph had a gap, it would fall back to the vector index using the embedded text chunks.
Step 6: Persist and reload
SimpleGraphStore lives in RAM. Persist it with the rest of the storage context:
index.storage_context.persist(persist_dir="./storage")
Reload later without re-extracting triplets:
from llama_index.core import StorageContext, load_index_from_storage
graph_store = SimpleGraphStore()
storage_context = StorageContext.from_defaults(
graph_store=graph_store,
persist_dir="./storage",
)
index = load_index_from_storage(storage_context)
This restores both the graph and the vector embeddings (if include_embeddings=True was used at build time).
Tuning extraction quality
The default KnowledgeGraphIndex uses ImplicitKGExtractor in recent LlamaIndex versions, which asks the LLM to output a JSON list of triplets. You can override the extractor:
from llama_index.core.extractors import (
ImplicitKGExtractor,
)
kg_extractor = ImplicitKGExtractor(
llm=Settings.llm,
max_triplets_per_chunk=10,
num_workers=2,
)
index = KnowledgeGraphIndex.from_documents(
documents,
graph_store=graph_store,
kg_extractor=kg_extractor,
)
Raising max_triplets_per_chunk captures denser graphs but costs more tokens. Run a small sample first and inspect graph_store.get_all_relationships() before indexing a large corpus.
When to use a knowledge graph index
A KnowledgeGraphIndex shines when answers require multi-hop reasoning: “Which vendors supply the factory that builds our flagship product?” Pure vector search struggles with that because the signal is spread across documents. The graph makes the path explicit.
It is the wrong tool for open-domain semantic search where you just want “documents similar to this sentence.” There, a VectorStoreIndex is cheaper and simpler. In practice, we often build both and route queries by intent.
This llamaindex knowledge graph index tutorial covered the full loop: load, extract, inspect, query, persist. The same code works against managed graph backends; only the graph_store import changes.