<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet href="/feed_style.xsl" type="text/xsl"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="https://www.rssboard.org/media-rss"><channel><title>Knowledge Extraction on DazzLog</title><link>https://blog.dazzlog.de/tags/knowledge-extraction/</link><description>Recent content in Knowledge Extraction on DazzLog</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>dazz - [Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/).</copyright><lastBuildDate>Fri, 17 Jul 2026 23:42:27 +0100</lastBuildDate><atom:link href="https://blog.dazzlog.de/tags/knowledge-extraction/index.xml" rel="self" type="application/rss+xml"/><icon>https://blog.dazzlog.de/logo.svg</icon><item><title>Four Ways to Extract Knowledge from Unstructured Data (and Why RAG Isn't One of Them)</title><link>https://blog.dazzlog.de/posts/2026-07-17_knowledge-extraction/</link><pubDate>Fri, 17 Jul 2026 23:42:27 +0100</pubDate><guid>https://blog.dazzlog.de/posts/2026-07-17_knowledge-extraction/</guid><description><![CDATA[<h2 id="the-problem-knowledge-trapped-in-the-unstructured">The problem: knowledge trapped in the unstructured</h2>
<p>Every video you watch, every long-form article you read, every podcast transcript sitting in a folder somewhere contains knowledge that is, structurally speaking, in the worst possible shape for reuse. It&rsquo;s linear. It&rsquo;s redundant. It&rsquo;s mixed with filler, tangents, and repetition. The same concept might be explained three different ways across forty minutes, buried between an ad read and a rambling aside about the weather. If you want to <em>use</em> that knowledge later — cite it, search it, connect it to something you learned six videos ago, hand it to an agent as durable context — you cannot use the transcript directly. You have to extract.</p>
<p>This is a narrower and more specific problem than &ldquo;how do I build a chatbot over my documents.&rdquo; It&rsquo;s tempting to conflate the two, because in 2024–2026 the default answer to almost any &ldquo;I have a pile of documents and want to do something smart with them&rdquo; question has become <em>just RAG it</em>. But extraction and retrieval are different problems, and building a system that treats them as the same thing tends to produce something that&rsquo;s good at neither: a search index dressed up as a knowledge base, or a knowledge base that only reveals its contents through a chat window.</p>
<p>The distinction that matters is this: <strong>extraction asks &ldquo;what is the durable, reusable knowledge in this source, and what form should it take so a human or an agent can consume it without re-processing the source?&rdquo;</strong> Retrieval — RAG — asks a completely different question: <strong>&ldquo;given a query right now, what&rsquo;s the most relevant material to feed an LLM so it can answer?&rdquo;</strong> The first produces an artifact. The second produces an answer. You can build the second on top of the first, but not the other way around, and treating them as interchangeable is where a lot of &ldquo;AI knowledge base&rdquo; projects quietly go wrong.</p>
<p>This post walks through four real approaches to this problem — Triplet Extraction, RAG, Ontology-style entity resolution, and OKF (Open Knowledge Format) — grounded in an actual system that implements three of them against the same source material: video transcripts from a YouTube-monitoring pipeline called DazzHub. Rather than treat these abstractly, every claim below is backed by a real run: real extracted triplets, a real generated OKF document, and real cluster data from an ontology experiment.</p>
<p>The video used as the running case study across three of the four sections is <em>&ldquo;Context Is the New Code&rdquo;</em> by Patrick Debois (Tessl), a talk about treating AI-agent context — prompts, instructions, specs, skills — as an engineered software artifact with its own development lifecycle. It&rsquo;s a good test case precisely because it&rsquo;s dense with named concepts, has a clear conceptual thesis, and overlaps thematically with material already processed by other parts of the same pipeline.</p>
<hr>
<h2 id="triplet-extraction-knowledge-as-an-edge-list">Triplet Extraction: knowledge as an edge list</h2>
<h3 id="what-it-is">What it is</h3>
<p>Triplet extraction is the most structurally minimal of the four approaches. You give an LLM a chunk of text and ask it to output a list of <code>(subject, predicate, object)</code> statements — the same shape as an RDF triple, the atomic unit of a knowledge graph. In the system studied here, the schema is deliberately constrained: a fixed enum of roughly ten entity types (<code>person</code>, <code>technology</code>, <code>concept</code>, <code>method</code>, <code>event</code>, <code>product</code>, and a few others) and exactly six predicates: <code>is_a</code>, <code>part_of</code>, <code>uses</code>, <code>requires</code>, <code>enables</code>, <code>applies_to</code>.</p>
<p>This is a real design decision with a real tradeoff. An open predicate vocabulary — let the LLM invent whatever relationship name fits — gives you expressiveness: &ldquo;Patrick Debois <em>pioneered</em> DevOps&rdquo; is more informative than forcing it into <code>uses</code> or <code>enables</code>. But an open vocabulary also gives you an explosion of near-duplicate predicates (<code>created</code>, <code>invented</code>, <code>pioneered</code>, <code>originated</code> all meaning roughly the same thing) that make the resulting graph nearly impossible to query consistently. A closed, small predicate set buys you exactly the opposite: every edge in the graph is guaranteed to be one of six types, which means you can write a Cypher query like &ldquo;find everything that <code>enables</code> X&rdquo; and trust that it will actually match semantically similar statements phrased differently in the source text, because the LLM was forced to normalize at extraction time rather than leaving normalization as a downstream problem nobody solves.</p>
<h3 id="what-it-actually-produced">What it actually produced</h3>
<p>Running this extractor against all 18 transcript chunks of the Patrick Debois talk (using gpt-5.2) produced 296 distinct triplets. The predicate distribution tells you something real about what this kind of extraction is <em>actually</em> good at capturing:</p>
<table>
	<thead>
			<tr>
					<th>Predicate</th>
					<th>Count</th>
					<th>Share</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>uses</code></td>
					<td>76</td>
					<td>25.7%</td>
			</tr>
			<tr>
					<td><code>enables</code></td>
					<td>69</td>
					<td>23.3%</td>
			</tr>
			<tr>
					<td><code>applies_to</code></td>
					<td>57</td>
					<td>19.3%</td>
			</tr>
			<tr>
					<td><code>requires</code></td>
					<td>56</td>
					<td>18.9%</td>
			</tr>
			<tr>
					<td><code>is_a</code></td>
					<td>20</td>
					<td>6.8%</td>
			</tr>
			<tr>
					<td><code>part_of</code></td>
					<td>18</td>
					<td>6.1%</td>
			</tr>
	</tbody>
</table>
<p>Notice what&rsquo;s <em>not</em> well represented: <code>is_a</code> and <code>part_of</code> — the two predicates that build an actual taxonomy or hierarchy — make up under 13% combined. The graph this produces is overwhelmingly relational-procedural (&ldquo;X uses Y,&rdquo; &ldquo;X enables Y,&rdquo; &ldquo;X requires Y&rdquo;) rather than hierarchical. That&rsquo;s not necessarily wrong — a talk about context engineering is more about workflows and dependencies than about class hierarchies — but it means you shouldn&rsquo;t expect a triplet-extraction pass to hand you a clean ontology for free. It gives you a graph of <em>how things relate procedurally</em>, not <em>what kind of thing something is</em>.</p>
<p>The more interesting — and more honest — finding is a quality issue that shows up immediately on inspection. A meaningful fraction of the extracted triplets look like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>Patrick Debois (person) --uses--&gt; skill (concept)
</span></span><span style="display:flex;"><span>Patrick Debois (person) --uses--&gt; parallel thinking (method)
</span></span><span style="display:flex;"><span>Patrick Debois (person) --uses--&gt; Context is the New Code (event)
</span></span><span style="display:flex;"><span>Patrick Debois (person) --enables--&gt; helper code conversion into skill (concept)
</span></span></code></pre></div><p>Roughly a quarter of all 296 edges have the speaker himself as the subject. This is a completely faithful extraction — the source material really does describe Patrick Debois using and enabling these things — but it&rsquo;s a subtly different thing from <em>durable knowledge</em>. &ldquo;Patrick Debois uses parallel thinking&rdquo; is a fact about a talk, not a fact about the world you&rsquo;d want sitting in a knowledge base six months later disconnected from its source. It&rsquo;s the triplet-extraction equivalent of a transcript that never lets go of its own narrator: every statement is anchored to &ldquo;the person talking,&rdquo; rather than being lifted out into a speaker-independent claim like &ldquo;parallel thinking (method) → applies_to → context engineering (concept),&rdquo; which the same extraction pass <em>also</em> produced, correctly, elsewhere in the same run.</p>
<p>This is not a flaw unique to this implementation — it&rsquo;s close to structurally inevitable for chunk-level triplet extraction done without an explicit instruction to strip speaker attribution, because from the LLM&rsquo;s point of view, &ldquo;the speaker did/used/enabled X&rdquo; is exactly as true and exactly as extractable as any other claim in the transcript. Fixing it isn&rsquo;t hard (a prompt instruction to prefer the depersonalized claim when both are present, or a post-filter that drops edges where the subject is a <code>person</code> type matching the known speaker), but it&rsquo;s a real, concrete illustration of a general truth about triplet extraction: <strong>the schema constrains form, not judgment.</strong> You still need a second pass — a prompt refinement, a filter, or a human — to separate &ldquo;this is durable knowledge&rdquo; from &ldquo;this is faithfully what was said.&rdquo;</p>
<h3 id="where-it-lives-and-what-its-for">Where it lives, and what it&rsquo;s for</h3>
<p>Structurally, these triplets get written to a <code>knowledge_graph</code> JSON column on the source chunk and then synced into Neo4j, where entities are merged by <code>{name, type}</code> and relationships accumulate a <code>source_chunk_id</code> array so the same relationship discovered independently in five different chunks — or five different videos — collapses onto one edge rather than creating five duplicates. This is real, working, exact-match deduplication: mention &ldquo;Retrieval Augmented Generation (concept)&rdquo; in three different chunks and you get one node, not three, with three source citations attached.</p>
<p>That&rsquo;s the ceiling of what this dedup mechanism can do, though: it&rsquo;s a string-equality merge on a normalized label. &ldquo;RAG,&rdquo; &ldquo;retrieval augmented generation,&rdquo; and &ldquo;Retrieval-Augmented Generation&rdquo; will only merge if something upstream normalizes them to the same string first. It has no notion that &ldquo;encoder-based retrieval&rdquo; and &ldquo;Retrieval Augmented Generation&rdquo; are the same underlying concept described two different ways — that&rsquo;s a semantic-similarity problem, and triplet extraction alone doesn&rsquo;t solve it. (We&rsquo;ll come back to who does.)</p>
<p>What triplet extraction is genuinely good for: feeding a graph database that supports relationship queries and graph algorithms — shortest-path reasoning, &ldquo;what depends on what,&rdquo; GraphRAG-style retrieval where you walk relevant edges instead of doing pure vector search. It&rsquo;s the right tool when the <em>shape of the relationships</em> is the thing you want to query, not when you want something a human reads top to bottom.</p>
<hr>
<h2 id="rag-not-an-extraction-method-an-access-pattern">RAG: not an extraction method, an access pattern</h2>
<h3 id="what-it-actually-is">What it actually is</h3>
<p>Retrieval-Augmented Generation deserves a section here specifically <em>because</em> it&rsquo;s so often treated as a peer alternative to the other three approaches, when it structurally isn&rsquo;t one. RAG is: at query time, retrieve some relevant material from a store, stuff it into an LLM&rsquo;s context window alongside the user&rsquo;s question, and generate an answer. That&rsquo;s it. Nothing about that definition says anything about <em>how the store got populated</em> or <em>what form the knowledge takes inside it</em>.</p>
<p>This matters because the store RAG retrieves from can be almost anything. The most common setup — chunk raw documents, embed the chunks, do vector similarity search — is really &ldquo;RAG over raw, unprocessed text,&rdquo; and it inherits every weakness of unprocessed text: no deduplication, no cross-document concept resolution, no distinction between the two paragraphs that actually matter and the eight that are filler, because nothing was ever <em>extracted</em> — only <em>chunked and indexed</em>. You can equally well run RAG over a collection of OKF documents (retrieve the curated concept summaries instead of raw transcript chunks — sharper signal, less noise), or over triplet-extracted graph data (this is what &ldquo;GraphRAG&rdquo; specifically means: instead of vector-searching chunks, you walk the graph structure — communities, entity neighborhoods — to assemble context, which is exactly what Microsoft&rsquo;s GraphRAG architecture and the Ontology pipeline described below both do). RAG is the delivery mechanism. It is agnostic to — and entirely dependent on the quality of — whatever sits underneath it.</p>
<h3 id="the-category-error">The category error</h3>
<p>Here&rsquo;s the concrete failure mode this framing is meant to prevent: a team decides they want &ldquo;a knowledge base of everything we&rsquo;ve learned from our video library.&rdquo; They stand up a vector store, chunk the transcripts, wire up a chat interface, and call it done. Ask it a question and it gives you a reasonable-sounding answer, stitched together from three retrieved chunks, and it <em>feels</em> like the knowledge has been captured. But nothing has actually been extracted. There is no artifact you can browse. There is no deduplicated concept list. There is no way to answer &ldquo;what does this corpus know about X&rdquo; except by asking the chatbot and hoping the retrieval step surfaces the right chunks — and if the same concept was mentioned in twelve different videos with twelve different phrasings, the chatbot might synthesize a coherent-sounding answer from three of them and never surface the other nine, with no way for you to know that happened.</p>
<p>RAG optimizes for &ldquo;answer this specific question well, right now.&rdquo; It does not optimize for, and typically does not produce, &ldquo;here is the browsable, citable, deduplicated body of knowledge this corpus contains.&rdquo; If what you actually want is the second thing, doing RAG <em>instead of</em> extraction doesn&rsquo;t get you there faster — it just defers the extraction problem to query time, every time, forever, without ever paying down the debt. The chatbot experience can feel like a substitute for a knowledge base right up until you need something a chatbot can&rsquo;t give you: an exportable dataset, a static page you can skim, a citation trail you can audit, or confidence that &ldquo;no answer was found&rdquo; actually means &ldquo;this isn&rsquo;t in the corpus&rdquo; rather than &ldquo;the retrieval step didn&rsquo;t surface the right three chunks this time.&rdquo;</p>
<p>None of this is an argument against RAG. It&rsquo;s an argument for knowing which problem you&rsquo;re solving. If the product is genuinely &ldquo;let a user ask ad-hoc questions of a large corpus,&rdquo; RAG — ideally layered over one of the three extraction approaches below rather than over raw chunks — is exactly right. If the product is &ldquo;produce a knowledge base people and agents can browse, cite, and build on independent of any specific question,&rdquo; RAG is the wrong layer to start with, because it&rsquo;s not building anything that persists.</p>
<hr>
<h2 id="ontology-the-heaviest-machinery-and-the-only-one-that-really-resolves-entities-across-sources">Ontology: the heaviest machinery, and the only one that really resolves entities across sources</h2>
<h3 id="the-pipeline">The pipeline</h3>
<p>Of the four approaches, Ontology-style extraction is the only one that attempts genuine cross-source entity resolution — recognizing that &ldquo;the thing mentioned in video A&rdquo; and &ldquo;the thing mentioned in video B&rdquo; are the same concept, even when phrased differently, and merging them into one canonical node with both sources cited. That capability is valuable enough to be worth its considerable complexity, so it&rsquo;s worth walking through the full pipeline as it actually runs:</p>
<ol>
<li><strong>Candidate discovery.</strong> An LLM pass over each video (or transcript chunk) identifies candidate ontology classes and properties — raw, unresolved mentions, each carrying a verbatim evidence quote and a confidence score. This stage is isolated per source; nothing is merged yet.</li>
<li><strong>Embedding generation.</strong> Every candidate gets a vector embedding (pgvector), turning &ldquo;raw label similarity&rdquo; into something a distance metric can operate on.</li>
<li><strong>Global clustering.</strong> Candidates of the same kind (class vs. property) are clustered by cosine similarity across the <em>entire</em> candidate pool — not per video, globally — with a configurable similarity threshold (0.85 in this system). This is the actual cross-source merge step: two mentions of conceptually the same thing, embedded close together regardless of which video they came from, land in the same cluster.</li>
<li><strong>LLM coherence validation.</strong> Because embedding similarity alone can be wrong — near-neighbors in embedding space aren&rsquo;t always the same concept — an LLM pass checks each cluster for internal coherence and can split it into sub-clusters if it&rsquo;s actually conflating two distinct ideas.</li>
<li><strong>Hierarchical community detection.</strong> Validated clusters become nodes in a graph (edges derived from validated property relationships), and a Leiden community-detection algorithm groups them into three hierarchical levels of topic communities.</li>
<li><strong>LLM community reports.</strong> For each detected community, an LLM pass generates a title, summary, and key-themes digest — essentially the &ldquo;so what does this cluster of concepts, spanning however many sources, actually mean&rdquo; step.</li>
<li><strong>Neo4j export + GDS.</strong> The resolved entity/community graph is pushed into Neo4j, where a real Graph Data Science call (<code>gds.node2vec.stream</code>) computes structural embeddings for downstream use.</li>
</ol>
<h3 id="what-actually-happened-when-this-ran">What actually happened when this ran</h3>
<p>The numbers from the real experiment this system ran are worth sitting with, because they&rsquo;re a useful corrective to how clean this sounds in the abstract. Across four videos, the pipeline produced 1,031 raw candidates, resolved into 284 clusters, grouped into 280 communities — and only 19 of those 284 clusters actually merge candidates from more than one of the four source videos. The other 265 are single-video clusters that happen to have survived the clustering step without finding a cross-video match, simply because the four source videos covered different enough topics (knowledge graphs vs. vector databases, multimodal models, BERT, technical-document summarization) that most concepts genuinely didn&rsquo;t recur. Of the 280 communities, only 8 have an LLM-generated report — report generation is feature-flagged off by default, so unless someone manually triggers it, you get the structural clustering with no human-readable digest layered on top.</p>
<p>Where it <em>did</em> work is genuinely compelling. One of the 19 cross-video clusters resolved to the canonical concept &ldquo;Retrieval Augmented Generation,&rdquo; correctly merging 13 separate mentions from two different videos — one about knowledge graphs versus vector databases, one about BERT — including phrasings as different as <em>&ldquo;traditional retrieval augmented generation systems&hellip; has really become a core component&rdquo;</em> and <em>&ldquo;you&rsquo;ve likely interacted with encoder based models through the form of retrieval augmented generation.&rdquo;</em> Two videos, on two different topics, both mentioning RAG in passing, correctly recognized as talking about the same thing and merged into a single node with both sources cited. That is the actual value proposition of this whole approach, demonstrated concretely: not &ldquo;extract facts,&rdquo; but &ldquo;recognize that this fact and that fact, from different sources, are the same fact.&rdquo;</p>
<h3 id="the-cost-of-that-capability">The cost of that capability</h3>
<p>That result is real, but so is the cost of getting it. This is a six-stage pipeline requiring a vector database, a graph database, a graph algorithms library, a custom community-detection implementation, and at least three separate LLM calls per candidate lifecycle (discovery, validation, and — optionally — report generation). The Leiden community-detection implementation in this system is explicitly documented in its own code comments as a <em>&ldquo;simplified, didactic implementation,&rdquo;</em> not a call to Neo4j GDS&rsquo;s production Leiden/Louvain algorithms — and the hierarchical level-2 recursion is, as of this writing, an unimplemented stub. Real GDS is used, but only for the node2vec structural-embedding step, which is a downstream enhancement on top of the resolution mechanism, not the resolution mechanism itself.</p>
<p>The project this was built for paused the entire ontology effort after this experiment, for reasons worth stating plainly because they&rsquo;re common and not unique to this codebase: the local LLM being used for candidate discovery was slow enough that iterating on the pipeline was painful, and the owner wasn&rsquo;t confident the resulting cluster/community quality was good enough to justify the machinery — a reasonable conclusion to reach after actually building the thing and looking hard at the output, rather than a reason to have not built it at all. Real cross-source entity resolution is valuable. It is also genuinely expensive to build well, and &ldquo;built but unvalidated&rdquo; is a meaningfully different state than &ldquo;built and trustworthy.&rdquo;</p>
<h2 id="okf-the-readable-one-isolated-per-source">OKF: the readable one, isolated per source</h2>
<h3 id="the-design">The design</h3>
<p>Open Knowledge Format takes the opposite bet from Ontology: instead of resolving entities across many sources through a multi-stage pipeline, do one clean LLM call per source and force the output into a structured, human-readable document. The system prompt driving this extraction is explicit about the philosophy: <em>&ldquo;CURATE, DON&rsquo;T TRANSCRIBE: capture durable knowledge (concepts, facts, definitions, relationships), not narration, filler, or chatter,&rdquo;</em> and <em>&ldquo;NEUTRAL VOICE: state knowledge directly; never write &rsquo;the video,&rsquo; &rsquo;the creator,&rsquo; or &rsquo;this episode.&rsquo;&rdquo;</em> The output schema is a YAML-frontmatter markdown document: a <code>type</code> (always <code>&quot;video-knowledge&quot;</code>), <code>title</code>, <code>category</code>, <code>confidence</code> (high/medium/low), <code>tags</code>, a short <code>summary</code>, and then structured lists — <code>keyConcepts</code>, <code>facts</code>, <code>definitions</code>, <code>relatedConcepts</code> — each rendered as a markdown section.</p>
<p>Run against the Patrick Debois talk, this produced a document that opens:</p>
<blockquote>
<p>AI-assisted software development increasingly depends on engineered &ldquo;context&rdquo; (prompts, instructions, specs, retrieved docs, skills) as a primary artifact that drives agent behavior. A context development lifecycle mirrors SDLC/DevOps loops: generate context, test/evaluate it with deterministic-like harnesses, distribute it as reusable packages, and observe outcomes via logs and production feedback to iteratively improve.</p>
</blockquote>
<p>— followed by key concepts like &ldquo;Context as a first-class software artifact,&rdquo; &ldquo;Nondeterminism-aware CI for evals&rdquo; (with the concrete detail that the same eval run multiple times can yield different outcomes and should be evaluated statistically rather than pass/fail), and definitions like <em>&ldquo;Skill: a packaged, reusable unit of context&hellip; intended to be installed/used by agents across projects; analogous to a software library/package.&rdquo;</em></p>
<p>Read that against the triplet output from the same video — <code>Patrick Debois (person) --uses--&gt; skill (concept)</code> — and the difference in <em>legibility</em> is immediate. One requires you to reconstruct meaning from an edge list. The other is a paragraph you can read in fifteen seconds and understand the actual argument of the talk. For a human trying to quickly grasp &ldquo;what was this video actually about,&rdquo; OKF wins decisively, and it&rsquo;s not close.</p>
<h3 id="the-limitation">The limitation</h3>
<p>The catch is exactly the thing Ontology was built to solve and OKF doesn&rsquo;t attempt: this document lives entirely on its own. There is one OKF file per video, generated independently, with no mechanism to notice that &ldquo;Skill: a packaged, reusable unit of context&rdquo; in this video&rsquo;s OKF and whatever the <em>next</em> video&rsquo;s OKF says about skills are talking about the same concept. If you process five hundred videos and eighty of them touch on &ldquo;context engineering&rdquo; in some way, you get eighty separate, redundant explanations of context engineering, scattered across eighty files, each written as if it were the only source that ever mentioned it. There&rsquo;s no cross-referencing, no canonical entry, no way to ask &ldquo;show me everything the corpus knows about skills&rdquo; except by opening every file and reading them all.</p>
<p>This is precisely the tension between the two approaches sitting side by side: OKF is legible but siloed; Ontology is resolved but heavy, complex, and — in this system&rsquo;s current state — not yet trusted enough to run unsupervised. Neither, on its own, is quite the thing you want if the goal is a genuinely browsable knowledge base that doesn&rsquo;t duplicate itself into uselessness at scale.</p>
<h2 id="the-synthesis-concept-files-or-okfs-simplicity-with-ontologys-memory">The synthesis: concept files, or OKF&rsquo;s simplicity with Ontology&rsquo;s memory</h2>
<p>There&rsquo;s a middle path here that&rsquo;s worth spelling out, because it falls directly out of naming what each approach gets right and wrong. OKF&rsquo;s strength is that creating a document is <em>cheap</em>: one LLM call, one clean markdown artifact, easy to reason about, easy to read. Ontology&rsquo;s strength is that it <em>remembers</em>: a new mention of a known concept doesn&rsquo;t create a duplicate, it strengthens an existing canonical node with a new citation. The expensive, fragile part of Ontology isn&rsquo;t the remembering — the embedding-similarity lookup that decides &ldquo;have we seen this concept before&rdquo; is a single, well-understood, already-working piece of infrastructure (pgvector cosine similarity against existing candidate embeddings). The expensive, fragile part is everything built <em>on top</em> of that lookup: hierarchical Leiden community detection, a custom graph-clustering implementation, Neo4j synchronization, GDS node2vec embeddings, multi-phase LLM cluster validation. None of that machinery is required to answer the simple question &ldquo;does this concept already have a file, or do I need to make one.&rdquo;</p>
<p>So: keep OKF&rsquo;s granularity change from &ldquo;one document per video&rdquo; to &ldquo;one document per <em>concept</em>,&rdquo; and keep OKF&rsquo;s single-clean-LLM-call philosophy for producing each document — but add exactly one new piece of machinery, reused wholesale from Ontology: an embedding-similarity check run against existing concept files before deciding whether to create a new one or update an existing one.</p>
<p>Concretely, the flow becomes: extract candidate concepts from a new video (a lighter-weight version of what OKF&rsquo;s <code>keyConcepts</code> extraction already does); for each candidate, look up its embedding against the existing concept-file store; below the similarity threshold, generate a new concept file with a single LLM call, identical in spirit to how OKF documents are generated today; above the threshold, fetch the existing concept file and make a <em>second</em> single LLM call — not a re-generation from scratch, but a targeted merge — asking the model to fold the new video&rsquo;s evidence into the existing file, extending its facts and definitions where the new source adds something and leaving the rest untouched. Every concept file&rsquo;s frontmatter carries a <code>sources</code> list — which videos, at which timestamps, contributed to this concept — and, symmetrically, every video record carries the reverse index: which concept files it touched. Two lookups, either direction, no graph database required for the base case.</p>
<p>This sidesteps Ontology&rsquo;s heaviest and most experimental layers entirely — no Leiden community detection, no Neo4j export, no GDS — while still solving the actual problem OKF can&rsquo;t: read the concept file for &ldquo;context development lifecycle&rdquo; and see, in one place, every video that discussed it, rather than opening eighty separate per-video documents to reconstruct the same picture by hand. It&rsquo;s a smaller bet than rebuilding trust in the full ontology pipeline, and it inherits OKF&rsquo;s core virtue — every artifact stays something a human can open and read in under a minute — while adding the one capability that actually matters for a knowledge base that&rsquo;s meant to grow: knowing when you&rsquo;ve already learned something.</p>
<h2 id="a-practical-decision-framework">A practical decision framework</h2>
<p>None of these four approaches is strictly better than the others — they answer different questions, and the right choice depends heavily on who or what is going to consume the output.</p>
<table>
	<thead>
			<tr>
					<th>You want&hellip;</th>
					<th>Reach for&hellip;</th>
					<th>Why</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>A chatbot that answers ad-hoc questions over a large, growing corpus</td>
					<td><strong>RAG</strong> (ideally over OKF documents, concept files, or a graph — not raw chunks)</td>
					<td>Retrieval is the right access pattern for arbitrary queries; just don&rsquo;t mistake it for having done extraction</td>
			</tr>
			<tr>
					<td>A single document you can skim to understand what one source covered</td>
					<td><strong>OKF</strong></td>
					<td>One clean, readable artifact per source; cheapest to produce, easiest to trust</td>
			</tr>
			<tr>
					<td>A browsable, deduplicated personal or team knowledge base that grows across many sources without duplicating itself</td>
					<td><strong>Concept files</strong> (OKF&rsquo;s simplicity + a similarity lookup)</td>
					<td>Gets you cross-source memory without Ontology&rsquo;s full weight</td>
			</tr>
			<tr>
					<td>To run graph algorithms, relationship queries, or build a GraphRAG retrieval layer</td>
					<td><strong>Triplet extraction → graph DB</strong></td>
					<td>The fixed predicate schema is exactly what makes graph queries reliable; just watch for speaker-attribution noise and consider filtering or reframing subject-is-the-narrator edges</td>
			</tr>
			<tr>
					<td>Fully resolved canonical entities across hundreds of sources, with rigorous multi-phase validation, and you can afford to build and maintain real infrastructure for it</td>
					<td><strong>Ontology</strong> (candidate → cluster → community → report)</td>
					<td>The only approach here with genuine, demonstrated cross-source entity resolution — but budget for the complexity, and validate quality before trusting it unsupervised</td>
			</tr>
	</tbody>
</table>
<p>The failure mode to avoid in each direction is symmetric. Reaching for RAG when you actually wanted a knowledge base gets you a chatbot with amnesia about its own contents — no browsable artifact, no audit trail, no way to know what wasn&rsquo;t retrieved. Reaching for full Ontology machinery when you actually wanted &ldquo;don&rsquo;t repeat myself across documents&rdquo; gets you six new subsystems, a custom graph-clustering algorithm to maintain, and — per the real numbers above — a nontrivial chance that most of your sources won&rsquo;t overlap enough to justify the cost. Reaching for triplet extraction when what you wanted was something readable gets you a technically correct edge list nobody wants to read. And shipping only OKF at scale gets you a library of excellent, siloed essays that never talk to each other.</p>
<h2 id="closing-the-tradeoff-is-always-legibility-versus-rigor">Closing: the tradeoff is always legibility versus rigor</h2>
<p>Step back from the specific implementations and a single axis explains most of the differences above: every one of these approaches trades off how <em>legible</em> its output is to a human against how <em>structurally rigorous</em> it is for a machine to reason over. OKF sits at the legible end — genuinely readable prose, at the cost of zero cross-source structure. Triplet extraction sits near the rigorous end — a clean, queryable edge list, at the cost of being nearly unreadable as prose and blind to synonymy. Ontology tries to buy both — readable community reports <em>and</em> resolved entities — and pays for it in genuine engineering complexity, with results here that are real but not yet validated at production quality. Concept files are a bet that you can buy back most of Ontology&rsquo;s memory without most of its weight, by being deliberate about which 20% of the machinery actually does the load-bearing work.</p>
<p>There is no version of this that gets you legibility and rigor and simplicity all at once for free. The right move is naming, honestly, which one your actual use case needs most — a human skimming for understanding, a machine walking a graph, or a system that needs to remember what it already knows the next time it sees the same idea again — and building for that, rather than reaching for whichever of the four happens to be the current default answer to &ldquo;we have unstructured data, now what.&rdquo;</p>
]]></description><media:thumbnail url="https://blog.dazzlog.de/knowledge-extraction.png"/></item></channel></rss>