Knowledge Graph Extraction Evaluation#
Docling-graph provides two complementary evaluation layers for measuring knowledge graph extraction quality:
- Template-level evaluation (
docling_graph/templategen/evaluate.py) — runs real pipeline extractions and reports grounding precision, attribute fill-rates, and graph audit signals. No ground truth required; advisory only. - Ground-truth comparison (
docs/examples/scripts/16_extraction_evaluation.py) — scores an extractedgraph.jsonagainst a reference JSON, computing node/edge P/R/F1, attribute completeness, and integrity checks. Used as a regression harness when tuning templates or extraction contracts. - Benchmark aggregation (
docs/examples/scripts/17_benchmark_aggregate.py) — aggregateseval.jsonfiles across a run matrix (documents × contracts × LLM serialization formats × repeats) into a single comparison table.
Metrics Reference#
Node and Edge P/R/F1#
The evaluate() function in Example 16 computes micro precision, recall, and F1 separately for nodes and edges — never averaged together . TP/FP/FN are summed across all classes before computing ratios, so large classes dominate .
Per-entity-class metrics are computed first, then the micro summary is derived .
Three matching tiers determine whether an extracted node counts as a TP :
| Tier | How it works |
|---|---|
| Strict | Exact equality of canonical graph_id_fields values |
| Relaxed | Unique same-class containment with equal digit signature (tolerates short label vs. full title) |
| Structural (aligned) | Identity-agnostic: unmatched same-class nodes paired by attribute overlap score ≥ 1.0, used when GT identifiers are synthesized (absent from source text) |
Structural alignment is activated automatically when the GT identifier is not found in the source text (--structural-align auto, the default) . It can be forced with --structural-align on or disabled with off.
Edge metrics follow the same strict/relaxed/aligned tiers: edge endpoints are resolved through the node alias map before comparing (label, source, target) triples .
The prf() helper computes per-class scores; micro_prf() sums TP/FP/FN across classes.
Grounding Precision#
Template-level grounding (in evaluate.py) checks whether extracted string node-attribute values appear as whitespace-normalized substrings within ProvenanceLedger chunk texts . The GroundingReport model exposes:
checked/groundedcountsprecision= grounded / checkedroot_id_syntheticflag — set when the root identity was filled with the file-stem fallback injected byrepair_root_identity, not actual document textungrounded_samples— up to 10Class.field=valuesamples not found in any chunk
Only string fields with ≥ 2 characters are checked; numeric/date values are excluded because they reformat freely .
The aggregate EvaluationSummary rolls up grounding_precision as grounded / checked across all documents .
Ground-truth verbatim ratio (Example 16) is a complementary check on matched nodes: long string fields (≥ 80 chars) in the extracted graph are tested as normalized substrings of the served source text. The result is reported as verbatim_ratio .
Attribute Completeness#
Completeness measures the fill-rate of declared fields on matched nodes — how many expected attributes were actually populated by the extractor.
- In the ground-truth comparison (Example 16): computed on strictly-matched nodes only; reports
filled/expectedper field per class . The benchmark aggregator rolls this up to a singlecompletenessratio . - In the template evaluator:
ClassFillRatetracksfill_rateas the mean fraction of declared node attributes filled per node, per class. Themean_fill_rateinEvaluationSummaryaverages across all classes and documents .
Graph Integrity Signals#
Both evaluation paths surface integrity issues that can mask inflated F1 scores:
| Signal | Description |
|---|---|
empty_identity_nodes | Nodes whose graph_id_fields are all empty — cannot be matched to anything |
orphan_nodes | Nodes not referenced by any edge |
unkeyed_extracted_nodes | Nodes with no usable identity (neither extracted nor ground-truth side) |
These are reported under the integrity key in eval.json and translated to rulebook clauses in the template evaluator via AUDIT_KEY_RULEBOOK.
Edge fan-out is an additional diagnostic: per edge label, the share of edges hanging off the single busiest source node. High fan-out in the extracted graph (≥ 0.6) with low fan-out in ground truth (≤ 0.4) flags "dump everything on one parent" pathology .
Entry Points#
| Script / Module | Purpose |
|---|---|
docling_graph/templategen/evaluate.py | evaluate_template() — live pipeline runs, grounding + fill-rate, no GT needed |
docs/examples/scripts/16_extraction_evaluation.py | GT comparison: node/edge P/R/F1, completeness, integrity, verbatim ratio |
docs/examples/scripts/17_benchmark_aggregate.py | Aggregates eval.json across a benchmark matrix; outputs synthesis_report.md |
Typical workflow:
# Step 1 – per-run scoring (produces eval.json)
uv run python docs/examples/scripts/16_extraction_evaluation.py \
--graph outputs/RUN_DIR/docling_graph/graph.json \
--truth data/insurance_terms/ground_truth.json \
--template docs.examples.templates.insurance_terms.AssuranceMRH \
--source document.md \
--out eval.json
# Step 2 – cross-run aggregation
uv run python docs/examples/scripts/17_benchmark_aggregate.py \
--root outputs/benchmarks
Key Design Decisions#
- Domain-agnostic: any
(template, ground_truth.json, graph.json)triple is valid — the same harness works for insurance, biomedical, legal, or any other domain . - Structural alignment for synthesized IDs: when a ground-truth author invents identifier slugs (e.g.
STUDY-LFP-GELATION), strict identity matching is unwinnable by design. The evaluator auto-detects this via source-text presence checks and falls back to attribute-overlap pairing . - No LLM judging: the template evaluator reports only signals the converter already emits — audit keys, fill-rates, grounding — without any additional LLM calls .
- Aligned rung is the fair headline number: the benchmark synthesis report treats the aligned F1 as the primary comparison metric when identity drift is present .