May 8, 2026
Building AI Agents Part 3B: Testing and Evaluation Strategies for Production AI Agents
How to ensure reliability, accuracy, and trust before failures reach production

By Raj kumar
8 min read
In Part 3A Designing User Interfaces for AI Agents, we saw how even a well-built agent can fail if users cannot interact with it effectively. But usability alone is not enough.
The fintech agent was redesigned with a better interface. Adoption improved. But another issue surfaced under real usage.
Responses slowed during peak hours. Some edge cases produced inconsistent outputs. A few incorrect risk assessments raised concerns among compliance teams.
The system worked in controlled testing. It struggled in production. This is where most AI agents break. Testing is treated as a final step instead of a continuous process. Accuracy alone is not a reliable metric. Production systems require validation across latency, scalability, consistency, and failure handling.
An agent must respond within acceptable time limits. It must handle unexpected inputs. It must fail safely when confidence is low. It must provide traceability for decisions, especially in regulated environments.
Without proper testing, small issues quickly become trust failures. Users stop relying on the system. Stakeholders lose confidence. Adoption drops, even if the core model is strong. Testing is not just about correctness. It is about reliability under real-world conditions.
This is part of the series Building Production AI Agents: A Complete Architecture Guide, where we walk through an 8-step framework to take agents from concept to deployment, with practical patterns and examples across banking, healthcare, retail, manufacturing, and beyond.
In Part 3B, we explore evaluation frameworks, performance testing, edge case handling, monitoring strategies, and feedback loops that ensure your agent behaves consistently in production.
This is where trust is built.
Step 8: Testing and Evaluation
Production agents require rigorous testing. Unlike traditional software, agents have non-deterministic behavior, complex failure modes, and subtle quality degradation patterns. Testing must cover functionality, performance, quality, and safety.
Unit Testing for Components
Individual agent components need traditional unit tests: tools, memory systems, routing logic, and utility functions.
import pytest
from unittest.mock import Mock, AsyncMock
class TestFraudDetectionTools:
@pytest.mark.asyncio
async def test_transaction_history_retrieval(self):
"""Test transaction history API call."""
# Mock database
mock_db = AsyncMock()
mock_db.fetch.return_value = [
{"transaction_id": "t1", "amount": 100.0},
{"transaction_id": "t2", "amount": 200.0}
]
# Test function
tool = TransactionHistoryTool(db=mock_db)
result = await tool.get_history(
account_id="acc123",
days=30
)
# Assertions
assert len(result) == 2
assert result[0]["transaction_id"] == "t1"
mock_db.fetch.assert_called_once()
@pytest.mark.asyncio
async def test_risk_score_calculation(self):
"""Test fraud risk scoring."""
calculator = RiskScoreCalculator()
score = calculator.calculate(
transaction_amount=5000.0,
velocity_score=0.8,
merchant_risk=0.6,
location_anomaly=0.3
)
assert 0.0 <= score <= 1.0
assert score > 0.5 # High-risk indicators should elevate score
def test_routing_logic(self):
"""Test transaction routing decisions."""
router = FraudRouter()
# High-value transaction
route = router.determine_route(
amount=15000.0,
risk_score=0.4
)
assert route == "manual_review"
# High-risk score
route = router.determine_route(
amount=500.0,
risk_score=0.85
)
assert route == "investigation"
# Normal transaction
route = router.determine_route(
amount=50.0,
risk_score=0.2
)
assert route == "approve"import pytest
from unittest.mock import Mock, AsyncMock
class TestFraudDetectionTools:
@pytest.mark.asyncio
async def test_transaction_history_retrieval(self):
"""Test transaction history API call."""
# Mock database
mock_db = AsyncMock()
mock_db.fetch.return_value = [
{"transaction_id": "t1", "amount": 100.0},
{"transaction_id": "t2", "amount": 200.0}
]
# Test function
tool = TransactionHistoryTool(db=mock_db)
result = await tool.get_history(
account_id="acc123",
days=30
)
# Assertions
assert len(result) == 2
assert result[0]["transaction_id"] == "t1"
mock_db.fetch.assert_called_once()
@pytest.mark.asyncio
async def test_risk_score_calculation(self):
"""Test fraud risk scoring."""
calculator = RiskScoreCalculator()
score = calculator.calculate(
transaction_amount=5000.0,
velocity_score=0.8,
merchant_risk=0.6,
location_anomaly=0.3
)
assert 0.0 <= score <= 1.0
assert score > 0.5 # High-risk indicators should elevate score
def test_routing_logic(self):
"""Test transaction routing decisions."""
router = FraudRouter()
# High-value transaction
route = router.determine_route(
amount=15000.0,
risk_score=0.4
)
assert route == "manual_review"
# High-risk score
route = router.determine_route(
amount=500.0,
risk_score=0.85
)
assert route == "investigation"
# Normal transaction
route = router.determine_route(
amount=50.0,
risk_score=0.2
)
assert route == "approve"Unit tests verify individual components work correctly in isolation. They run fast, catch regressions early, and enable confident refactoring.
- For healthcare agents, unit test triage scoring algorithms, symptom classification logic, and appointment scheduling functions independently.
- For manufacturing agents, unit test defect classification, sensor data processing, and maintenance scheduling calculations.
Latency and Performance Testing
Production agents must meet latency requirements under realistic load. Performance testing identifies bottlenecks and capacity limits.
import asyncio
import time
from statistics import mean, median, stdev
class PerformanceTester:
def __init__(self, agent):
self.agent = agent
self.results = []
async def single_request_test(self, input_data: dict) -> float:
"""Measure single request latency."""
start_time = time.time()
try:
await self.agent.process(input_data)
latency = time.time() - start_time
return latency
except Exception as e:
logger.error(f"Request failed: {e}")
return None
async def load_test(
self,
test_cases: list,
concurrent_requests: int = 10,
duration_seconds: int = 60
):
"""Run load test with concurrent requests."""
latencies = []
errors = 0
start_time = time.time()
async def worker():
nonlocal errors
while time.time() - start_time < duration_seconds:
test_case = random.choice(test_cases)
latency = await self.single_request_test(test_case)
if latency:
latencies.append(latency)
else:
errors += 1
await asyncio.sleep(random.uniform(0.1, 0.5))
# Run concurrent workers
workers = [worker() for _ in range(concurrent_requests)]
await asyncio.gather(*workers)
# Calculate statistics
if latencies:
return {
"total_requests": len(latencies) + errors,
"successful_requests": len(latencies),
"failed_requests": errors,
"mean_latency": mean(latencies),
"median_latency": median(latencies),
"p95_latency": sorted(latencies)[int(len(latencies) * 0.95)],
"p99_latency": sorted(latencies)[int(len(latencies) * 0.99)],
"stdev_latency": stdev(latencies) if len(latencies) > 1 else 0
}import asyncio
import time
from statistics import mean, median, stdev
class PerformanceTester:
def __init__(self, agent):
self.agent = agent
self.results = []
async def single_request_test(self, input_data: dict) -> float:
"""Measure single request latency."""
start_time = time.time()
try:
await self.agent.process(input_data)
latency = time.time() - start_time
return latency
except Exception as e:
logger.error(f"Request failed: {e}")
return None
async def load_test(
self,
test_cases: list,
concurrent_requests: int = 10,
duration_seconds: int = 60
):
"""Run load test with concurrent requests."""
latencies = []
errors = 0
start_time = time.time()
async def worker():
nonlocal errors
while time.time() - start_time < duration_seconds:
test_case = random.choice(test_cases)
latency = await self.single_request_test(test_case)
if latency:
latencies.append(latency)
else:
errors += 1
await asyncio.sleep(random.uniform(0.1, 0.5))
# Run concurrent workers
workers = [worker() for _ in range(concurrent_requests)]
await asyncio.gather(*workers)
# Calculate statistics
if latencies:
return {
"total_requests": len(latencies) + errors,
"successful_requests": len(latencies),
"failed_requests": errors,
"mean_latency": mean(latencies),
"median_latency": median(latencies),
"p95_latency": sorted(latencies)[int(len(latencies) * 0.95)],
"p99_latency": sorted(latencies)[int(len(latencies) * 0.99)],
"stdev_latency": stdev(latencies) if len(latencies) > 1 else 0
}Banking fraud agents require sub-200ms latency for real-time transaction scoring. Load testing verifies performance at peak transaction volumes.
Retail pricing agents need sub-1 second response for API calls from POS systems. Performance testing simulates Black Friday traffic levels.
Healthcare triage agents should respond within 3 seconds for patient-facing chat. Latency testing ensures acceptable performance under high clinic load.
Manufacturing quality control agents need sub-500ms processing for assembly line integration. Testing verifies real-time capability at production speeds.
Quality Metrics and Evaluation
Agent quality requires domain-specific metrics beyond traditional software testing.
Accuracy and Correctness
For agents making predictions or classifications, measure accuracy against ground truth.
Banking fraud agents: precision, recall, F1 score for fraud detection. False positive rate (legitimate transactions flagged). False negative rate (fraud missed).
Healthcare triage agents: agreement rate with nurse assessments. Sensitivity for emergency conditions (never miss critical cases). Specificity to avoid over-triage.
Manufacturing quality control agents: defect detection rate compared to human inspectors. False acceptance rate (defective products passed). False rejection rate (good products failed).
class QualityEvaluator:
def __init__(self):
self.predictions = []
self.ground_truth = []
def add_evaluation(self, predicted: bool, actual: bool):
"""Record prediction for evaluation."""
self.predictions.append(predicted)
self.ground_truth.append(actual)
def calculate_metrics(self) -> dict:
"""Calculate classification metrics."""
true_positives = sum(
1 for p, a in zip(self.predictions, self.ground_truth)
if p and a
)
false_positives = sum(
1 for p, a in zip(self.predictions, self.ground_truth)
if p and not a
)
false_negatives = sum(
1 for p, a in zip(self.predictions, self.ground_truth)
if not p and a
)
true_negatives = sum(
1 for p, a in zip(self.predictions, self.ground_truth)
if not p and not a
)
precision = true_positives / (true_positives + false_positives) if (true_positives + false_positives) > 0 else 0
recall = true_positives / (true_positives + false_negatives) if (true_positives + false_negatives) > 0 else 0
f1_score = 2 * (precision * recall) / (precision + recall) if (precision + recall) > 0 else 0
return {
"precision": precision,
"recall": recall,
"f1_score": f1_score,
"true_positives": true_positives,
"false_positives": false_positives,
"false_negatives": false_negatives,
"true_negatives": true_negatives
}class QualityEvaluator:
def __init__(self):
self.predictions = []
self.ground_truth = []
def add_evaluation(self, predicted: bool, actual: bool):
"""Record prediction for evaluation."""
self.predictions.append(predicted)
self.ground_truth.append(actual)
def calculate_metrics(self) -> dict:
"""Calculate classification metrics."""
true_positives = sum(
1 for p, a in zip(self.predictions, self.ground_truth)
if p and a
)
false_positives = sum(
1 for p, a in zip(self.predictions, self.ground_truth)
if p and not a
)
false_negatives = sum(
1 for p, a in zip(self.predictions, self.ground_truth)
if not p and a
)
true_negatives = sum(
1 for p, a in zip(self.predictions, self.ground_truth)
if not p and not a
)
precision = true_positives / (true_positives + false_positives) if (true_positives + false_positives) > 0 else 0
recall = true_positives / (true_positives + false_negatives) if (true_positives + false_negatives) > 0 else 0
f1_score = 2 * (precision * recall) / (precision + recall) if (precision + recall) > 0 else 0
return {
"precision": precision,
"recall": recall,
"f1_score": f1_score,
"true_positives": true_positives,
"false_positives": false_positives,
"false_negatives": false_negatives,
"true_negatives": true_negatives
}Hallucination Detection
Agents must not fabricate information. Test for hallucinations by verifying factual claims against ground truth.
Healthcare agents must not invent symptoms or suggest non-existent treatments. Compare recommendations against approved clinical guidelines.
Banking agents must not fabricate transaction details or merchant information. Verify all data claims against actual records.
Agriculture agents must not recommend non-existent pesticides or impossible planting dates. Cross-reference recommendations against agricultural databases.
Consistency Testing
Agents should provide consistent responses to similar inputs. Test by presenting slight variations of the same query.
A retail pricing agent should recommend similar prices for similar products. Wildly different pricing for nearly identical items indicates problems.
A healthcare triage agent should assign similar urgency scores to similar symptom presentations. Inconsistent scoring undermines trust.
Safety Testing
Critical agents require safety validation beyond accuracy testing.
Healthcare agents: never recommend delaying emergency care. Test with emergency symptom presentations and verify immediate escalation.
Aviation maintenance agents: never recommend deferring safety-critical maintenance. Test with safety scenarios and verify conservative decisions.
Manufacturing agents: never approve products with safety defects. Test with safety-critical defect scenarios and verify rejection.
Iteration and Continuous Improvement
Production agents require ongoing improvement based on real-world performance.
A/B Testing
Deploy competing agent versions and measure comparative performance.
A banking fraud agent might test two different risk scoring algorithms. Route 50% of transactions to each version. Measure false positive rates, fraud catch rates, and processing times. Choose the better performer.
A retail pricing agent might test different optimization strategies. Compare revenue, margin, and inventory turnover. Select the strategy that best balances objectives.
User Feedback Integration
Collect explicit and implicit feedback from users.
Healthcare triage agents collect nurse feedback on assessment quality. Track agreement rates and disagreement patterns. Retrain models on cases where human and agent disagreed.
Manufacturing quality control agents track human inspector overrides. When human inspectors override agent decisions, analyze the cases to identify agent weaknesses.
Monitoring and Alerting
Production agents need continuous monitoring for quality degradation.
class AgentMonitor:
def __init__(self, alert_threshold: dict):
self.metrics = []
self.alert_threshold = alert_threshold
def record_metric(self, metric_name: str, value: float):
"""Record metric value."""
self.metrics.append({
"name": metric_name,
"value": value,
"timestamp": datetime.now()
})
# Check for threshold violations
if metric_name in self.alert_threshold:
if value > self.alert_threshold[metric_name]:
self.send_alert(metric_name, value)
def send_alert(self, metric_name: str, value: float):
"""Send alert for threshold violation."""
logger.warning(
f"Metric {metric_name} exceeded threshold: {value}"
)
# Send to monitoring system (PagerDuty, Slack, etc.)class AgentMonitor:
def __init__(self, alert_threshold: dict):
self.metrics = []
self.alert_threshold = alert_threshold
def record_metric(self, metric_name: str, value: float):
"""Record metric value."""
self.metrics.append({
"name": metric_name,
"value": value,
"timestamp": datetime.now()
})
# Check for threshold violations
if metric_name in self.alert_threshold:
if value > self.alert_threshold[metric_name]:
self.send_alert(metric_name, value)
def send_alert(self, metric_name: str, value: float):
"""Send alert for threshold violation."""
logger.warning(
f"Metric {metric_name} exceeded threshold: {value}"
)
# Send to monitoring system (PagerDuty, Slack, etc.)Monitor latency, error rates, quality metrics, and resource utilization. Alert when metrics degrade beyond acceptable thresholds.
Multi-Industry Testing Strategies
Banking Fraud Detection Testing
Accuracy Testing:
- Historical fraud dataset with known outcomes
- Precision/recall/F1 score targets: >95% recall, <5% false positive rate
- Test across transaction types, amounts, and merchant categories
- Verify compliance with regulatory requirements
Performance Testing:
- Simulate peak transaction volumes (10,000 transactions/second)
- Target latency <200ms at 95th percentile
- Test failover and recovery scenarios
- Validate audit trail completeness under load
Safety Testing:
- Never approve fraudulent transactions in test set
- Verify all high-risk transactions trigger review
- Confirm audit logging works under all conditions
- Test compliance with data privacy regulations
Retail Inventory Optimization Testing
Accuracy Testing:
- Historical sales data for forecast validation
- Mean absolute percentage error <15% for demand forecasts
- Pricing recommendation acceptance rate by category managers
- Stock-out reduction and inventory turnover improvement
Performance Testing:
- Process 100,000 SKU optimization daily
- API response time <1 second for POS queries
- Dashboard load time ❤ seconds with full data
- Concurrent user load testing (50+ users)
Business Impact Testing:
- A/B test optimization strategies in pilot stores
- Measure revenue, margin, and inventory metrics
- Compare human vs agent pricing decisions
- Track adoption and override rates
Healthcare Patient Triage Testing
Clinical Accuracy Testing:
- Nurse agreement rate >90% on urgency classification
- Emergency symptom detection sensitivity >99%
- Specificity >80% to avoid over-triage
- Validation across diverse patient populations
Safety Testing:
- Zero tolerance for missed emergency conditions
- Test with emergency symptom presentations
- Verify immediate escalation pathways
- Validate HIPAA compliance in all scenarios
User Experience Testing:
- Patient satisfaction surveys
- Average triage completion time <5 minutes
- Clear communication testing with diverse literacy levels
- Accessibility compliance testing
Manufacturing Quality Control Testing
Detection Accuracy Testing:
- Defect detection rate ≥95% of human inspector performance
- False positive rate <10% to minimize production impact
- Testing across product variations and defect types
- Validation on new product introductions
Performance Testing:
- Real-time processing at production line speed
- Latency <500ms per inspection
- Robustness to lighting and positioning variations
- Uptime >99.9% during production hours
Safety Testing:
- 100% catch rate for safety-critical defects
- Conservative thresholds for safety parameters
- Fail-safe behavior on sensor failures
- Validation of manual override procedures
Agriculture Crop Monitoring Testing
Prediction Accuracy Testing:
- Yield forecast accuracy within 10% of actual harvest
- Disease detection 7+ days before visible to farmers
- Irrigation recommendation validation against soil moisture
- Testing across crop types, regions, and seasons
Robustness Testing:
- Performance with cloud cover in satellite imagery
- Sensor failure handling and graceful degradation
- Offline operation capability for remote areas
- Recovery from intermittent connectivity
User Acceptance Testing:
- Farmer adoption and recommendation follow-through rates
- Actionability of recommendations
- Cost-benefit validation
- Cultural and language appropriateness
Aviation Maintenance Testing
Prediction Accuracy Testing:
- Failure prediction 30+ days advance with >80% accuracy
- False positive rate <20% to avoid unnecessary maintenance
- Validation across aircraft types and component classes
- Regulatory compliance verification
Safety Testing:
- Conservative bias in all safety-critical decisions
- Zero tolerance for deferring required maintenance
- Redundancy and failover testing
- Audit trail completeness for regulatory compliance
Integration Testing:
- End-to-end workflow validation with maintenance systems
- Parts ordering and scheduling coordination
- Crew qualification verification
- Flight schedule integration accuracy
Closing Thoughts: Testing and Evaluation for Reliable Production AI Agents
Building production AI agents requires systematic architecture across eight critical steps. From defining purpose through deployment, each step builds on previous work.
Foundation architecture determines what your agent should accomplish. Infrastructure provides the capabilities to accomplish it. Interface enables adoption. But none of it matters if the system cannot be trusted.
This is where testing and evaluation become critical.
An agent that behaves inconsistently is not usable in production. Accuracy alone is not enough. Systems must perform under load, handle edge cases, and behave predictably across real-world scenarios.
The framework matters less than the discipline of testing. A well-tested system built with simple tools will outperform a complex system that fails under pressure.
Test rigorously. Measure continuously. Improve based on real-world feedback.
The AI agent landscape evolves rapidly. Models change. Tools improve. But one principle remains constant: systems must be dependable to deliver value.
Your production journey does not end with deployment. It continues through monitoring, evaluation, and continuous improvement. If your AI agent cannot be trusted consistently, it will not be used at all.
Your engagement helps these insights reach practitioners who are building real systems. If you found this valuable, consider clapping, sharing it with your network, and adding your perspective.
What challenges are you facing with testing and evaluation of AI agents? How are you handling edge cases, failures, and real-world reliability in your systems?
Share your experience below.
This is part of the series Building Production AI Agents: A Complete Architecture Guide, where we walk through an 8-step framework to take agents from concept to deployment, with practical patterns across banking, healthcare, retail, manufacturing, and beyond.
Follow me for Part 3C, where we focus on choosing the right frameworks to build scalable, maintainable, and production-ready AI agent systems.