Create a Knowledge Graph from Text

Learn to build a knowledge graph from text using Python and LLMs. This tutorial covers entity extraction, relation mapping, and graph construction, with hands-on steps, troubleshooting, and what to study next.

Focus: create a knowledge graph from text

Sponsored

Ever stared at thousands of paragraphs of customer feedback, research papers, or support tickets and wished you could just see the relationships hidden inside? Extracting entities and connections manually is painfully slow and error-prone. In this lesson, you'll learn how to create a knowledge graph from text using Python and LLMs — turning unstructured prose into a structured map of entities and relationships you can query, visualize, and reason over. By the end, you'll have a working pipeline you can adapt to your own data.

The problem this lesson solves

Text is the most common format for human knowledge, but it's also the least structured. When you need to answer questions like "Which customers mentioned feature X alongside bug Y?" or "What drugs interact with medication Z?", searching through raw text is slow and imprecise. A knowledge graph solves this by representing information as triples: subject — predicate — object. For example: "Aspirin" — "treats" — "Headache". Once you have triples, you can store them in a graph database, query them with Cypher or SPARQL, and power recommendation engines, semantic search, and explainable AI systems.

The manual alternative — reading documents and filling in spreadsheets — doesn't scale. An LLM can extract these triples automatically, but you need a pipeline to go from raw text to a clean, queryable graph. That's exactly what we'll build.

Core concept / mental model

Think of a knowledge graph as a map of a city where entities are the buildings and relations are the roads connecting them. Text is a description of that city — full of streets, landmarks, and directions — but it's written as a narrative, not a map. Your job is to parse that narrative and reconstruct the map.

The pipeline has three stages:

  1. Entity extraction — identify the buildings (people, places, concepts, products).
  2. Relation extraction — identify the roads (verbs, prepositions, causal links).
  3. Graph assembly — place the buildings and roads on the map (store as nodes and edges).

An LLM is great at all three because it understands context. Unlike regex or NER-only approaches, it can infer relations like "causes" or "depends on" even when the connection is implicit.

Pro tip: Keep your relation set small and controlled (e.g., causes, treats, located_in, part_of). A limited vocabulary makes the graph much easier to query and avoids a messy tangle of tiny, one-off relations.

How it works step by step

Here's the logical sequence you'll follow every time you build a knowledge graph from text:

  1. Preprocess the text — clean it, split into sentences, and decide whether to process the whole document or chunk it.
  2. Design the schema — define what counts as an entity and which relation types matter for your domain.
  3. Prompt the LLM — ask it to return a list of triples in a structured format like JSON.
  4. Validate the output — check for missing entities, wrong relation types, or syntax errors.
  5. Build the graph — add nodes and edges to a graph data structure or a graph database.
  6. Store and query — persist it for later use and write queries to extract insights.

Each step has its own failure modes — an LLM might invent a relation, miss a subtle entity, or output invalid JSON. We'll address those in the troubleshooting section.

Hands-on walkthrough

Let's build a minimal end-to-end pipeline using openai, networkx, and json. We'll extract triples from a short medical text about a fictional drug.

Step 1: Install dependencies

pip install openai networkx

Step 2: Write the extraction function

import json
import openai
from networkx import Graph

def extract_triples(text: str, relation_types: list[str]) -> list[dict]:
    """Ask an LLM to return a list of triples from text."""
    system_prompt = """You are a knowledge graph builder. Extract all entities and relationships from the given text.
    Return a JSON array of objects with keys: subject, predicate, object. Subject and object must be concise phrases (no more than 3 words). Predicate must be one of the allowed relation types."""
    user_prompt = f"""Allowed relation types: {', '.join(relation_types)}
    Text: {text}

    Return only JSON, no other text."""
    response = openai.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_prompt}
        ],
        response_format={"type": "json_object"},
        temperature=0
    )
    content = response.choices[0].message.content
    data = json.loads(content)  # safe because response_format enforces JSON
    return data.get("triples", [])

Step 3: Build the graph

def build_knowledge_graph(triples: list[dict]) -> Graph:
    """Add nodes and edges to a networkx graph."""
    g = Graph()
    for triple in triples:
        subj = triple["subject"]
        obj = triple["object"]
        pred = triple["predicate"]
        g.add_node(subj, type="entity")
        g.add_node(obj, type="entity")
        g.add_edge(subj, obj, relation=pred)
    return g

Step 4: Run it on sample text

text = """Clinical trials show that Nexium treats acid reflux.
Nexium may cause headaches in rare cases.
The drug is manufactured by AstraZeneca.
"""
relations = ["treats", "causes", "manufactured_by"]

triples = extract_triples(text, relations)
print(triples)
# Expected output (similar):
# [
#   {"subject": "Nexium", "predicate": "treats", "object": "acid reflux"},
#   {"subject": "Nexium", "predicate": "causes", "object": "headaches"},
#   {"subject": "Nexium", "predicate": "manufactured_by", "object": "AstraZeneca"}
# ]

graph = build_knowledge_graph(triples)
print("Number of nodes:", graph.number_of_nodes())  # 4
print("Number of edges:", graph.number_of_edges())  # 3

# Show a simple path
print("Nexium neighbors:", list(graph.neighbors("Nexium")))
# ['acid reflux', 'headaches', 'AstraZeneca']

What just happened? The LLM read the text, identified the key entities and relations, and returned a structured list. We then stored those as nodes and edges in a networkx graph, which we can query, visualize, or export to a graph database.

Compare options / when to choose what

Approach Example Pros Cons Best for
LLM extraction OpenAI GPT, Claude Handles complex relations, implicit connections Cost, latency, occasional hallucination Rich, unstructured text, many relation types
Traditional NLP spaCy NER + dependency parsing Fast, cheap, deterministic Requires custom relation rules, misses implicit links Simple fact extraction, high-volume batch
Regex / pattern matching Hand-crafted rules Zero ML setup Fragile, huge maintenance Very controlled input format, small vocab
Cloud NLU AWS Comprehend, Azure Text Analytics Managed, scales Limited relation types, less control Quick prototyping, when vendor lock-in is OK

When to choose what: - Use LLM extraction when your text is messy or contains nuanced relations (e.g., medical literature, legal contracts). - Use traditional NLP when you need low cost and your relations are mostly verb-based and explicit. - Use regex only for logs or highly templated text. - Use cloud NLU when you want zero-maintenance and are okay with predefined entity/relation sets.

Pro tip: For production, try a hybrid — use LLMs for entity/relation extraction, but run validation rules to filter out nonsense before inserting into the graph.

Troubleshooting & edge cases

  • LLM returns invalid JSON: even with response_format, sometimes the content is malformed. Wrap json.loads in a try/except and re-prompt or use a custom parser.
try:
    data = json.loads(content)
except json.JSONDecodeError:
    print("Failed to parse, retrying...")
    # retry logic here
  • Entity persistence: the LLM might refer to the same entity with different names (e.g., "Nexium" vs "nexium", or "AstraZeneca" vs "AZ"). Use a normalization step (lowercase, alias mapping) or instruct the LLM to use canonical names in the prompt.

  • Relation ambiguity: sometimes a sentence like "John met Mary" can be interpreted as John — met — Mary or Mary — met — John. In your prompt, specify the direction: "subject is the agent, object is the patient."

  • Chunking errors: if your text is long, chunk it into sentences or paragraphs. But beware — a relation may span across chunks (e.g., a coreferent pronoun). Use coreference resolution or pass a summary window.

  • Hallucinated triples: the LLM might invent a fact not in the text. Mitigate by adding a post-hoc verification step: ask a another LLM call to confirm each triple against the original text, or use a rule-based check.

  • Graph too dense / too sparse: review your relation types. If you have too many distinct predicates, the graph becomes noisy. If you have too few, it becomes meaningless. Iterate on your schema.

What you learned & what's next

You've built a complete pipeline that creates a knowledge graph from text — from prompting an LLM for triples to assembling a queryable graph structure. You can now:

  • Explain the core pipeline: entity extraction, relation extraction, and graph assembly.
  • Apply it to your own data using Python, an LLM API, and networkx.
  • Choose between LLM extraction, traditional NLP, regex, and cloud NLU based on your needs.
  • Troubleshoot common issues like JSON parsing, entity normalization, and hallucinated triples.

In the next lesson of the Applied AI engineering track, you'll take this graph and query it with a graph database (Neo4j) to answer complex questions like "Which entities are connected to X within two hops?" You'll also learn how to visualize your graph for non-technical stakeholders. That connection turns your new knowledge graph from a toy example into a production-ready data product.

Keep practicing: build a small graph from news headlines, or try extracting a social network from a chat log. The pattern is the same, but the data variety will sharpen your skills.

Practice recap

Try building a mini knowledge graph from a set of 3–4 news headlines about a company. Define relations like 'acquires', 'launches', and 'partners_with', then extract triples with your preferred LLM. Validate the output manually and use networkx to count nodes and edges, then print the neighbors of the central company entity.

Common mistakes

  • Using too many relation types without a controlled vocabulary — the graph becomes a tangled web with no queryable pattern.
  • Forgetting to normalize entities (e.g., 'Nexium' vs 'nexium') — duplicates wreck graph integrity.
  • Trusting LLM output blindly — you must validate JSON and catch hallucinated triples.
  • Processing the entire text in one prompt when it's too long — chunk it, but also handle relations that span chunks.
  • Ignoring directionality of relations — always specify subject/object order in your prompt.

Variations

  1. Use a local LLM (e.g., Llama 3 via Ollama) for offline extraction to avoid API costs.
  2. Use a dedicated graph database like Neo4j to store and query the graph with Cypher for scalability.
  3. Combine LLM extraction with a rule-based validator to filter out low-confidence triples before insertion.

Real-world use cases

  • Automatically build a medical knowledge graph from clinical trial reports to identify drug interactions.
  • Extract a personnel and project relationship graph from corporate emails and internal wikis.
  • Create a supply chain knowledge graph from shipping documents to trace part origins and dependencies.

Key takeaways

  • A knowledge graph represents text as triples: subject, predicate, object.
  • The pipeline has three stages: entity extraction, relation extraction, and graph assembly.
  • LLMs excel at extracting implicit relations but need a controlled relation vocabulary.
  • Always validate and normalize LLM output to avoid JSON errors, duplicate entities, and hallucinations.
  • Choose between LLM, traditional NLP, regex, or cloud NLU based on cost, quality, and scalability needs.
  • Your new graph is ready for querying — often with a graph database or visualization tools.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.