--- title: "Evals Module" description: "Evaluation framework for measuring Knowledge Graph quality, extraction accuracy, and pipeline performance." icon: "chart-line" --- `semantica.evals` provides a comprehensive evaluation framework for measuring extraction accuracy, graph quality, and pipeline performance. Use it to benchmark extractors, validate pipeline output, and track quality regressions across runs. ## What You Get Completeness, consistency, schema compliance, coverage, and orphan node metrics. NER precision / recall / F1 and relation extraction metrics against gold-standard datasets. Throughput (docs/sec), per-step latency, peak memory, and error rate benchmarking. Record pipeline runs and compare metrics across commits or config changes. Merge precision, false positive / false negative rates for deduplication strategies. Inference accuracy, rule coverage, and derivation depth for reasoning engines. ## Quick Start ```python from semantica.evals import KGEvaluator evaluator = KGEvaluator() report = evaluator.evaluate(kg, ontology=ontology) print(f"Completeness: {report.completeness:.2%}") print(f"Consistency: {report.consistency:.2%}") print(f"Coverage: {report.coverage:.2%}") print(f"Orphan nodes: {report.orphan_count}") ``` ```python from semantica.evals import ExtractionEvaluator evaluator = ExtractionEvaluator() report = evaluator.evaluate_ner( predictions=extracted_entities, gold_standard=annotated_entities, ) print(f"Precision: {report.precision:.3f}") print(f"Recall: {report.recall:.3f}") print(f"F1: {report.f1:.3f}") print(f"By type: {report.per_type_metrics}") ``` ```python from semantica.evals import PipelineEvaluator evaluator = PipelineEvaluator() metrics = evaluator.benchmark(pipeline, data="data/", warmup_runs=2, bench_runs=5) print(f"Throughput: {metrics.docs_per_second:.1f} docs/sec") print(f"Total duration: {metrics.total_seconds:.1f}s") print(f"Per-step latency: {metrics.step_latencies}") print(f"Peak memory (MB): {metrics.peak_memory_mb:.0f}") print(f"Error rate: {metrics.error_rate:.2%}") ``` ```python from semantica.evals import RegressionTracker tracker = RegressionTracker(db_path="eval_history.db") run_id = tracker.record_run( pipeline_version="v1.2.0", metrics=metrics, config=config.to_dict(), ) diff = tracker.compare(run_id, baseline_run_id="run_abc123") for metric, change in diff.items(): direction = "↑" if change > 0 else "↓" print(f" {metric}: {direction} {abs(change):.2%}") ``` ## Evaluation Areas Measure completeness, consistency, schema compliance, and structural health of a knowledge graph: ```python from semantica.evals import KGEvaluator evaluator = KGEvaluator() report = evaluator.evaluate(kg, ontology=ontology) print(f"Completeness: {report.completeness:.2%}") # % entities with all required fields print(f"Consistency: {report.consistency:.2%}") # % entities without type conflicts print(f"Coverage: {report.coverage:.2%}") # % entity types in ontology print(f"Total nodes: {report.node_count}") print(f"Orphan nodes: {report.orphan_count}") # nodes with no edges ``` **Key behaviours:** - `consistency` requires an ontology — without one, it always returns 1.0 - `orphan_count` flags disconnected nodes that likely represent extraction or deduplication errors - `completeness` checks required properties defined in the ontology schema Compare extracted entities and relations against annotated gold-standard data: ```python from semantica.evals import ExtractionEvaluator evaluator = ExtractionEvaluator() # NER evaluation ner_report = evaluator.evaluate_ner( predictions=extracted_entities, gold_standard=annotated_entities, ) print(f"Precision: {ner_report.precision:.3f}") print(f"Recall: {ner_report.recall:.3f}") print(f"F1: {ner_report.f1:.3f}") print(f"By type: {ner_report.per_type_metrics}") # Relation extraction evaluation rel_report = evaluator.evaluate_relations( predictions=extracted_relations, gold_standard=annotated_relations, ) print(f"Relation F1: {rel_report.f1:.3f}") ``` Benchmark throughput, latency, memory, and error rate across multiple runs: ```python from semantica.evals import PipelineEvaluator evaluator = PipelineEvaluator() metrics = evaluator.benchmark( pipeline, data="data/", warmup_runs=2, # eliminate cold-start noise bench_runs=5, # average over 5 real runs ) print(f"Throughput: {metrics.docs_per_second:.1f} docs/sec") print(f"Total duration: {metrics.total_seconds:.1f}s") print(f"Per-step latency: {metrics.step_latencies}") print(f"Peak memory (MB): {metrics.peak_memory_mb:.0f}") print(f"Error rate: {metrics.error_rate:.2%}") ``` Store runs and compare metrics across pipeline versions: ```python from semantica.evals import RegressionTracker tracker = RegressionTracker(db_path="eval_history.db") # Record a run with version tag and full config snapshot run_id = tracker.record_run( pipeline_version="v1.2.0", metrics=metrics, config=config.to_dict(), ) # Compare to a previous run diff = tracker.compare(run_id, baseline_run_id="run_abc123") for metric, change in diff.items(): direction = "↑" if change > 0 else "↓" print(f" {metric}: {direction} {abs(change):.2%}") ``` ## When to Evaluate | Trigger | Evaluator to Use | What to Check | | ------- | ---------------- | ------------- | | New extraction model or method | `ExtractionEvaluator` | Precision, recall, F1 vs gold standard | | After changing LLM provider | `ExtractionEvaluator` | Per-type F1 — check if rare types regressed | | Before releasing new pipeline version | `PipelineEvaluator` | Throughput, latency, error rate | | After deduplication strategy change | `KGEvaluator` | Orphan count, consistency score | | Every production deployment | `RegressionTracker` | Compare vs previous baseline run | ## Tips and Common Pitfalls **Build a gold standard dataset early.** `ExtractionEvaluator` requires annotated ground truth. Without it, you're evaluating subjectively. Even 100 carefully annotated documents give you a meaningful baseline to track regressions against. **Evaluate per entity type, not just overall F1.** Aggregate F1 can hide regressions — if your model's PERSON F1 drops from 0.95 to 0.80 but ORGANIZATION improves, the average may look stable. Use `report.per_type_metrics` to catch type-specific regressions. **Store every benchmark run with `RegressionTracker`.** Run ID + version tag + config snapshot gives you a reproducible audit trail. Without it, "did the last release make things better?" has no objective answer. **Run `PipelineEvaluator` with `warmup_runs=2`.** Cold starts are unrepresentative — model weights get cached, JIT compilation kicks in. Warmup runs eliminate this noise from your benchmark numbers. **`KGEvaluator` needs an ontology for consistency scoring.** Without an ontology, `consistency` always returns 1.0 — there's nothing to check against. Pass `ontology=ontology` to get meaningful consistency metrics. Extraction module to evaluate. Graph quality assessment. Pipeline performance metrics. Deduplication accuracy evaluation.