Skip to content

Multi-Dimensional Assessment: Beyond Accuracy

Overview

Measuring only accuracy is like measuring car quality by top speed. What about safety, reliability, fuel efficiency, comfort?

Agent quality needs 8 dimensions.


The 8 Dimensions Framework

Dimension 1: Accuracy

class AccuracyMetric:
    """Does the agent produce correct outputs?"""

    def measure(self, agent, test_set):
        """
        Test set: (input, expected_output)
        """
        correct = 0

        for test_input, expected in test_set:
            output = agent.run(test_input)

            if self.matches(output, expected):
                correct += 1

        accuracy = correct / len(test_set)

        return {
            'accuracy': accuracy,
            'absolute_correct': correct,
            'absolute_total': len(test_set)
        }

    def matches(self, output, expected):
        """Flexible matching (fuzzy string, semantic, etc)"""
        return semantic_similarity(output, expected) > 0.9

Typical Range: 70-95% for production agents
Target: Domain-dependent (code: 95%, customer service: 85%)


Dimension 2: Reliability

class ReliabilityMetric:
    """Is output consistent across runs?"""

    def measure(self, agent, test_set, runs=5):
        """Run each test multiple times"""

        consistency_scores = []

        for test_input, _ in test_set:
            outputs = []

            # Run same input N times
            for _ in range(runs):
                output = agent.run(test_input)
                outputs.append(output)

            # Measure consistency
            consistency = self.measure_consistency(outputs)
            consistency_scores.append(consistency)

        return {
            'reliability': sum(consistency_scores) / len(consistency_scores),
            'consistency_details': consistency_scores
        }

    def measure_consistency(self, outputs):
        """All outputs identical? Mostly similar? Random?"""
        if all(o == outputs[0] for o in outputs):
            return 1.0  # Perfect consistency

        # Semantic similarity
        similarities = []
        for i, o1 in enumerate(outputs):
            for o2 in outputs[i+1:]:
                similarities.append(semantic_similarity(o1, o2))

        return sum(similarities) / len(similarities)

Why It Matters: Unreliable agents are worse than wrong agents (you can't trust them)
Typical Range: 75-98%


Dimension 3: Latency

class LatencyMetric:
    """How fast does the agent respond?"""

    def measure(self, agent, test_set):
        """Measure response time"""

        latencies = []

        for test_input, _ in test_set:
            start = time.time()
            agent.run(test_input)
            latency = time.time() - start
            latencies.append(latency)

        return {
            'p50': percentile(latencies, 50),  # Median
            'p95': percentile(latencies, 95),  # 95th percentile
            'p99': percentile(latencies, 99),  # 99th percentile
            'max': max(latencies),
            'mean': sum(latencies) / len(latencies)
        }

Why It Matters: Users abandon slow agents
Typical Range: - Interactive: < 1 second - Batch: < 30 seconds - Async: < 1 minute


Dimension 4: Cost

class CostMetric:
    """What's the total cost per request?"""

    def measure(self, agent, test_set):
        """Track API costs"""

        costs = {
            'llm_calls': 0,
            'api_calls': 0,
            'compute': 0,
            'total': 0
        }

        for test_input, _ in test_set:
            call_cost = agent.run_and_track_cost(test_input)
            costs['total'] += call_cost.total
            costs['llm_calls'] += call_cost.llm
            costs['api_calls'] += call_cost.apis
            costs['compute'] += call_cost.compute

        avg_cost = costs['total'] / len(test_set)

        return {
            'cost_per_call': avg_cost,
            'cost_breakdown': costs,
            'annual_cost_1m_calls': avg_cost * 1_000_000
        }

Why It Matters: Cheap but broken is worse than expensive but reliable
Typical Range: $0.001 - $0.10 per call


Dimension 5: Safety

class SafetyMetric:
    """Does agent respect policies and constraints?"""

    def measure(self, agent, policies, test_set):
        """Test policy compliance"""

        violations = {
            'data_access': 0,
            'cost_overrun': 0,
            'policy_violation': 0,
            'harmful_output': 0
        }

        for test_input, policy_constraint in test_set:
            try:
                output = agent.run(test_input)

                if not self.passes_policies(output, policies):
                    violations['policy_violation'] += 1

                if self.contains_harmful_content(output):
                    violations['harmful_output'] += 1

            except CostLimitExceeded:
                violations['cost_overrun'] += 1
            except UnauthorizedAccess:
                violations['data_access'] += 1

        compliance_rate = 1 - (sum(violations.values()) / len(test_set))

        return {
            'compliance_rate': compliance_rate,
            'violations': violations
        }

Why It Matters: One safety violation can lose customer trust
Target: > 99.5% compliance


Dimension 6: Robustness

class RobustnessMetric:
    """How well does agent handle adversarial inputs?"""

    def measure(self, agent, test_set):
        """Test on modified/adversarial inputs"""

        results = {
            'typos': 0,        # Misspelled words
            'injection': 0,    # Prompt injection
            'outliers': 0,     # Out-of-distribution
            'adversarial': 0   # Intentional attacks
        }

        for test_input, expected in test_set:
            # Test variant 1: with typos
            typo_input = self.add_typos(test_input)
            if agent.run(typo_input) still_correct:
                results['typos'] += 1

            # Test variant 2: with injection
            injection_input = self.add_injection(test_input)
            if agent.resists_injection(injection_input):
                results['injection'] += 1

            # Test variant 3: adversarial
            adversarial_input = self.make_adversarial(test_input)
            if agent.run(adversarial_input) robust:
                results['adversarial'] += 1

        robustness = sum(results.values()) / (len(results) * len(test_set))

        return {
            'robustness_score': robustness,
            'breakdown': results
        }

Why It Matters: Real users make typos, try injections, use adversarial inputs
Typical Range: 60-85%


Dimension 7: Explainability

class ExplainabilityMetric:
    """Can we understand why the agent did something?"""

    def measure(self, agent, test_set):
        """Check explanation quality"""

        scores = []

        for test_input, _ in test_set:
            output, reasoning = agent.run_with_reasoning(test_input)

            # Score explanation quality
            score = self.rate_explanation(
                reasoning,
                output,
                test_input
            )
            scores.append(score)

        explainability = sum(scores) / len(scores)

        return {
            'explainability': explainability,
            'reasoning_length': average_reasoning_length(agent),
            'token_efficiency': output_tokens / reasoning_tokens
        }

    def rate_explanation(self, reasoning, output, input_text):
        """Rate explanation on clarity, completeness, accuracy"""

        scores = {
            'addresses_input': self.covers_input(reasoning, input_text),
            'justifies_output': self.explains_output(reasoning, output),
            'step_by_step': self.is_sequential(reasoning),
            'clarity': self.measure_clarity(reasoning)
        }

        return sum(scores.values()) / len(scores)

Why It Matters: Debugging failures requires understanding decisions
Typical Range: 60-90%


Dimension 8: Correctness

class CorrectnessMetric:
    """Is the output actually correct (vs just plausible)?"""

    def measure(self, agent, test_set, ground_truth_source):
        """Verify against authoritative source"""

        correct = 0
        partially_correct = 0
        wrong = 0

        for test_input, expected_output in test_set:
            output = agent.run(test_input)

            # Verify against ground truth
            verdict = ground_truth_source.verify(output, expected_output)

            if verdict.fully_correct:
                correct += 1
            elif verdict.partially_correct:
                partially_correct += 1
            else:
                wrong += 1

        return {
            'fully_correct': correct / len(test_set),
            'partially_correct': partially_correct / len(test_set),
            'wrong': wrong / len(test_set)
        }

Why It Matters: Accuracy might measure format, correctness verifies truth
Typical Range: 70-95%


Aggregating 8 Dimensions

class ComprehensiveScore:
    def __init__(self, weights=None):
        # Customize importance of each dimension
        self.weights = weights or {
            'accuracy': 0.25,
            'reliability': 0.15,
            'latency': 0.10,
            'cost': 0.10,
            'safety': 0.15,
            'robustness': 0.10,
            'explainability': 0.10,
            'correctness': 0.05
        }

    def score(self, metrics):
        """Weighted aggregate of 8 dimensions"""

        score = 0
        for dimension, weight in self.weights.items():
            normalized = metrics[dimension] / 100  # 0-1 range
            score += normalized * weight

        return score * 100  # Back to 0-100

3 Warnings ⚠️

Warning 1: Ignoring Tradeoffs

# ❌ WRONG
agent_a = {
    'accuracy': 95,
    'latency': 5s,
    'cost': $0.10
}

agent_b = {
    'accuracy': 92,
    'latency': 0.5s,
    'cost': $0.01
}

# Which is better? Need to weight tradeoffs

# ✅ RIGHT
weights = {
    'accuracy': 0.5,      # Most important
    'latency': 0.3,       # Some importance
    'cost': 0.2           # Less important
}

score_a = weighted_score(agent_a, weights)
score_b = weighted_score(agent_b, weights)
# Now can compare fairly

Warning 2: Measuring Wrong Proxy

# ❌ WRONG
# Measure "tokens used" as efficiency proxy
efficiency = output_tokens / input_tokens

# But doesn't measure what matters:
# - Latency? - Cost? - Accuracy?

# ✅ RIGHT
# Measure what actually matters
efficiency = {
    'cost_per_correct_answer': cost / accuracy,
    'latency_for_correct': latency_when_accurate,
    'tokens_per_value': tokens / value_delivered
}

Warning 3: Static Weights

# ❌ WRONG
weights = {
    'accuracy': 0.5,
    'cost': 0.1
}  # Set once, never revisited

# But importance changes by domain:
# - Medical: accuracy >> cost
# - Customer service: cost >> accuracy

# ✅ RIGHT
weights = get_domain_specific_weights(domain)

# Medical: accuracy=0.8, cost=0.2
# CS: accuracy=0.5, cost=0.3, latency=0.2

Last Updated: August 9, 2026