6 · The cleanup is the work¶
Extraction hands you a vocabulary full of near-duplicates. Whisper
mis-hears the same name three different ways, the model writes Habeck in one
chunk and Robert Habeck in the next, and German inflection turns one word into
five. None of that is wrong, exactly, but it is un-consolidated, and that hurts in
two ways. It adds noise. And it makes real connections hard to find, or outright
impossible, because the same thing is not being treated as the same thing: when
one entity is scattered across five spellings, the graph never learns the five are
one, so it can neither count a topic nor connect two mentions of it. Resolving that
vocabulary down to, ideally, one node per real-world thing, without collapsing
things that only look alike, is the cleanup that separates a demo from something
correct enough to build on.
| metric | before | after |
|---|---|---|
| distinct entities | 4,793 | 4,286 |
| catastrophic over-merges | — | 0 |
look-alikes kept apart (Iran/Irak) |
— | preserved |
Numbers are from a 12-episode proof-of-concept, small enough to verify every merge by hand, which is where the "zero over-merges" claim is honestly earned. The same tiers run over the full 352-episode corpus, tens of thousands of entities, where a residual fraction of over-merges survives review and is corrected with a short list of declarative overrides.
The recurring rule below is the same one that shaped extraction: try the cheapest fix first, and only escalate to a bigger tool when the structure of the problem actually demands it, which, here, it mostly doesn't.
When a bigger model is the wrong move¶
Whisper fragments one entity across episodes (GovCoins, Goffcoins and
Gafcoin are all one mistranscribed coin), so the vocabulary itself needs
resolving. The naive fix, "ask an LLM which of these are the same," over-merges
(GovCoins/Dogecoin), and prompt-hardening plateaus with the rules ignored
verbatim. Reaching for a bigger model made it worse:
Gemma 3 27B merged a country with a group of people,
a model-class limitation, not a capacity one. What worked was three tiers,
cheapest first:
- Deterministic normalization, casing, whitespace, umlaut folding (40 merges).
simplemmaGerman lemmatization, no LLM, which structurally keepsWettbewerb ≠ Wettbewerberapart (333 merges).- A QwQ-32B reasoning model on only the genuine-typo remainder (166 merges).
Result: 4,793 → 4,286 entities, zero catastrophic over-merges, with look-alikes
like Iran/Irak preserved. The expensive model touches only the fraction the two
cheap, deterministic tiers can't settle.
That routing is the whole economics of the pass. QwQ-32B is a reasoning model: it "thinks" before answering, spending roughly 500 tokens and about 40 seconds on a single cluster. Sending the entire vocabulary through it would have been the obvious, expensive mistake. Instead the deterministic tiers settle the bulk for free and near-instantly, so only 166 of the 500-plus consolidations, the genuinely ambiguous typos, ever reach the reasoning model. On this proof-of-concept that is the difference between minutes and most of an afternoon. On the full 352-episode corpus, where this tier alone ran for about 33 hours, it is the difference between a pass that finishes and one that does not.
Further reading: Dalerci et al., MÖVE: A Holistic LLM Benchmark for the German Public Sector (arXiv:2606.13111, 2026) finds that model size alone is a poor predictor of quality, and that the best model differs by task, consistent with what the entity-resolution pass ran into here.
From surname to person¶
Spelling resolution collapses variants that look alike. It cannot, and
shouldn't, merge Habeck into Robert Habeck: the strings aren't similar, and
folding every surname into a full name on string distance alone would be reckless.
That case is coreference, one person referred to by different names (Habeck,
Robert Habeck, Kanzler Habeck, Herr Habeck), and it gets its own final tier.
A rule can't do it, for two reasons that both come out of the data. Common given
names are ordinary dictionary words, so Robert, Olaf and Friedrich read as
generic terms rather than the halves of a name a filter should protect. And Whisper
mishears first names, so Baerbock turns up under Alina, Anna and Annalena
Baerbock, which look like three different people. String similarity actively
misleads here.
So, as with Tier 3's hard cases, the decision is made from evidence. A candidate
cluster is every entity sharing a surname where at least one full-name form is
typed Person. The reasoning model is then shown example sentences for each form
and asked which of them refer to the same person in this corpus. It merges those,
keeps genuinely different people who happen to share a surname apart, and discards
things that only borrow the name (Hass gegen Habeck is an event, Bundesregierung
Scholz an institution). Crucially it is allowed only to add merges, never to
split what the earlier tiers settled, so a confused answer costs nothing. In the
production graph this is the step that folds the bare Habeck into Robert
Habeck: the person's 200-plus connections stop being split across two nodes and
land on one.