ConceptStablesince v0.5.0

System Comparison & Regression Diffing

Diffing two AI systems, telemetry artifacts, models, or RAG pipelines — step-level layer alignment, quality delta metrics, hallucination drift, latency regressions, and automated CI/CD deployment gating.

Audience: AI Engineers & QA TeamsRead: 12 minEdit on GitHub

Why System Comparison Matters

Modern AI applications are continuously evolving. Models are fine-tuned. Prompts are revised. RAG pipelines gain new retrieval steps. Vector stores are re-indexed. Workflow nodes are reordered. Each change has the potential to improve — or degrade — system quality, latency, and reliability.

Traditional software has mature tools for comparing code changes: diffs, test suites, and regression checks. AI systems require a different approach. Unlike deterministic software, AI systems produce probabilistic outputs that depend on model weights, retrieval quality, prompt formulation, and runtime environment.

Comparing AI systems requires answering questions like:

  • Which component introduced the quality regression — the model, the retrieval, or the prompt?
  • Did the new fine-tuned model hallucinate more or less than the baseline?
  • Which workflow step became the new latency bottleneck after the infrastructure upgrade?
  • Did the new prompt template improve answer faithfulness without increasing token cost?
  • Is the candidate deployment safe to promote to production?

The NeuronScope Regression Comparer Engine was built to answer all of these questions systematically — using canonical fingerprints, step-level telemetry alignment, and structured quality metrics.

How the Comparison Engine Works

Comparison operates on sealed .nsz telemetry artifacts produced byns.Scope. Each artifact captures a complete fingerprinted record of one AI system execution — including model weights, prompt variables, retrieval results, execution traces, evaluation scores, profiling data, and environment metadata.

The Comparison Engine performs three phases:

  • Phase 1 — Structural Alignment: Match execution steps between baseline and candidate using canonical layer IDs and fingerprints. Detect added, removed, or reordered components.
  • Phase 2 — Metric Computation: Compute quality deltas, latency regressions, hallucination drift, and cost variance across aligned steps.
  • Phase 3 — Regression Decision: Apply configurable thresholds to determine whether the candidate represents a regression, improvement, or neutral change.

Canonical Layer & Step Alignment

Before metrics are computed, the Comparer aligns the baseline and candidate execution traces step-by-step using canonical layer IDs and prompt fingerprints. This alignment is deterministic and handles:

  • Added steps: New retrieval passes, new tool calls, or new workflow nodes in the candidate.
  • Removed steps: Eliminated workflow branches or skipped retrieval stages.
  • Reordered steps: Steps executing in a different sequence due to workflow restructuring.
  • Structural breaks: Different model architectures, incompatible prompt templates, or environment changes that prevent step-level alignment.
alignment.py
python
import neuronscope as ns

baseline  = ns.load_artifact("baseline_v1.nsz")
candidate = ns.load_artifact("candidate_v2.nsz")

diff = ns.compare(baseline, candidate)

# Inspect structural alignment
print(f"Aligned steps:  {len(diff.aligned_steps)}")
print(f"Added steps:    {len(diff.added_steps)}")
print(f"Removed steps:  {len(diff.removed_steps)}")
print(f"Structural break: {diff.has_structural_break}")

# Inspect step alignment details
for aligned in diff.aligned_steps:
    print(f"  {aligned.step_name}: baseline={aligned.baseline_fp[:8]}  candidate={aligned.candidate_fp[:8]}")

Built-in Quality & Performance Metrics

The Regression Comparer Engine computes the following metrics out of the box:

Quality Metrics

  • quality_delta — Evaluation score difference across standardized benchmark tasks. Positive means improvement; negative means regression.
  • hallucination_delta — Change in hallucination score between pipeline versions. Positive means more hallucinated (worse); negative means more grounded (better).
  • answer_faithfulness_delta — Change in how faithfully the system answers using retrieved context.
  • retrieval_precision_delta — Change in the precision of retrieved documents. Degradation here often explains downstream quality regressions.
  • answer_relevance_delta — Change in how relevant the answers are to the original queries.

Performance Metrics

  • latency_step_breakdown — Step-by-step wall-clock latency diff. Pinpoints which API call, vector search, or model generation step became the new bottleneck.
  • latency_p50_delta_ms / latency_p95_delta_ms — Median and tail latency changes.
  • ttft_delta_ms — Change in Time-To-First-Token for LLM generation steps.
  • throughput_delta — Change in tokens-per-second for generation steps.
  • peak_vram_delta_mb — Change in peak GPU VRAM utilization.
  • token_cost_delta — Total token usage and estimated cloud cost variance across runs.
  • cosine_similarity — Cosine similarity over model activation hidden states at aligned layers. Low similarity at a specific layer often indicates model weight changes that affect reasoning.

Comparing Production Runs

compare_runs.py
python
import neuronscope as ns

baseline  = ns.load_artifact("rag_prod_v2.nsz")
candidate = ns.load_artifact("rag_prod_v3.nsz")

diff = ns.compare(baseline, candidate)

# Full summary
print(diff.summary())
# ┌─────────────────────────────┬──────────┬──────────┬──────────┐
# │ Metric                      │ Baseline │ Candidate│   Delta  │
# ├─────────────────────────────┼──────────┼──────────┼──────────┤
# │ Hallucination Score         │  0.127   │  0.089   │  -0.038  │
# │ Answer Faithfulness         │  0.841   │  0.907   │  +0.066  │
# │ Retrieval Precision         │  0.763   │  0.781   │  +0.018  │
# │ P95 Latency (ms)            │  1840    │  1620    │  -220ms  │
# │ Token Cost / Query          │  $0.0042 │  $0.0039 │  -$0.0003│
# └─────────────────────────────┴──────────┴──────────┴──────────┘

# Check for regression with configurable threshold
if diff.has_regression(threshold=0.05):
    print(f"REGRESSION DETECTED: {diff.regression_reason}")
    # "Hallucination score increased by 0.08 (threshold: 0.05)"
else:
    print(f"No regression. Quality improvement: {diff.quality_delta:+.3f}")

Comparing Two Models

When comparing two model versions on the same evaluation dataset, NeuronScope runs both models, captures telemetry from each, and performs a comprehensive cross-model analysis:

model_compare.py
python
import neuronscope as ns

# Compare base model vs. fine-tuned model
base_model        = ns.Model.wrap(load_model("llama-2-"))
fine_tuned_model  = ns.Model.wrap(load_model("llama-2--finetuned"))
eval_dataset      = ns.Dataset.load("eval_queries.jsonl")

# Run evaluation on both models
comparison = ns.compare.models(
    baseline=base_model,
    candidate=fine_tuned_model,
    dataset=eval_dataset,
    metrics=["accuracy", "hallucination", "faithfulness", "latency", "cost"],
    sample_size=500,
)

print(f"Winner: {comparison.winner}")
print(f"Quality improvement: {comparison.quality_improvement:+.1%}")
print(f"Latency change:      {comparison.latency_delta_ms:+.0f}ms")
print(f"Cost change:         {comparison.cost_delta:+.4f} per query")

# Layer-level activation similarity (did the fine-tuning change internal representations?)
for layer_diff in comparison.layer_similarities:
    if layer_diff.cosine_similarity < 0.95:
        print(f"  Layer {layer_diff.name}: similarity={layer_diff.cosine_similarity:.3f} (changed significantly)")

RAG Pipeline Comparison

RAG pipeline comparisons are especially useful when changing retrieval strategies, re-indexing vector stores, updating embedding models, or modifying prompt templates. NeuronScope traces each component independently so you can isolate whether a quality change came from retrieval, context assembly, or generation.

rag_compare.py
python
import neuronscope as ns

# Capture baseline RAG run (current production)
with ns.Scope("rag_baseline") as baseline_scope:
    for query in eval_queries:
        docs = old_vector_store.search(query, k=5)
        baseline_scope.log_retrieval(query=query, docs=docs)
        answer = llm.generate(build_prompt(query, docs))
baseline_scope.save("rag_baseline.nsz")

# Capture candidate RAG run (new re-indexed vector store)
with ns.Scope("rag_candidate") as candidate_scope:
    for query in eval_queries:
        docs = new_vector_store.search(query, k=5)   # same queries, new index
        candidate_scope.log_retrieval(query=query, docs=docs)
        answer = llm.generate(build_prompt(query, docs))
candidate_scope.save("rag_candidate.nsz")

# Compare — attribute changes to specific RAG components
diff = ns.compare(
    ns.load_artifact("rag_baseline.nsz"),
    ns.load_artifact("rag_candidate.nsz"),
)

# Component-level attribution
print(f"Retrieval precision Δ:  {diff.retrieval_precision_delta:+.}")
print(f"Context relevance Δ:    {diff.context_relevance_delta:+.3f}")
print(f"Generation quality Δ:   {diff.generation_quality_delta:+.3f}")
print(f"→ Root cause: {diff.primary_regression_component}")

CI/CD Deployment Gating

NeuronScope's comparison engine integrates directly into CI/CD pipelines to gate deployments on quality thresholds — preventing regressions from reaching production automatically.

ci_gate.py
python
import neuronscope as ns
import sys

# Load baseline (from artifact registry or S3)
baseline  = ns.load_artifact("s3://my-bucket/artifacts/baseline_v2.nsz")
candidate = ns.load_artifact("candidate_v3.nsz")

diff = ns.compare(baseline, candidate)

THRESHOLDS = {
    "hallucination": 0.03,   # max allowed increase in hallucination
    "quality":       -0.05,  # max allowed quality decrease
    "latency_p95":   200,    # max allowed P95 latency increase (ms)
    "cost":          0.001,  # max allowed cost increase per query
}

regressions = []
if diff.hallucination_delta > THRESHOLDS["hallucination"]:
    regressions.append(f"Hallucination increased by {diff.hallucination_delta:+.}")
if diff.quality_delta < THRESHOLDS["quality"]:
    regressions.append(f"Quality decreased by {diff.quality_delta:+.}")
if diff.latency_p95_delta_ms > THRESHOLDS["latency_p95"]:
    regressions.append(f"P95 latency increased by {diff.latency_p95_delta_ms:+.}ms")

if regressions:
    print("DEPLOYMENT BLOCKED  Regressions detected:")
    for r in regressions:
        print(f"  ✗ {r}")
    sys.exit(1)

print("DEPLOYMENT APPROVED  No regressions detected.")
print(f"  Quality Δ:    {diff.quality_delta:+.3f}")
print(f"  Latency Δ:    {diff.latency_p95_delta_ms:+.0f}ms")

Interpreting System Deltas

A positive delta in the quality metric means the candidate is better. A positive delta in hallucination score means the candidate hallucinates more (worse). Here is a quick reference:

  • Quality delta > 0 → Improvement. Candidate answers are more accurate.
  • Hallucination delta > 0 → Regression. Candidate produces more ungrounded content.
  • Latency delta > 0 → Regression. Candidate is slower.
  • Cost delta > 0 → Regression. Candidate consumes more tokens or uses more expensive APIs.
  • Retrieval precision delta > 0 → Improvement. The new vector store or embedding model is finding more relevant documents.

Structural vs. Numerical Changes

The Comparison Engine distinguishes between two types of changes:

Structural Changes

Structural changes affect the shape or composition of the AI system itself:

  • A model layer was added or removed (architecture change).
  • A retrieval step was added to or removed from the RAG pipeline.
  • An agent tool was registered or deregistered.
  • A workflow node was reordered or split.

Structural changes are detected by comparing architecture fingerprints. When a structural break is detected, the Comparer flags it with diff.has_structural_break = True and provides a structural diff summary.

Numerical Changes

Numerical changes affect the behavior of existing components without altering the system structure:

  • Model fine-tuning (same architecture, different weights).
  • Prompt template revision (same slots, different wording).
  • Vector store re-indexing (same index structure, different vectors).
  • Hyperparameter changes (temperature, top-p, max_tokens).

Numerical changes are detected by comparing weight fingerprints and evaluation metrics while the architecture fingerprint remains constant.

Related