Knowledge Graph Construction with Claude
You have a pile of unstructured documents and need to answer questions that span them — "who works with people who worked on project X", "which vendors are connected to this incident". No single document contains the answer. RAG retrieval won't chain the facts for you. You need a knowledge graph: entities as nodes, typed relations as edges, so that multi-hop reasoning becomes graph traversal.
Building one used to mean training a named-entity recognizer on your domain, training a relation classifier, writing entity-resolution heuristics, and maintaining all three as your data shifted. With Claude, each of those stages becomes a prompt.
What you'll learn
By the end of this guide you will be able to:
- Use structured outputs to extract typed entities and subject–predicate–object triples from arbitrary text with no training data
- Apply Claude-driven entity resolution to collapse surface-form variants into canonical nodes, replacing brittle string-similarity heuristics
- Assemble and query an in-memory graph, and run multi-hop questions by serializing subgraphs back to Claude
- Measure extraction quality with precision/recall against a gold set and reason about the cost/quality tradeoff between Haiku and Sonnet
Everything runs in memory with no database. The techniques transfer directly to Neo4j, Neptune, or a Postgres adjacency table when you need to scale.
Prerequisites
- Python 3.11+
- Anthropic API key (get one here(opens in new tab))
- Basic familiarity with graphs (nodes, edges, traversal)
Setup
We use two models. Haiku handles the high-volume, schema-constrained extraction work where speed and cost matter more than nuance. Sonnet handles entity resolution and summarization, where the model needs to weigh conflicting evidence across documents.
Building a corpus
We need a handful of documents that talk about overlapping entities, so that entity resolution has real work to do. The Apollo program is a good test bed: six short Wikipedia summaries that all mention NASA, the Moon, several astronauts, and a launch vehicle — but each article names them slightly differently.
We fetch summaries from the Wikipedia REST API rather than full articles to keep token costs low. For a production pipeline you would chunk full documents; the extraction logic is identical.
Loaded 6 documents Sample — Apollo program: The Apollo program, also known as Project Apollo, was the United States human spaceflight program led by NASA, which landed the first humans on the Moon in 1969. The Apollo program was conceived in 1960 in the Dwight D. Eisenhower presidency during Project Mercury and executed after Project Gemini. ...
Entity and relation extraction
Classical NER tags spans of text with labels (PERSON, ORG, LOC). Classical relation extraction then classifies pairs of spans into relation types. Both traditionally require labeled training data per domain.
We collapse both stages into a single Claude call per document. The key is structured outputs: we define the output shape as a Pydantic model and pass it to client.messages.parse(). Claude's response is guaranteed to validate against that schema and comes back as a typed Python object — no regex parsing, no JSON decode errors, no defensive isinstance checks.
Apollo program 7 entities 6 relations Apollo 11 7 entities 6 relations Neil Armstrong 3 entities 3 relations Saturn V 6 entities 6 relations Buzz Aldrin 8 entities 10 relations Kennedy Space Center 9 entities 13 relations Total: 40 raw entities, 44 raw relations
Let's look at what was extracted. Notice how the same real-world entity appears under different surface forms across documents — this is the entity resolution problem we solve next.
ARTIFACT (3): Lunar Module Eagle Saturn V Skylab EVENT (13): Apollo Apollo 11 Apollo program Artemis Gemini 12 Project Gemini Project Mercury Skylab Space Shuttle LOCATION (9): Cape Canaveral Space Force Station Kennedy Space Center Launch Complex 39 Merritt Island Moon ORGANIZATION (6): John F. Kennedy Space Center NASA PERSON (9): Buzz Aldrin Dwight D. Eisenhower Edwin Aldrin John F. Kennedy Michael Collins Neil Armstrong
Entity resolution
The raw extraction gives us overlapping mentions: "NASA" and "National Aeronautics and Space Administration", "Neil Armstrong" and "Armstrong", possibly "the Moon" and "Moon". If we build a graph directly from this, we get a fractured mess where the same concept is split across disconnected nodes.
Traditional approaches use string similarity (edit distance, Jaccard on tokens) plus blocking rules. That works for typos but fails on "Edwin Aldrin" vs "Buzz Aldrin" — two names with zero character overlap that refer to the same person.
We instead ask Claude to cluster entities of each type, using the one-line descriptions from extraction as disambiguation context. The descriptions matter: "Armstrong — first person to walk on the Moon" and "Armstrong — jazz trumpeter" have the same name but should not merge.
Two failure modes to watch for. First, any raw name Claude leaves out of every cluster silently disappears from the graph, because alias_to_canonical has no entry for it — a production resolver should fall back to a single-element cluster for unmatched names so nothing is lost. Second, the resolver can over-merge: a specific mission like "Gemini 12" may get folded into the broader "Project Gemini" because the descriptions overlap. The first loses nodes, the second loses precision. Both are worth spot-checking in the output below.
Entity resolution: 23 unique names → 21 canonical entities EVENT Apollo 11 EVENT Apollo program (also: Apollo) EVENT Artemis PERSON Buzz Aldrin (also: Edwin Aldrin) LOCATION Cape Canaveral Space Force Station PERSON Dwight D. Eisenhower EVENT Gemini 12 PERSON John F. Kennedy ORGANIZATION John F. Kennedy Space Center LOCATION Kennedy Space Center Launch Complex 39 ARTIFACT Lunar Module Eagle LOCATION Merritt Island PERSON Michael Collins LOCATION Moon ORGANIZATION NASA PERSON Neil Armstrong EVENT Project Gemini EVENT Project Mercury ARTIFACT Saturn V ARTIFACT Skylab EVENT Space Shuttle
Assembling the graph
With a clean alias map, we rewrite every relation endpoint to its canonical form and load the result into NetworkX. We use a MultiDiGraph because two entities can be connected by several distinct predicates ("launched from" and "operated by"), and direction matters ("Armstrong commanded Apollo 11" is not the same edge as "Apollo 11 commanded Armstrong").
Each node carries its type, the set of documents that mention it, and a mention count. Each edge carries its predicate and source document.
Graph: 21 nodes, 44 edges Connected components: 1 Most connected entities: Apollo 11 degree 12 (EVENT) Apollo program degree 11 (EVENT) John F. Kennedy Space Center degree 9 (ORGANIZATION) Moon degree 7 (LOCATION) NASA degree 6 (ORGANIZATION)

Node size scales with degree — the hubs are the entities that tie the corpus together. Color encodes type: if your graph is mostly one color, your corpus is narrow; a good mix means the extractor is finding the full cast of people, places, and things. A single connected component means entity resolution did its job — fragmented islands would indicate variants that should have merged but didn't.
Entity summarization
Each node currently carries only the one-line description from whichever document mentioned it first. For the hub nodes — the ones that show up in many documents — we can do much better: pool every mention, add the graph neighborhood as context, and have Claude synthesize a proper profile.
This is the step that turns a graph of labels into a graph of knowledge. The summaries become the node content you surface in search results or feed to downstream QA.
═══ Apollo 11 ═══ Apollo 11 was the American spaceflight that first landed humans on the Moon. It was the fifth crewed mission of NASA's Apollo program, conducted by NASA, and took place in 1969. The Lunar Module Eagle was part of the mission. The crew was Commander Neil Armstrong, Command Module Pilot Michael Collins, and Lunar Module Pilot Edwin Buzz Aldrin. All three were on their second and final spaceflight. Armstrong became the first person to walk on the Moon, and Aldrin was the second. Aldrin had earlier made three spacewalks on NASA's 1966 Gemini 12 mission. Armstrong died in 2012 and Collins in 2021, which leaves Aldrin as the last surviving Apollo 11 crew member and the oldest living astronaut. Time range: 1969 – 1969 Key facts: • Apollo 11 was the first spaceflight to land humans on the Moon. • Apollo 11 was the fifth crewed mission of NASA's Apollo program. • The crew was Neil Armstrong (Commander), Michael Collins (Command Module Pilot) and Buzz Aldrin (Lunar Module Pilot), each on their second and final spaceflight. • Neil Armstrong, commander of Apollo 11, became the first person to walk on the Moon, followed by Buzz Aldrin as the second. • Aldrin is the last surviving Apollo 11 crew member following the deaths of Armstrong in 2012 and Collins in 2021. ═══ Apollo program ═══ The Apollo program, also known as Project Apollo, was the United States human spaceflight program led by NASA. It landed the first humans on the Moon in 1969. It was conceived in 1960 during the Eisenhower presidency, while Project Mercury was under way, and was executed after Project Gemini. It was later dedicated to President John F. Kennedy's goal, stated in his May 25, 1961 address to Congress, of landing a man on the Moon and returning him safely to the Earth before the decade was out. Apollo 11 was the first mission to land humans on the Moon and the fifth crewed mission of the program. Its crew was Neil Armstrong, Michael Collins and Edwin "Buzz" Aldrin. The Saturn V, a three-stage, liquid-fueled, human-rated super heavy-lift rocket, was developed under the program for lunar exploration. Nine of the thirteen Saturn V launches sent 24 astronauts toward the Moon, from Apollo 8 to Apollo 17. Launch operations for Apollo were carried out from Kennedy Space Center Launch Complex 39 and managed by the Kennedy Space Center on Merritt Island, Florida. The sources do not state an exact end date for the program. Time range: 1960 – unknown Key facts: • The Apollo program was the U.S. human spaceflight program led by NASA, and it landed the first humans on the Moon in 1969. • The program was conceived in 1960 during the Eisenhower presidency and executed after Project Gemini. • Apollo 11, crewed by Neil Armstrong, Michael Collins and Buzz Aldrin, was the fifth crewed Apollo mission and the first to land humans on the Moon. • The Saturn V rocket was developed under the Apollo program, and nine of its thirteen launches carried 24 astronauts toward the Moon from Apollo 8 to Apollo 17. • Apollo launch operations were carried out from Kennedy Space Center Launch Complex 39 and managed by the Kennedy Space Center. ═══ John F. Kennedy Space Center ═══ The John F. Kennedy Space Center (KSC) is one of the ten field centers of NASA. It is located on Merritt Island, on the east coast of Florida. Since 1968, KSC has served as NASA's primary launch center for American spaceflight, research, and technology. Launch operations for the Apollo, Skylab, Space Shuttle, and Artemis programs were carried out from Kennedy Space Center Launch Complex 39 and managed by KSC. Launch Complex 39 is part of the center. KSC is adjacent to Cape Canaveral Space Force Station (CCSFS). The management of the two entities works closely together, shares resources, and operates facilities on each other's property. Time range: 1968 – ongoing Key facts: • The John F. Kennedy Space Center is one of the ten field centers of NASA. • KSC is located on Merritt Island, Florida, on the east coast of the state. • Since 1968, KSC has been NASA's primary launch center of American spaceflight, research, and technology. • Launch operations for the Apollo, Skylab, Space Shuttle, and Artemis programs were carried out from Launch Complex 39 and managed by KSC. • KSC is adjacent to Cape Canaveral Space Force Station; the two share resources and operate facilities on each other's property.
Querying the graph
The payoff of building a knowledge graph is multi-hop reasoning: answering questions that require chaining facts that never co-occur in a single document. "Which locations are connected to people who flew on Apollo 11?" needs the extractor to have found person→mission edges in one document and person→location edges in another, then the resolver to have unified the person nodes so those edges actually meet.
We serialize a relevant subgraph as triples and let Claude reason over it. For comparison, we first ask the same question with no graph context.
Querying 2-hop neighborhood of: Apollo program WITHOUT graph context: # Locations linked to Apollo 11 people I've grouped these by connection type, focusing mainly on the three crew members, with a few others at the end. ## Birthplaces and hometowns - **Wapakoneta, Ohio**: Neil Armstrong's hometown, now home to the Armstrong Air & Space Museum. - **Glen Ridge and Montclair, New Jersey**: Buzz Aldrin was born in Glen Ridge and attended Montclair High School. - **Rome, Italy**: Michael Collins was born here, where his father was a U.S. Army officer. ## Education and military training - **Purdue University (Indiana)**: Armstrong studied aeronautical engineering here. - **U.S. Military Academy, West Point (New York)**: Both Aldrin and Collins graduated from here. - **MIT (Massachusetts)**: Aldrin earned his doctorate in astronautics, with a thesis on orbital rendezvous. - **Korea**: Armstrong flew Navy combat missions, and Aldrin flew Air Force combat missions. ## Careers before and after Apollo - **Edwards Air Force Base / NASA Flight Research Center (California)**: Armstrong was a research test pilot here, and Collins attended the test pilot school. - **Lewis Research Center (Cleveland, Ohio)**: Armstrong's early NASA work. - **Washington, D.C.**: Collins became the director of the National Air and Space Museum. - **University of Cincinnati**: Armstrong taught aerospace engineering here after leaving NASA. ## Mission sites - **Kennedy Space Center, Launch Complex 39A (Florida)**: The launch site on July 16, 1969. - **Tranquility Base (Sea of Tranquility, Moon)**: Armstrong and Aldrin's landing site. - **Johnson Space Center / Mission Control (Houston)**: The flight controllers' base, including Flight Director Gene Kranz and capsule communicator Charlie Duke. - **Tracking stations**: Goldstone (California), Honeysuckle Creek and Parkes Observatory (Australia). Parkes and Honeysuckle Creek were crucial for relaying the moonwalk TV broadcast. - **Pacific Ocean, southwest of Hawaii**: The splashdown site, where the USS *Hornet* recovered the crew. - **Honolulu and Houston**: The crew was quarantined, first in a mobile unit aboard the *Hornet* and then at the Lunar Receiving Laboratory. ## Later life and death - **Armstrong** lived near Lebanon, Ohio, and died in Cincinnati in 2012. He was buried at sea in the Philippine Sea. - **Collins** retired in Florida (Naples and Marco Island area), died in 2021, and is buried at Arlington National Cemetery. - **Aldrin** has lived in California and Florida, and remains an advocate for Mars exploration. If you're interested in a particular person or type of place (for example mission control staff, or a travel itinerary of museums and sites), I can go deeper. ──────────────────────────────────────────────────────────── WITH graph context: **The Moon is the only location directly linked to Apollo 11 people in the graph.** **Direct connections** - Buzz Aldrin: `(Buzz Aldrin) --[walked on]--> (Moon)`. He is tied to Apollo 11 by `(Buzz Aldrin) --[crewed]--> (Apollo 11)` and `--[part of]--> (Apollo 11)`. - Neil Armstrong: `(Neil Armstrong) --[walked on]--> (Moon)`. He is tied to Apollo 11 by `(Neil Armstrong) --[commanded]--> (Apollo 11)`. The graph has no explicit "part of" edge for him, but commanding the mission implies he was part of it. **Indirect connections** - Michael Collins: `(Michael Collins) --[crewed]--> (Apollo 11)` and `--[part of]--> (Apollo 11)`. The graph has no edge linking him directly to a location. He connects to the Moon only through the mission: `(Apollo 11) --[landed on]--> (Moon)`. - Through the Apollo program, the crew is also loosely connected to Kennedy Space Center and its site. The chain is `(Apollo 11) --[part of]--> (Apollo program)`, then `(John F. Kennedy Space Center) --[managed launch operations for]--> (Apollo program)` and `(Kennedy Space Center Launch Complex 39) --[launched]--> (Apollo program)`. From there, `(John F. Kennedy Space Center) --[located on]--> (Merritt Island)` and `--[adjacent to]--> (Cape Canaveral Space Force Station)`. These links run through the program, not through the people themselves. **Not locations:** Aldrin also `--[piloted]--> (Lunar Module Eagle)`, which is `--[part of]--> (Apollo 11)`, and `--[piloted]--> (Gemini 12)`. These are spacecraft and missions, not places.
The ungrounded answer draws on Claude's pretraining and may be correct — Apollo 11 is famous. But the grounded answer is traceable: every claim cites an edge we extracted from a specific document. On a private corpus where Claude has no prior knowledge, only the grounded answer works at all.
Evaluation
Knowledge graph quality is measured with precision and recall against a gold set. We ship a small hand-labeled set in data/sample_triples.json covering two of the articles, plus data/alias_map.json which normalizes surface-form variants to the gold names so that "the Moon" and "Moon" count as the same hit.
The check below scores two things side by side: raw extractor output, and the same entities after passing through alias_to_canonical from the resolution step. When the resolver picks a canonical form the alias map knows about (or that matches gold verbatim), resolved recall climbs. When it picks a verbose form the alias map doesn't cover — say "Neil Alden Armstrong" — resolved recall can drop, because a name that matched gold before resolution no longer does after. That's not a resolver bug; it's a scoring artifact. The fix is to extend alias_map.json whenever you see a canonical form the scorer doesn't recognize.
This cell scores entities only. The standalone script also scores relations, matching on (source, target) pairs with predicate wording ignored — so its relation recall is an upper bound. Run it from the repo root:
Raw extraction vs resolved-graph recall against gold: Apollo 11 raw F1=0.78 (P=1.00 R=0.64) resolved R=0.64 still missed after resolution: columbia, kennedy space center, lunar module eagle, saturn v Neil Armstrong raw F1=0.55 (P=1.00 R=0.38) resolved R=0.38 still missed after resolution: gemini 8, korean war, nasa, purdue university, united states navy
Scaling up
This notebook processed six documents in memory. Production knowledge graphs are built from thousands. A few notes on scaling:
Extraction cost. Haiku is cheap enough to run on large corpora, but prompt caching(opens in new tab) cuts costs further when your extraction schema and instructions stay fixed — cache the system prompt and schema, pay full price only for the document text. The Message Batches API(opens in new tab) gives 50% off for jobs that can wait up to 24 hours.
Entity resolution at scale. Feeding ten thousand PERSON entities to Claude in one prompt doesn't work. Block first: group candidates by cheap signals (same last name, overlapping tokens, embedding similarity) so Claude only arbitrates within small blocks. The resolution prompt above works unchanged on blocks of 50–100.
Incremental updates. When a new document arrives, extract its entities, resolve them against the existing canonical set (not against each other), and add only the new edges. Re-summarize an entity only when its source-document set changes materially.
Storage. NetworkX is fine to a few hundred thousand edges. Beyond that, the schema maps directly onto a property graph (Neo4j, Neptune) or three Postgres tables: entities(id, name, type, summary), relations(source_id, target_id, predicate), aliases(entity_id, alias). The extraction and resolution code doesn't change — only the persistence layer does.
Summary
You've built a complete knowledge graph pipeline with nothing but prompts:
- Extraction — a single structured-output call per document replaced what used to be a trained NER model plus a trained relation classifier. The Pydantic schema is the only "training" required.
- Resolution — Claude clustered surface forms using the extraction descriptions as context, catching cases like "Edwin Aldrin" → "Buzz Aldrin" that string similarity misses entirely.
- Summarization — hub nodes got rich profiles synthesized across every document that mentioned them, with structured time ranges and traceable key facts.
- Querying — serialized subgraphs let Claude answer multi-hop questions with edge-level citations, grounding answers in the graph you built rather than pretraining.
The evaluation harness in evaluation/ gives you a feedback loop: change the extraction prompt, rerun the scorer, watch the F1 move. That loop is what turns a demo into a production system.
- Extracting structured JSON(opens in new tab) — the tool-use approach to the same extraction pattern, useful when you're already in an agentic tool-calling flow
- Retrieval augmented generation(opens in new tab) — the complementary approach when you need document retrieval rather than fact traversal
- Contextual embeddings(opens in new tab) — enriching chunks before embedding, the same "add context before indexing" idea applied to vector search
