Machine Learning Mastery

Automating Knowledge Graph Population: Extracting Entities and Triples from Unstructured Text with an LLM

6.9内容质量

TL;DR · AI 摘要

Automating Knowledge Graph Population: Extracting Entities and Triples from Unstructured Text with an LLM - MachineLearn...

核心要点

  • 主题聚焦:Automating Knowledge Graph Population: Extractin
  • 来源:Machine Learning Mastery,建议结合原文判断细节。
  • AI 分析暂不可用,本条为保底评分与摘要。
#AI#编程#后端
打开原文

Automating Knowledge Graph Population: Extracting Entities and Triples from Unstructured Text with an LLM - MachineLearningMastery.com

Automating Knowledge Graph Population: Extracting Entities and Triples from Unstructured Text with an LLM

By

Iván Palomares Carrascosa

on

September 29, 2026

in

Language Models

0

Share

Post

In this article, you will learn how to automatically extract structured knowledge from raw text and populate a knowledge graph with SPOC quads using a local LLM via Ollama.

Topics we will cover include:

  • How to set up Ollama with the Llama 3.2 model to run a free, local LLM for structured data extraction.
  • How to design a robust extraction pipeline that converts unstructured Wikipedia text into SPOC (Subject-Predicate-Object-Context) quads using few-shot prompting and JSON output mode.
  • How to load the extracted quads into a QuadStore knowledge graph, ready for use in a Graph-RAG retrieval pipeline.

Introduction

The recent article on Building a Deterministic 3-Tiered Graph-RAG System shows how a hierarchical, graph-based architecture can tackle the issue of hallucinations in standard vector information retrieval.

That article leveraged Quadstore , a lightweight knowledge graph database implemented in Python, to teach LLMs to respect ground-truth facts, thereby ensuring factual accuracy and deterministic retrieval conflict resolution in applications like RAG systems.

A critical question remains, though: where does the factual graph knowledge come from? This article helps close the loop, showing a free, fully automated approach to extract entities and build SPOC quads (Subject-Predicate-Object-Context) from raw text such as Wikipedia pages. We will do this with the help of a local, free LLM from Ollama. Once these quads are built, we will illustrate how to directly populate the Quadstore.

Prerequisites and Setup

The workflow shown in this article is designed to run seamlessly both in a Google Colab notebook and in your local Python IDE. If you choose the latter, you will need to manually install Ollama on your computer first, along with pulling the Llama 3.2 model locally.

In Google Colab, you can set up Ollama and get Llama 3.2 for your open session using these commands:

!apt-get update -qq && apt-get install -y -qq zstd !curl -fsSL https://ollama.com/install.sh | sh

1

2

!

apt

-

get

update

qq

&&

install

y

zstd

curl

fsSL

https

:

//ollama.com/install.sh | sh

Either way, you will need to install these two libraries as well:

!pip install wikipedia requests

pip

wikipedia

requests

Llama 3.2 is a lightweight, free model. Its API is configured to strictly operate in JSON input/output mode, a mandatory standard for reliable data extraction. Using subprocess , we can start the Ollama server as a background process and pull our target model:

import subprocess import time # 1. Starting the Ollama server in the background print("Starting Ollama server...") process = subprocess.Popen(["ollama", "serve"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) time.sleep(3) # Give the server a moment to start # 2. Pulling the Llama 3.2 model (this may take a minute or two on Colab) print("Pulling Llama 3.2...") subprocess.run(["ollama", "pull", "llama3.2"]) print("Model ready!")

3

4

5

6

7

8

9

10

11

12

import

subprocess

time

1. Starting the Ollama server in the background

print

(

"Starting Ollama server..."

)

process

=

.

Popen

[

"ollama"

,

"serve"

]

stdout

DEVNULL

stderr

sleep

Give the server a moment to start

2. Pulling the Llama 3.2 model (this may take a minute or two on Colab)

"Pulling Llama 3.2..."

run

"pull"

"llama3.2"

"Model ready!"

Automated Knowledge Graph Population

Let’s look at the process of constructing our knowledge graph from a source of raw text. We will convert narrative text into strictly modeled relationships that extend classical RDF triples of the form (Subject, Predicate, Object) by adding a fourth dimension: the context. This is useful for tracking where a fact comes from and whether it is true or not.

A triple like ("LeBron James", "plays_for", "Lakers") thus becomes ("LeBron James", "plays_for", "Lakers", "NBA_2023_Roster") .

First, we will create a small, simulated QuadStore engine that mimics the framework used in the related article this one follows up on. If you are working in a notebook, run this code in a separate cell to generate a quadstore.py file in your workspace on the fly:

%%writefile quadstore.py class QuadStore: def __init__(self): # Using a simple list to store the facts for our lightweight implementation self.quads = [] def add(self, subject, predicate, obj, context): """Adds a new SPOC quad to the knowledge graph.""" quad = (subject, predicate, obj, context) if quad not in self.quads: self.quads.append(quad) def query(self, subject=None, predicate=None, obj=None, context=None): """Queries the graph. Returns a list of quads that match the provided criteria.""" results = [] for q_sub, q_pred, q_obj, q_ctx in self.quads: if (subject is None or subject == q_sub) and \ (predicate is None or predicate == q_pred) and \ (obj is None or obj == q_obj) and \ (context is None or context == q_ctx): results.append((q_sub, q_pred, q_obj, q_ctx)) return results

13

14

15

16

17

18

19

20

21

22

23

%

writefile

quadstore

py

class

def

__init__

self

Using a simple list to store the facts for our lightweight implementation

quads

add

subject

predicate

obj

context

""

"Adds a new SPOC quad to the knowledge graph."

quad

if

not

append

query

None

"Queries the graph. Returns a list of quads that match the provided criteria."

results

for

q_sub

q_pred

q_obj

q_ctx

is

or

==

and

\

return

A file containing exactly the above code will be created, and we will refer to it later on just like any other Python module, to demonstrate how to load our created knowledge graph into our mock Graph-RAG system.

Back to the main process: we will now pull some raw text from Wikipedia using the namesake API. The auto_suggest=False option ensures we correctly fetch the right article name from Wikipedia without automated corrections that may cause a crash.

import wikipedia print("Fetching Wikipedia summary...") # Disabling auto_suggest to prevent the library from renaming "Turing" to "tuning" wiki_page = wikipedia.page("Alan Turing", auto_suggest=False) text_content = wiki_page.summary # We'll just take the first two paragraphs of the Wikipedia page to keep extraction fast paragraphs = text_content.split('\n')[:2] short_text = " ".join(paragraphs) print(f"Extracted {len(short_text)} characters of text ready for processing.")

"Fetching Wikipedia summary..."

Disabling auto_suggest to prevent the library from renaming "Turing" to "tuning"

wiki_page

page

"Alan Turing"

auto_suggest

False

text_content

summary

We'll just take the first two paragraphs of the Wikipedia page to keep extraction fast

paragraphs

split

'\n'

short_text

" "

join

f

"Extracted {len(short_text)} characters of text ready for processing."

Output:

Fetching Wikipedia summary... Extracted 1244 characters of text ready for processing.

Fetching

Extracted

1244

characters

of

text

ready

processing

Now comes the core of the entire workflow: the robust extraction engine, modeled by the following function that:

  • Works with the target LLM’s formatting engine to extract structured data in the form of quads. To do this, we use few-shot examples as part of the prompt sent to the LLM.
  • Post-processes the LLM output to extract a list of facts and build a list of quads accordingly.

import json import requests def extract_spoc_quads_final(text, context_label, model="llama3.2"): # To abide by Llama3.2's output mode, we ask for a JSON object with a "facts" key prompt = f""" You are an expert data extraction algorithm. Extract atomic facts from the text. You must output a valid JSON object containing a single key called "facts". The value of "facts" must be an array of objects. Example output format: {{ "facts": [ {{"subject": "LeBron James", "predicate": "plays_for", "object": "Lakers"}}, {{"subject": "Lakers", "predicate": "based_in", "object": "Los Angeles"}} ] }} Text to process: {text} """ payload = { "model": model, "prompt": prompt, "format": "json", "stream": False, "temperature": 0.0 } try: response = requests.post('http://localhost:11434/api/generate', json=payload) response.raise_for_status() raw_llm_text = response.json()['response'] parsed_json = json.loads(raw_llm_text) # Looking specifically for the "facts" array triples = parsed_json.get("facts", []) # Fallback: If the LLM still used a different key, grab the first list we find if not triples and isinstance(parsed_json, dict): for key, value in parsed_json.items(): if isinstance(value, list): triples = value break quads = [] for t in triples: if not isinstance(t, dict): continue # Converting keys to lowercase to catch "Subject" vs "subject" normalized_t = {str(k).lower().strip(): str(v).strip() for k, v in t.items()} if all(k in normalized_t for k in ('subject', 'predicate', 'object')): quads.append({ "subject": normalized_t['subject'], "predicate": normalized_t['predicate'], "object": normalized_t['object'], "context": context_label }) return quads except Exception as e: print(f"Extraction failed: {e}") return []

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

json

extract_spoc_quads_final

context_label

model

To abide by Llama3.2's output mode, we ask for a JSON object with a "facts" key

prompt

"

You are an expert data extraction algorithm. Extract atomic facts from the text.

You must output a valid JSON object containing a single key called "

facts

".

The value of "

" must be an array of objects.

Example output format:

{{

": [

{{"

": "

LeBron

James

", "

plays

_

object

Lakers

"}},

based

Los

Angeles

"}}

}}

Text to process:

{text}

payload

{

"model"

"prompt"

"format"

"json"

"stream"

"temperature"

0.0

}

try

response

'http://localhost:11434/api/generate'

raise_for_status

raw_llm_text

'response'

parsed_json

loads

Looking specifically for the "facts" array

triples

"facts"

Fallback: If the LLM still used a different key, grab the first list we find

isinstance

dict

key

value

items

list

break

t

continue

Converting keys to lowercase to catch "Subject" vs "subject"

normalized_t

str

k

lower

strip

v

all

'subject'

'predicate'

'object'

"subject"

"predicate"

"object"

"context"

label

except

Exception

as

e

"Extraction failed: {e}"

All that remains is running the pipeline to extract, view, and make use of our newly created quads, which will constitute our knowledge graph.

print("Beginning extraction (this takes a few seconds on a Colab T4 GPU)...\n") extracted_quads = extract_spoc_quads_final( text=short_text, context_label="Wikipedia_Alan_Turing" ) # Viewing the results for quad in extracted_quads: print(f"S: {quad['subject']:<20} | P: {quad['predicate']:<15} | O: {quad['object']:<25} | C: {quad['context']}")

"Beginning extraction (this takes a few seconds on a Colab T4 GPU)...\n"

extracted_quads

"Wikipedia_Alan_Turing"

Viewing the results

"S: {quad['subject']:<20} | P: {quad['predicate']:<15} | O: {quad['object']:<25} | C: {quad['context']}"

Results:

Beginning extraction (this takes a few seconds on a Colab T4 GPU)... S: Alan Mathison Turing | P: was | O: an English mathematician, computer scientist, logician, cryptanalyst, philosopher and theoretical biologist | C: Wikipedia_Alan_Turing S: Alan Mathison Turing | P: was born | O: in London | C: Wikipedia_Alan_Turing S: Alan Mathison Turing | P: was raised | O: in southern England | C: Wikipedia_Alan_Turing S: Alan Mathison Turing | P: graduated from | O: King's College, Cambridge | C: Wikipedia_Alan_Turing S: Alan Mathison Turing | P: earned | O: a doctorate degree from Princeton University | C: Wikipedia_Alan_Turing S: Alan Mathison Turing | P: worked for | O: the Government Code and Cypher School at Bletchley Park | C: Wikipedia_Alan_Turing S: Alan Mathison Turing | P: led | O: Hut 8, the section responsible for German naval cryptanalysis | C: Wikipedia_Alan_Turing S: Alan Mathison Turing | P: devised techniques for | O: speeding the breaking of German ciphers | C: Wikipedia_Alan_Turing S: Alan Mathison Turing | P: played a crucial role in | O: cracking intercepted messages that enabled the Allies to defeat the Axis powers | C: Wikipedia_Alan_Turing S: Alan Mathison Turing | P: is | O: widely considered to be the father of theoretical computer science | C: Wikipedia_Alan_Turing S: Alan Mathison Turing | P: was | O: influential in the development of theoretical computer science | C: Wikipedia_Alan_Turing

Beginning

extraction

this

takes

a

few

seconds

Colab

T4

GPU

S

Alan

Mathison

Turing

|

P

was

O

an

English

mathematician

computer

scientist

logician

cryptanalyst

philosopher

theoretical

biologist

C

Wikipedia_Alan

born

London

raised

southern

England

graduated

from

King

'

College

Cambridge

earned

doctorate

degree

Princeton

University

worked

the

Government

Code

Cypher

School

at

Bletchley

Park

led

Hut

section

responsible

German

naval

cryptanalysis

devised

techniques

speeding

breaking

ciphers

played

crucial

role

cracking

intercepted

messages

that

enabled

Allies

to

defeat

Axis

powers

widely

considered

be

father

science

influential

development

Wikipedia_Alan_Turing

From just two paragraphs of Alan Turing’s Wikipedia article, we extracted around 11 facts, structured as quads. Note that the exact number may vary slightly due to the non-deterministic behavior of the LLM.

We wrap up by seeing how to add these facts into the QuadStore object:

from quadstore import QuadStore facts_qs = QuadStore() for quad in extracted_quads: facts_qs.add( quad["subject"], quad["predicate"], quad["object"], quad["context"] ) print(f"Successfully loaded {len(extracted_quads)} automated facts into the Graph RAG system!")

facts_qs

"Successfully loaded {len(extracted_quads)} automated facts into the Graph RAG system!"

Successfully loaded 11 automated facts into the Graph RAG system!

Successfully

loaded

automated

into

Graph

RAG

system

Conclusion

This article closed the loop on our deterministic 3-tiered Graph-RAG architecture by showing how to build a knowledge graph consisting of facts extracted directly from unstructured text in the form of quads — all from scratch. You can now integrate this knowledge into your retrieval pipeline to help eliminate issues like LLM hallucinations.

More On This Topic

  • Clustering Unstructured Text with LLM Embeddings and HDBSCAN
  • Automating Data Cleaning Processes with Pandas
  • Introduction to AutoML: Automating Machine Learning…
  • Extracting Histogram of Gradients with OpenCV
  • 3 Feature Engineering Techniques for Unstructured Text Data
  • The Role of Domain Knowledge in Machine Learning:…

/.entry