TEI-NER Pipeline

HYBRID NER + LLM · NORMDATEN-LINKING · v7
Fünfstufige Hybrid-Pipeline: Lokale Heuristik → Normdaten-Lookup → LLM-Verifikation → 3-Stufen-Kreuzreferenz → XML-Provenienz + HTML-Report
Register-Daten
Wikidata / GND API
Heuristik / Scoring
LLM (Gemma 4 / Gemini / Claude)
5
PHASEN
20+
MECHANISMEN
3
ENTITY-TYPEN
~$1
PRO 400 ENTITIES
PHASE 0
Corpus-Profiler
$0 · lokal
Analysiert das gesamte Korpus und erzeugt einen optimierten System-Prompt für die LLM-Verifikation. Spracherkennung, Epochen, Regionen, Korrespondenz-Netzwerk.
36 Sprachen
Drei-Pass: Unicode-Schrift → Diakritika → Wort-Marker. Gewichtet (3×/1×), Plausibilitätsfilter.
26 Epochen
-800 bis 1970. Datums-Extraktion mit Priorität: correspAction > Body > Titel. Editions-Daten ignoriert.
Regionen (2-Stufen)
Strong/Weak-Marker. "Paris" nie in Frankreich (Trojaner!), "Rom" nie in Italien (antik). Mehrdeutige Namen nur mit Kontext.
Korrespondenz-Netzwerk
Wer schreibt von wo an wen? correspAction + Register-Personen → reale Geographie der Akteure statt Textinhalt.
LLM-Analyse (optional)
Lokales LLM (Gemma 4) analysiert Einzeldokumente. Gesamteinschätzung: Sprachstufe, Region, Entity-Linking-Hinweise.
▸ Details

OUTPUT: SYSTEM-PROMPT

Enthält: Projektkontext, Epochen, Sprachen, Regionen, Korrespondenz-Netzwerk, LLM-Einschätzung. Wird bei jedem LLM-Call als System-Prompt mitgeschickt.

GEO-DISAMBIGUIERUNG

Explizite Anweisung an Claude: IMMER den Kandidaten bevorzugen der geographisch zum Netzwerk passt. Antike Ortsnamen = literarische Referenzen.

KORRESPONDENZ-NETZWERK

Extrahiert aus <correspAction>: Sender, Empfänger, Absende-/Empfangsorte. Wirkungsorte aus Register-Personen. Ergibt die reale Geographie.

PHASE 1
Register lesen & Normdaten suchen
$0 · API
Liest alle Metadaten aus dem Register, sucht Kandidaten in Wikidata und GND, führt Anachronismus-Filter und Disambiguierung durch.
Preload-Cache (SPARQL-Batch)
SPARQL-Batch-Preloader lädt Wikidata+GND-Daten vorab in SQLite-Cache. Phase 1 von ~40 Min auf ~30 Sek. Spart ~70% API-Calls. Offline-fähig. NEU
Externe DBs (6,5M+524K)
persons.db: 6,5M Personen mit GND/Wikidata-IDs und Namensvarianten. Places.db: 524K+ Orte mit historischen Schreibweisen. Werden vor API-Suche konsultiert. NEU
Name + Alt-Namen
<persName type="alt">Ἠχώ</persName> → Suche in WD + GND mit allen Namensformen.
Note / Desc
Volltext (max 500 Zeichen), inkl. verschachtelter Elemente. Fließt in 4 Disambiguierungsschritte ein.
Lebensdaten
<birth when="1544"/> → +0.15 Boost bei Match, Anachronismus-Check bei Mismatch.
Qualifier-Erkennung
"Burg" in Note → sucht "Burg Friedberg" zusätzlich. Auch: Kloster, Universität, Zunft, Bistum...
Wikidata + GND Suche
Primäre Suche mit Register-Typ (Person/Ort/Org). Danach: Alt-Namen-Suche, Qualifier-Suche, Note-qualifizierte Suche.
Anachronismus-Filter
Geburtsjahr > Korpus + 50 → -0.50. Keywords (metal, film, genus of) → -0.40. Jahreszahl in Beschreibung → -0.50.
Domänen-Boost
"mytholog" in Note UND "mythology" in Beschreibung → +0.30. Semantischer Abgleich Note ↔ Kandidat.
Namens-Überlappung
Kein Namensbestandteil im Kandidat → -0.30. <50% Überlappung → -0.15. Schützt vor "Anna" → "Xyz von Honstein".
SubjectHeading Fallback
Wenn Note "Volksstamm/mythologisch/theologisch" → erzwingt SubjectHeading-Suche, auch wenn Person-Treffer gut ist.
Note-qualifizierte Suche
"mythologische Figur" → sucht "Echo mythology" (WD) + "Echo Nymphe" / "Echo Sagengestalt" (GND).
▸ Details

NOTE-KEYWORD-GEWICHTUNG

Stark (+0.15): Burg, Kloster, Theologe, Universität...
Phrase (+0.12): "Kreis Neuss", "Burg Friedberg"
Jahr (+0.08): 1171, 1530
Normal (+0.03): ≥5 Zeichen, kein Stopwort
Stopwörter gefiltert: erstmals, erwähnt, gehörte...

LOBID-KORREKTUR

LOBID kann falsche Wikidata-IDs liefern (z.B. Pseudo-Aristoteles Q1783131 statt Q868). Fix: Niedrigste Q-Nummer + direkte Verifikation gegen Wikidata-Suche.

DREI ENTITY-TYPEN

Person: birth/death, occupation, floruit
Ort: Qualifier (Burg/Kirche/Fluss), location, district
Org: Qualifier (Universität/Zunft/Bistum), Gründungsdaten, Sitz

PHASE 1.5
Kontext aus Quelltexten
$0 · lokal
Sucht jeden Entity-Namen in den TEI-Quelltexten und extrahiert Textumgebungen als Kontext für die LLM-Verifikation.
Context-Harvester
Durchsucht alle TEI-XMLs nach Entity-Namen. Extrahiert ±200 Zeichen Kontext. Wird im LLM-Prompt als "Quelltext-Kontext" angezeigt.
▸ Details

WAS CLAUDE SIEHT

Quelltext-Kontext: "...Rhodomanus Echoni Nymphae dedicavit carmina..." — hilft Claude zu verstehen dass Echo eine mythologische Nymphe ist, nicht ein Musikpreis.

PHASE 1.7
Historische Schreibweisen
~$0.10 · LLM
Entities ohne Normdaten-Treffer werden per LLM auf historische Schreibweisen geprüft. Claude erkennt z.B. "Alderkyrchen" → "Aldekerk".
Schreibweisen-Erkennung
LLM-Prompt: "Finde modernen Ortsnamen für: Alderkyrchen, Creveld, Cöln". Erkennt: y→i, ck→k, dt→d, oe→ö.
Nachsuche mit modernem Namen
"Alderkyrchen" → Claude sagt "Aldekerk" → neue Wikidata+GND-Suche mit "Aldekerk" → Treffer!
▸ Details

BATCH-VERARBEITUNG

5 Entities pro Batch. Anthropic Batch API (50% Rabatt). 3-Stufen JSON-Parser für truncierte Antworten.

PHASE 2
LLM-Verifikation
~$0.10–0.80 · Gemini/Claude
LLM prüft jeden Kandidaten gegen Register-Daten, Quelltext-Kontext und Corpus-Profil. Vergibt MATCH / PARTIAL / NONE mit Begründung. PARTIAL-Fallback: Auto-Link bei GND-Confidence ≥0.70. Type Enforcement: Entity-Typ vom Editor ist nicht verhandelbar.
Gemma 4 / Gemini 2.5 Flash / Claude
Standard: Gemma 4 lokal (LM Studio) oder Gemini 2.5 Flash (API). Alternativ: Claude Sonnet mit Batch API (50% Rabatt). max_tokens: 4000.
Register-Notiz im Prompt
Claude sieht: "Register-Notiz: Burg Friedberg, erstmals 1171 erwähnt" — und vergleicht mit Kandidaten-Beschreibung.
Lebensdaten im Prompt
"Lebensdaten (Register): geb. 1544, gest. 1604" — Claude prüft gegen Kandidaten-Daten: "Johann Freder (1544–1604) → passt!"
Geo-Disambiguierung
System-Prompt: "Akteure waren aktiv in: Rostock, Jena, Wittenberg. Bei mehrdeutigen Namen → Netzwerk-Region bevorzugen."
Robuster JSON-Parser
3-Stufen: Komplett → Array-Regex → Einzelobjekte. Rettet Teilergebnisse bei trunciertem JSON.
▸ Details

WAS CLAUDE BEKOMMT

System: Corpus-Profil + Geo-Disambiguierung + Entity-Typ-Hinweise
User: Name, Typ, Alt-Namen, Lebensdaten, Amt/Beruf, Register-Notiz, Quelltext-Kontext, Top-3-Kandidaten

WAS CLAUDE ANTWORTET

{"idx":1, "verdict":"MATCH", "best":1, "confidence":0.95, "reason":"...", "modern_name":"Aldekerk"}

ENTITY-TYP-ANWEISUNGEN

Mythologische Figuren → SubjectHeading gültig.
NIEMALS moderne Personen für historische Begriffe.
Antike Ortsnamen = literarische Referenzen.

PHASE 2.7
Spelling-Recovery
~$0.05 · LLM
VERIFIED_NONE-Entities, bei denen Kandidaten vorhanden waren aber alle abgelehnt wurden, werden erneut per Schreibweisen-Analyse geprüft. Rettet Einträge mit historischen Namensvarianten.
Spelling Post-Processing
LLM analysiert ob der Entity-Name eine historische Schreibweise sein könnte. Falls ja: erneute Normdaten-Suche mit modernem Namen + Verifikation. NEU
Nachsuche + Re-Verifikation
Neue Kandidaten werden mit dem originalen Kontext (Note, Lebensdaten, Quelltext) verifiziert.
▶ Details

UNTERSCHIED ZU PHASE 1.7

Phase 1.7 behandelt Entities ohne Kandidaten (kein API-Treffer). Phase 2.7 behandelt Entities mit Kandidaten, die aber alle vom LLM abgelehnt wurden — hier könnte eine Schreibweisen-Variante den richtigen Treffer bringen.

PHASE 4
XML schreiben & Kreuzreferenz
$0 · lokal
Schreibt verifizierte IDs ins XML mit Provenienz-Attributen. Editorische IDs werden nie überschrieben. Kreuzreferenz ergänzt fehlende WD/GND-IDs.
@resp + @cert
resp="#tei-ner-pipeline" cert="high|medium|low" an jedem generierten Element. Editorische Einträge (ohne @resp) sofort erkennbar.
Editorische ID-Schutz
Register hat GND für Burg → Pipeline findet Stadt-GND → Editorische bleibt, Konflikt wird im Report dokumentiert.
Kreuzreferenz (3-Stufen)
GND ohne WD → Drei Strategien: 1) Vorhandene Kandidaten prüfen ($0) 2) Alt-Namen in WD suchen 3) Direkte Suche. MIT Anachronismus + Domänen-Check.
LOBID-Verifikation
LOBID-eingebettete WD-IDs gegen direkte Suche prüfen. Niedrigste Q-Nummer bevorzugen. Löst: Pseudo-Aristoteles Q1783131 → Q868.
Auto-Link (≥0.90)
Nur bei Score ≥0.90 ohne LLM-Verdict. Betrifft ~80 eindeutige Fälle (Berlin, Köln, Düsseldorf). Rest geht zum LLM.
Editorial Conflict Report
EDITORIAL_CONFIRMED: Pipeline bestätigt editorische ID. EDITORIAL_CONFLICT: Pipeline hätte andere ID → im Report mit beiden Werten.
--crossref-editorial
Kreuzreferenz auch für editorische IDs: Ergänzt fehlende WD/GND-IDs bei Einträgen mit manuell gesetzten IDs. NEU
HTML-Report
Interaktiver Report mit Filtern, Suche, sortierbarer Tabelle. Direkte Links zu GND/Wikidata. Konflikte hervorgehoben. Nachträglich erzeugbar.
▸ Details

KREUZREFERENZ: 3-STUFEN-STRATEGIE

Wenn GND-Match keine Wikidata-ID hat:
Stufe 1: Vorhandene Kandidaten durchsuchen — Q207368 war schon in den Kandidaten, kostet $0.
Stufe 2: Alt-Namen in Wikidata suchen — "Ἠχώ" findet Q207368 auch wenn "Echo" zu mehrdeutig ist.
Stufe 3: Direkte Suche mit Match-Label (Fallback).
Jede Stufe hat Anachronismus-Check + Domänen-Abgleich.

PROVENIENZ IM TEI-HEADER

<respStmt xml:id="tei-ner-pipeline"> mit Methode, Modell, Datum, Schwellenwerten. Automatisch eingefügt.

CONFIDENCE → CERT MAPPING

≥0.85 → cert="high"
0.65–0.84 → cert="medium" (Review empfohlen)
<0.65 → cert="low" (manuell prüfen)

XPATH-FILTRIERBAR

//idno[@resp] → Tool-Einträge
//idno[not(@resp)] → Editorische
//idno[@cert='medium'] → Review-Kandidaten

HTML-REPORT

Interaktiver Report mit: Suchfeld, Filter-Buttons (Status + Entity-Typ), sortierbare Spalten, klickbare GND/Wikidata-Links, Konflikte rot hervorgehoben, Confidence-Badges. Nachträglich erzeugbar mit python3 -m src.html_reporter.

Live-Beispiel: „Echo"
Register: <persName>Echo</persName> · <persName type="alt">Ἠχώ</persName> · <note>mythologische Figur</note>
Primär: "Echo" als Person in Wikidata + GND → Insekten, TV-Serie, Illustratorin (2017+), Dub-Musiker
5 Treffer
★ Register: "Ἠχώ" in Wikidata → Q207368 mountain nymph gefunden!
Score 0.15
★ Register: "mytholog" in Note → GND-Suche "Echo Nymphe" → 121852881 Sagengestalt!
Score 0.44
ANACHRONISMUS
GND 1217023410 (Illustratorin): periodOfActivity: 2017- → 2017 > Korpus 1606 + 100
0.75 → 0.25
ANACHRONISMUS
Umberto Echo (Dub-Musiker): birth=1980, "dub-musiker" in desc
0.70 → 0.00
NOTE-KEYWORD
★ Register: "mytholog" (+0.15) in Note matcht "mythologie" in GND 121852881
0.44 → 0.59
DOMÄNEN-BOOST
★ Register: "mytholog" in Note UND "mythologie" in Beschreibung → semantischer Match
0.59 → 0.89
PHANTOM
GND 1217023410: Note hat Domäne, Kandidat hat keine Beschr. + keine Lebensdaten
0.25 → 0.00
LLM
Top-Kandidat: 121852881 "Echo, Sagengestalt — Nymphe aus d. griech. Mythologie" (Score 0.89)
MATCH 0.98
GND ✓
<idno type="GND" resp="#tei-ner-pipeline" cert="high">121852881</idno>
Kreuzreferenz Stufe 1: Vorhandene Kandidaten durchsuchen — Q207368 "mountain nymph of Greek mythology" war schon in den Kandidaten! Domäne "mythology" matcht → $0, sofort
Q207368 ✓
WD ✓
<idno type="Wikidata" resp="#tei-ner-pipeline" cert="medium">Q207368</idno>