What Are AI Agent Maintenance Contracts?
AI agent maintenance contracts are ongoing service agreements between developers and clients that ensure deployed AI agents remain functional, secure, and performant over time. Unlike traditional software licensing models where a client purchases a perpetual license, maintenance contracts create a recurring revenue stream where clients pay regularly — monthly, quarterly, or annually — for continuous support, updates, monitoring, and optimization of their AI agent deployments.
An AI agent — whether it's a customer support bot, a code review assistant, a data pipeline orchestrator, or an autonomous trading agent — doesn't simply "run forever" after deployment. Models drift, APIs change, security vulnerabilities emerge, business logic evolves, and underlying data distributions shift. A maintenance contract formalizes the ongoing relationship required to keep these agents healthy.
Key components typically covered in such contracts include:
- Model retraining and fine-tuning — periodic updates to combat concept drift and accuracy decay
- Prompt and tool chain updates — adapting to new API versions, deprecated endpoints, or expanded capabilities
- Security patching — addressing vulnerabilities in agent dependencies and runtime environments
- Performance monitoring — tracking latency, throughput, error rates, and cost efficiency
- Usage analytics and reporting — delivering insights on agent behavior, ROI, and usage patterns
- Priority support and incident response — guaranteed SLAs for critical failures
Why Recurring Revenue Matters for AI Agent Developers
Recurring revenue transforms a project-based freelance business or product studio into a sustainable, predictable operation. For developers building AI agents, the benefits are substantial:
- Predictable cash flow — Monthly or quarterly recurring revenue (MRR/ARR) allows you to forecast income, plan hiring, and invest in infrastructure without feast-or-famine cycles
- Higher lifetime value (LTV) — A client paying $500/month for 3 years generates $18,000, far exceeding a one-time $5,000 build fee
- Compounding improvement — Continuous access to agent telemetry and usage patterns lets you improve the product iteratively, making each renewal more valuable than the last
- Valuation multiples — Companies with recurring revenue models command higher acquisition multiples (typically 3–10x ARR) compared to project-based agencies
- Reduced client acquisition costs — Retaining existing clients is 5–25x cheaper than acquiring new ones; maintenance contracts formalize retention
- Alignment of incentives — When you're paid monthly to keep an agent running well, your incentives align perfectly with the client's desire for reliable, high-performing automation
How to Structure AI Agent Maintenance Contracts
Tiered Support Models
A well-designed tier structure allows you to serve different client segments while maximizing revenue from high-value accounts. Here's a proven three-tier framework:
# Example Tier Configuration (JSON structure for contract management system)
{
"tiers": {
"essential": {
"monthly_price": 499,
"included_hours": 5,
"response_time_sla": "48h",
"resolution_sla": "5 business days",
"monitoring": "basic_health_checks",
"retraining": "quarterly",
"support_channels": ["email"],
"max_agents_covered": 3,
"additional_agent_cost": 149
},
"professional": {
"monthly_price": 1499,
"included_hours": 15,
"response_time_sla": "8h",
"resolution_sla": "48h",
"monitoring": "full_telemetry_with_alerts",
"retraining": "monthly",
"support_channels": ["email", "slack", "phone_emergency"],
"max_agents_covered": 10,
"additional_agent_cost": 129,
"includes": ["quarterly_business_review", "cost_optimization_report"]
},
"enterprise": {
"monthly_price": 4999,
"included_hours": 40,
"response_time_sla": "1h",
"resolution_sla": "4h",
"monitoring": "full_telemetry_with_predictive_alerts",
"retraining": "continuous_adaptive",
"support_channels": ["email", "slack", "phone_emergency", "dedicated_dsm"],
"max_agents_covered": 50,
"additional_agent_cost": 99,
"includes": ["monthly_strategy_session", "custom_sla_negotiation",
"on_premise_support", "compliance_reporting"]
}
}
}
Pricing Strategies
Several pricing models work well for AI agent maintenance contracts. The right choice depends on your agent's value proposition and the client's usage pattern:
- Flat monthly fee by tier — Simplest to sell and administer; works well when agent complexity and usage are relatively uniform across clients
- Per-agent pricing — Charge per deployed agent instance; scales naturally as clients expand their automation footprint
- Usage-based pricing — Tie maintenance fees to inference volume (e.g., per 1,000 API calls); aligns cost with value delivered but requires metering infrastructure
- Outcome-based pricing — Charge based on measurable results (e.g., tickets deflected, leads qualified, trades executed); highest upside but requires attribution tracking
- Hybrid models — Combine a base platform fee with usage overage charges; provides stability plus growth upside
# Hybrid pricing calculator example
class MaintenancePricingCalculator:
def __init__(self, base_fee: float, included_requests: int,
overage_rate_per_1000: float, retraining_surcharge: float = 0):
self.base_fee = base_fee
self.included_requests = included_requests
self.overage_rate = overage_rate_per_1000
self.retraining_surcharge = retraining_surcharge
def calculate_monthly(self, total_requests: int,
retraining_triggered: bool = False) -> dict:
overage = max(0, total_requests - self.included_requests)
overage_cost = (overage / 1000) * self.overage_rate
subtotal = self.base_fee + overage_cost
retraining_fee = self.retraining_surcharge if retraining_triggered else 0
return {
"base_fee": self.base_fee,
"overage_requests": overage,
"overage_cost": round(overage_cost, 2),
"retraining_fee": retraining_fee,
"total": round(subtotal + retraining_fee, 2),
"effective_rate_per_request": round(
(subtotal + retraining_fee) / max(total_requests, 1), 4
)
}
# Usage example
calculator = MaintenancePricingCalculator(
base_fee=999.00,
included_requests=100000,
overage_rate_per_1000=5.50,
retraining_surcharge=250.00
)
invoice = calculator.calculate_monthly(
total_requests=142000,
retraining_triggered=True
)
print(invoice)
# Output: {
# 'base_fee': 999.0,
# 'overage_requests': 42000,
# 'overage_cost': 231.0,
# 'retraining_fee': 250.0,
# 'total': 1480.0,
# 'effective_rate_per_request': 0.0104
# }
Contract Lifecycle Management
A robust maintenance contract system must handle the entire lifecycle — from initial agreement through renewal, upsell, and (when necessary) graceful offboarding:
# Contract lifecycle state machine
from enum import Enum
from datetime import datetime, timedelta
from typing import Optional
class ContractState(Enum):
DRAFT = "draft"
PENDING_APPROVAL = "pending_approval"
ACTIVE = "active"
GRACE_PERIOD = "grace_period"
SUSPENDED = "suspended"
RENEWAL_NEGOTIATION = "renewal_negotiation"
EXPIRED = "expired"
TERMINATED = "terminated"
class MaintenanceContract:
def __init__(self, contract_id: str, client_name: str, tier: str,
monthly_fee: float, start_date: datetime, duration_months: int):
self.contract_id = contract_id
self.client_name = client_name
self.tier = tier
self.monthly_fee = monthly_fee
self.start_date = start_date
self.end_date = start_date + timedelta(days=30 * duration_months)
self.state = ContractState.DRAFT
self.auto_renew = False
self.renewal_reminders_sent = []
self.payment_history = []
self.modifications_log = []
def activate(self) -> bool:
if self.state in (ContractState.DRAFT, ContractState.PENDING_APPROVAL):
self.state = ContractState.ACTIVE
self.modifications_log.append({
"timestamp": datetime.now().isoformat(),
"action": "activate",
"previous_state": "draft"
})
return True
return False
def enter_grace_period(self) -> None:
self.state = ContractState.GRACE_PERIOD
self.modifications_log.append({
"timestamp": datetime.now().isoformat(),
"action": "grace_period_entered",
"reason": "payment_overdue"
})
def process_renewal(self, new_duration_months: int,
adjusted_fee: Optional[float] = None) -> None:
if self.state == ContractState.GRACE_PERIOD:
self.state = ContractState.RENEWAL_NEGOTIATION
new_fee = adjusted_fee or self.monthly_fee
self.monthly_fee = new_fee
self.start_date = self.end_date
self.end_date = self.start_date + timedelta(days=30 * new_duration_months)
self.state = ContractState.ACTIVE
self.renewal_reminders_sent = []
self.modifications_log.append({
"timestamp": datetime.now().isoformat(),
"action": "renewal",
"new_fee": new_fee,
"new_end_date": self.end_date.isoformat()
})
def check_renewal_window(self) -> dict:
"""Returns renewal status and recommended actions"""
days_remaining = (self.end_date - datetime.now()).days
if days_remaining < 0:
return {"status": "expired", "action": "enter_grace_period"}
elif days_remaining <= 30 and len(self.renewal_reminders_sent) == 0:
return {"status": "renewal_window", "action": "send_first_reminder"}
elif days_remaining <= 14 and len(self.renewal_reminders_sent) == 1:
return {"status": "urgent_renewal", "action": "send_second_reminder"}
elif days_remaining <= 7 and len(self.renewal_reminders_sent) <= 2:
return {"status": "critical_renewal", "action": "schedule_client_call"}
else:
return {"status": "active_stable", "action": "no_action_needed"}
Implementation: Building a Maintenance Contract System
Contract Data Model and Database Schema
A production-ready maintenance contract system requires careful schema design. Here's a PostgreSQL schema that supports multi-tenant, multi-tier contract management with full audit trails:
-- Core schema for AI Agent Maintenance Contract System
CREATE TABLE clients (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_name VARCHAR(255) NOT NULL,
contact_email VARCHAR(255) NOT NULL,
billing_email VARCHAR(255),
stripe_customer_id VARCHAR(100) UNIQUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE TABLE ai_agents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
agent_name VARCHAR(255) NOT NULL,
agent_type VARCHAR(100) NOT NULL, -- e.g., 'chatbot', 'code_review', 'data_pipeline'
deployment_environment VARCHAR(100),
model_provider VARCHAR(100),
model_version VARCHAR(50),
average_daily_requests INTEGER DEFAULT 0,
last_health_check TIMESTAMP WITH TIME ZONE,
status VARCHAR(50) DEFAULT 'active',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(client_id, agent_name)
);
CREATE TABLE maintenance_tiers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tier_name VARCHAR(100) NOT NULL UNIQUE,
monthly_base_fee DECIMAL(10,2) NOT NULL,
included_support_hours INTEGER NOT NULL,
included_retraining_events INTEGER DEFAULT 0,
sla_response_hours INTEGER NOT NULL,
sla_resolution_hours INTEGER NOT NULL,
max_agents_included INTEGER NOT NULL,
additional_agent_fee DECIMAL(10,2) NOT NULL,
overage_hourly_rate DECIMAL(10,2) NOT NULL,
features JSONB DEFAULT '{}',
is_active BOOLEAN DEFAULT true
);
CREATE TABLE contracts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
contract_number VARCHAR(50) NOT NULL UNIQUE,
client_id UUID NOT NULL REFERENCES clients(id),
tier_id UUID NOT NULL REFERENCES maintenance_tiers(id),
status VARCHAR(50) NOT NULL DEFAULT 'draft',
-- 'draft', 'active', 'grace_period', 'suspended', 'renewed', 'expired', 'terminated'
start_date DATE NOT NULL,
end_date DATE NOT NULL,
auto_renew BOOLEAN DEFAULT false,
renewal_reminder_count INTEGER DEFAULT 0,
last_renewal_action TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE TABLE contract_agents (
contract_id UUID NOT NULL REFERENCES contracts(id) ON DELETE CASCADE,
agent_id UUID NOT NULL REFERENCES ai_agents(id) ON DELETE CASCADE,
added_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
PRIMARY KEY (contract_id, agent_id)
);
CREATE TABLE invoices (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
contract_id UUID NOT NULL REFERENCES contracts(id),
invoice_number VARCHAR(50) NOT NULL UNIQUE,
period_start DATE NOT NULL,
period_end DATE NOT NULL,
base_amount DECIMAL(10,2) NOT NULL,
overage_hours DECIMAL(10,2) DEFAULT 0,
overage_amount DECIMAL(10,2) DEFAULT 0,
additional_agents_fee DECIMAL(10,2) DEFAULT 0,
retraining_events_fee DECIMAL(10,2) DEFAULT 0,
total_amount DECIMAL(10,2) NOT NULL,
status VARCHAR(50) DEFAULT 'pending',
-- 'pending', 'sent', 'paid', 'overdue', 'void'
stripe_invoice_id VARCHAR(100),
due_date DATE NOT NULL,
paid_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE TABLE sla_incidents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
contract_id UUID NOT NULL REFERENCES contracts(id),
agent_id UUID REFERENCES ai_agents(id),
incident_type VARCHAR(100) NOT NULL,
severity VARCHAR(20) NOT NULL, -- 'critical', 'high', 'medium', 'low'
detected_at TIMESTAMP WITH TIME ZONE NOT NULL,
acknowledged_at TIMESTAMP WITH TIME ZONE,
resolved_at TIMESTAMP WITH TIME ZONE,
sla_target_hours INTEGER,
actual_resolution_hours DECIMAL(8,2),
sla_breached BOOLEAN DEFAULT false,
postmortem_document_url VARCHAR(500),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Index for performance
CREATE INDEX idx_contracts_status ON contracts(status);
CREATE INDEX idx_invoices_status_due ON invoices(status, due_date);
CREATE INDEX idx_sla_incidents_contract ON sla_incidents(contract_id, detected_at);
CREATE INDEX idx_ai_agents_client_status ON ai_agents(client_id, status);
Automated Billing Engine
The billing engine is the financial heart of your maintenance contract system. It must handle recurring invoice generation, proration, usage calculation, and integration with payment processors:
# Automated billing engine with Stripe integration
import stripe
from datetime import datetime, date, timedelta
from decimal import Decimal
from typing import List, Optional
stripe.api_key = "sk_live_..."
class MaintenanceBillingEngine:
def __init__(self, db_connection):
self.db = db_connection
self.today = date.today()
def generate_monthly_invoices(self) -> dict:
"""Batch generate invoices for all active contracts"""
active_contracts = self.db.query(
"""SELECT c.id, c.contract_number, c.client_id, c.tier_id,
c.start_date, c.end_date, cl.stripe_customer_id,
cl.company_name, t.monthly_base_fee, t.additional_agent_fee,
t.overage_hourly_rate, t.included_support_hours
FROM contracts c
JOIN clients cl ON c.client_id = cl.id
JOIN maintenance_tiers t ON c.tier_id = t.id
WHERE c.status = 'active'
AND c.end_date >= CURRENT_DATE"""
)
generated = []
for contract in active_contracts:
invoice_data = self._calculate_invoice_for_contract(contract)
if invoice_data['total_amount'] > 0:
# Create Stripe invoice
stripe_invoice = stripe.Invoice.create(
customer=contract['stripe_customer_id'],
auto_advance=True,
collection_method='charge_automatically',
days_until_due=30,
metadata={
'contract_id': contract['id'],
'contract_number': contract['contract_number']
}
)
# Add line items
stripe.InvoiceItem.create(
customer=contract['stripe_customer_id'],
invoice=stripe_invoice.id,
amount=int(invoice_data['base_amount'] * 100), # cents
currency='usd',
description=f"AI Agent Maintenance - {contract['tier_name']} Tier"
)
if invoice_data['overage_amount'] > 0:
stripe.InvoiceItem.create(
customer=contract['stripe_customer_id'],
invoice=stripe_invoice.id,
amount=int(invoice_data['overage_amount'] * 100),
currency='usd',
description=f"Support overage - {invoice_data['overage_hours']} hours"
)
stripe.Invoice.finalize_invoice(stripe_invoice.id)
# Store in our database
self.db.execute(
"""INSERT INTO invoices (contract_id, invoice_number,
period_start, period_end, base_amount, overage_hours,
overage_amount, additional_agents_fee, total_amount,
stripe_invoice_id, due_date)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""",
(contract['id'], f"INV-{datetime.now().strftime('%Y%m')}-{contract['contract_number']}",
invoice_data['period_start'], invoice_data['period_end'],
invoice_data['base_amount'], invoice_data['overage_hours'],
invoice_data['overage_amount'], invoice_data['additional_agents_fee'],
invoice_data['total_amount'], stripe_invoice.id,
self.today + timedelta(days=30))
)
generated.append({
'contract_id': contract['id'],
'invoice_total': invoice_data['total_amount'],
'stripe_invoice_id': stripe_invoice.id
})
return {
'total_invoices_generated': len(generated),
'total_revenue': sum(g['invoice_total'] for g in generated),
'invoices': generated
}
def _calculate_invoice_for_contract(self, contract: dict) -> dict:
"""Calculate detailed invoice amounts for a single contract"""
period_start = date(self.today.year, self.today.month, 1)
period_end = date(
self.today.year,
self.today.month + 1 if self.today.month < 12 else 1,
1
) - timedelta(days=1)
# Base fee
base_amount = contract['monthly_base_fee']
# Count agents on contract
agent_count = self.db.query_one(
"""SELECT COUNT(*) as count FROM contract_agents
WHERE contract_id = %s""",
(contract['id'],)
)['count']
max_included = contract.get('max_agents_included', 3)
extra_agents = max(0, agent_count - max_included)
additional_agents_fee = extra_agents * contract['additional_agent_fee']
# Calculate support overage
support_hours_used = self.db.query_one(
"""SELECT COALESCE(SUM(hours_logged), 0) as total
FROM support_tickets
WHERE contract_id = %s
AND created_at BETWEEN %s AND %s""",
(contract['id'], period_start, period_end)
)['total']
overage_hours = max(
0,
support_hours_used - contract['included_support_hours']
)
overage_amount = overage_hours * contract['overage_hourly_rate']
total = base_amount + additional_agents_fee + overage_amount
return {
'period_start': period_start,
'period_end': period_end,
'base_amount': base_amount,
'agent_count': agent_count,
'extra_agents': extra_agents,
'additional_agents_fee': additional_agents_fee,
'support_hours_used': support_hours_used,
'overage_hours': overage_hours,
'overage_amount': overage_amount,
'total_amount': total
}
def handle_payment_failure(self, invoice_id: str) -> None:
"""Handle failed payments - dunning process and contract status update"""
invoice = self.db.query_one(
"""SELECT i.*, c.status as contract_status, c.id as contract_id
FROM invoices i
JOIN contracts c ON i.contract_id = c.id
WHERE i.stripe_invoice_id = %s""",
(invoice_id,)
)
if not invoice:
return
days_overdue = (self.today - invoice['due_date']).days
if days_overdue >= 30 and invoice['contract_status'] == 'active':
# Move contract to grace period after 30 days overdue
self.db.execute(
"""UPDATE contracts SET status = 'grace_period',
updated_at = NOW() WHERE id = %s""",
(invoice['contract_id'],)
)
# Send suspension notice
self._send_email_template(
invoice['client_email'],
'service_suspension_warning',
{'days_overdue': days_overdue}
)
elif days_overdue >= 60:
# Suspend services after 60 days
self.db.execute(
"""UPDATE contracts SET status = 'suspended',
updated_at = NOW() WHERE id = %s""",
(invoice['contract_id'],)
)
# Disable agent API access
self._disable_agent_access(invoice['contract_id'])
def _disable_agent_access(self, contract_id: str) -> None:
"""Revoke API keys and disable agent endpoints for a contract"""
self.db.execute(
"""UPDATE ai_agents SET status = 'suspended'
WHERE id IN (
SELECT agent_id FROM contract_agents
WHERE contract_id = %s
)""",
(contract_id,)
)
SLA Monitoring and Incident Management
Service Level Agreement (SLA) compliance is a cornerstone of maintenance contracts. An automated monitoring system tracks agent health, detects incidents, and measures resolution times against contractual obligations:
# SLA monitoring service with alerting
import asyncio
import aiohttp
from datetime import datetime, timedelta
from dataclasses import dataclass
from typing import List, Dict
@dataclass
class SLADefinition:
severity: str
response_time_minutes: int
resolution_time_minutes: int
availability_target_percent: float
class SLAMonitoringService:
def __init__(self, db_pool, notification_client):
self.db = db_pool
self.notifier = notification_client
self.sla_definitions = {
'critical': SLADefinition('critical', 60, 240, 99.95),
'high': SLADefinition('high', 240, 1440, 99.9),
'medium': SLADefinition('medium', 480, 2880, 99.5),
'low': SLADefinition('low', 1440, 5760, 99.0)
}
async def check_agent_health(self, agent_id: str) -> dict:
"""Perform comprehensive health check on an AI agent"""
agent = await self.db.fetch_one(
"""SELECT a.*, c.id as contract_id, t.sla_response_hours,
t.sla_resolution_hours
FROM ai_agents a
JOIN contract_agents ca ON a.id = ca.agent_id
JOIN contracts c ON ca.contract_id = c.id
JOIN maintenance_tiers t ON c.tier_id = t.id
WHERE a.id = %s AND a.status = 'active'
AND c.status = 'active'""",
(agent_id,)
)
if not agent:
return {'status': 'no_active_contract'}
checks = {}
# Check HTTP health endpoint
try:
async with aiohttp.ClientSession() as session:
async with session.get(
f"{agent['deployment_url']}/health",
timeout=aiohttp.ClientTimeout(total=10)
) as resp:
checks['http_status'] = resp.status
checks['http_ok'] = resp.status == 200
except Exception as e:
checks['http_status'] = 'unreachable'
checks['http_ok'] = False
checks['error'] = str(e)
# Check latency
try:
async with aiohttp.ClientSession() as session:
start = datetime.now()
async with session.get(
f"{agent['deployment_url']}/ping",
timeout=aiohttp.ClientTimeout(total=5)
) as resp:
latency_ms = (datetime.now() - start).total_seconds() * 1000
checks['latency_ms'] = round(latency_ms, 2)
checks['latency_ok'] = latency_ms < 2000
except Exception:
checks['latency_ms'] = None
checks['latency_ok'] = False
# Check error rate in last hour
recent_errors = await self.db.fetch_val(
"""SELECT COUNT(*) FROM agent_logs
WHERE agent_id = %s
AND level = 'ERROR'
AND timestamp > NOW() - INTERVAL '1 hour'""",
(agent_id,)
)
total_requests = await self.db.fetch_val(
"""SELECT COUNT(*) FROM agent_logs
WHERE agent_id = %s
AND timestamp > NOW() - INTERVAL '1 hour'""",
(agent_id,)
)
error_rate = (recent_errors / max(total_requests, 1)) * 100
checks['error_rate_percent'] = round(error_rate, 2)
checks['error_rate_ok'] = error_rate < 5.0
# Determine overall health
is_healthy = all([
checks.get('http_ok', False),
checks.get('latency_ok', False),
checks.get('error_rate_ok', False)
])
if not is_healthy:
await self._create_incident(agent, checks)
return {
'agent_id': agent_id,
'healthy': is_healthy,
'checks': checks,
'timestamp': datetime.now().isoformat()
}
async def _create_incident(self, agent: dict, checks: dict) -> str:
"""Create SLA incident and notify relevant parties"""
severity = self._determine_severity(checks)
incident_id = await self.db.execute(
"""INSERT INTO sla_incidents
(contract_id, agent_id, incident_type, severity, detected_at,
sla_target_hours)
VALUES (%s, %s, %s, %s, %s, %s)
RETURNING id""",
(agent['contract_id'], agent['id'], 'health_check_failure',
severity, datetime.now(),
self.sla_definitions[severity].resolution_time_minutes / 60)
)
# Notify support team
await self.notifier.send_pagerduty_alert({
'incident_id': incident_id,
'agent': agent['agent_name'],
'client': agent['company_name'],
'severity': severity,
'checks': checks
})
# Log for contract reporting
await self.db.execute(
"""INSERT INTO incident_notifications
(incident_id, channel, sent_at)
VALUES (%s, 'pagerduty', %s)""",
(incident_id, datetime.now())
)
return incident_id
def _determine_severity(self, checks: dict) -> str:
"""Map health check results to SLA severity levels"""
if checks.get('http_ok') is False:
return 'critical'
if checks.get('error_rate_percent', 0) > 20:
return 'critical'
if checks.get('error_rate_percent', 0) > 10:
return 'high'
if not checks.get('latency_ok', True):
return 'medium'
return 'low'
async def generate_sla_report(self, contract_id: str,
month: int, year: int) -> dict:
"""Generate monthly SLA compliance report for client"""
period_start = date(year, month, 1)
period_end = date(
year, month + 1 if month < 12 else 1, 1
) - timedelta(days=1)
incidents = await self.db.fetch_all(
"""SELECT severity, detected_at, resolved_at,
sla_target_hours, actual_resolution_hours,
sla_breached
FROM sla_incidents
WHERE contract_id = %s
AND detected_at BETWEEN %s AND %s""",
(contract_id, period_start, period_end)
)
total_incidents = len(incidents)
breached = sum(1 for i in incidents if i['sla_breached'])
# Calculate uptime percentage
total_minutes_in_period = (
(period_end - period_start).days + 1
) * 24 * 60
incident_minutes = sum(
(i['actual_resolution_hours'] or i['sla_target_hours']) * 60
for i in incidents
)
uptime = ((total_minutes_in_period - incident_minutes) /
total_minutes_in_period) * 100
report = {
'contract_id': contract_id,
'period': f"{year}-{month:02d}",
'total_incidents': total_incidents,
'sla_breaches': breached,
'compliance_rate': round(
((total_incidents - breached) / max(total_incidents, 1)) * 100, 2
),
'uptime_percentage': round(uptime, 4),
'incidents_by_severity': {},
'recommendations': []
}
# Severity breakdown
for severity in ['critical', 'high', 'medium', 'low']:
count = sum(1 for i in incidents if i['severity'] == severity)
if count > 0:
report['incidents_by_severity'][severity] = count
# Generate recommendations
if breached > 0:
report['recommendations'].append(
"Review incident response procedures for faster resolution times"
)
if uptime < 99.5:
report['recommendations'].append(
"Consider upgrading to Enterprise tier for predictive monitoring"
)
return report
Best Practices for AI Agent Maintenance Contracts
Define Clear Scope Boundaries
Nothing erodes maintenance contract profitability faster than scope creep. Clearly delineate what's included and what constitutes billable change work:
- Included maintenance: Bug fixes, security patches, model retraining within existing architecture, API compatibility updates, performance tuning within 20% of baseline
- Billable change requests: New features, additional integrations, architecture changes, migration to new model providers, custom dashboard development
- Shared responsibility: Document what the client must maintain (e.g., their API keys, their infrastructure, their data quality) versus what you're responsible for
# Example scope definition embedded in contract metadata
scope_definition = {
"maintenance_included": [
"weekly_health_checks",
"monthly_model_retraining_with_existing_architecture",
"security_patches_critical_and_high",
"api_version_compatibility_updates",
"cost_optimization_within_20_percent_baseline",
"incident_response_per_sla_table"
],
"change_requests_billable": [
"new_agent_capabilities_or_tools",
"additional_data_source_integrations",
"model_provider_m