Introduction
You manage a dozen VPS instances running various Docker containers, websites, and services. In daily operations, have you experienced these scenarios?
- A user reports the website is down, and only then do you SSH in to discover the disk is full;
- One server’s CPU has been spiking for three days, unnoticed until traffic anomalies appeared;
- An SSL certificate expires and breaks your service because the calendar reminder got buried;
- The monthly bill arrives, revealing several idle VPS instances burning money for nothing.
The core problem with traditional operations is reactive response — taking action only after something goes wrong. AI Agents change this paradigm, making proactive governance possible.
This article walks you through building an AI Agent-driven VPS intelligent operations system from scratch. No expensive SaaS required — everything uses open-source tools and locally-run LLMs, at zero cost.
What Is AI Agent-Driven Operations?
An AI Agent is not a simple script or rule engine. It’s an autonomous system with a sense-think-act closed loop:
- Sense: Collect and aggregate VPS state via monitoring data, log analysis, and metric fusion;
- Reason: Use LLMs to understand context, identify anomalous patterns, and diagnose root causes;
- Decide: Formulate remediation plans based on a policy library and safety boundaries;
- Act: Execute operations automatically in a controlled environment, or route to human approval;
- Learn: Record each incident’s resolution process and continuously improve judgment logic.
The key distinction from traditional alerting systems: an AI Agent doesn’t just tell you “something broke” — it tells you what happened, why it happened, and how to fix it.
Architecture Overview
The system consists of four core components:
┌─────────────────────────────────────────────────┐
│ AI Agent Orchestrator │
│ (Local LLM + Orchestration Framework) │
│ ┌──────────┬──────────┬──────────┬───────────┐ │
│ │ Sense │ Reason │ Decide │ Act │ │
│ │Collect │Analyze │Plan │Remediate │ │
│ └──────────┴──────────┴──────────┴───────────┘ │
├─────────────────────────────────────────────────┤
│ Infrastructure Layer (All VPS) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │NodeExp │ │Loki/Prom │ │Custom │ │
│ │Exporter │ │tail/Prom │ │Agents │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────┘
Component Details
Sense Layer: Reuses your existing monitoring stack (Prometheus + Node Exporter + Loki) with one key improvement — collection frequency is reduced from the standard 15 seconds to 5 seconds for finer-grained detection.
Reason Layer: The heart of the system. A lightweight local LLM (such as Qwen2.5-7B-Instruct or Mistral-7B-Instruct) processes structured prompt templates against your monitoring data for semantic analysis.
Decide Layer: Maintains an “operations knowledge graph” linking common problems to solutions. For example:
# knowledge-base/disk-full.yaml
problem: "Disk usage exceeds 90%"
indicators:
- node_filesystem_avail_bytes < 1GB
- rate(node_filesystem_write_bytes_total[1h]) > 10MB/s
possible_causes:
- name: "Log inflation"
confidence: 0.7
evidence: "rate(log_volume_bytes) spike detected"
solution: "Clean old logs, configure logrotate"
- name: "Upload accumulation"
confidence: 0.2
evidence: "/var/upload directory growing abnormally"
solution: "Archive or clean upload files"
- name: "Database bloat"
confidence: 0.1
evidence: "pg_database_size持续增长"
solution: "Run VACUUM FULL"
Act Layer: Operates in two modes:
- Auto mode: Low-risk operations execute directly (log cleanup, service restart);
- Review mode: High-risk operations require human confirmation (disk expansion, firewall rule changes).
Step 1: Unified Data Ingestion
The AI Agent needs comprehensive data input to make accurate judgments. We integrate three data source types:
1. Metrics Data
Deploy Node Exporter on each VPS and collect centrally via Prometheus:
# docker-compose.monitoring.yml
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'
- '--query.max-concurrency=20'
ports:
- "9090:9090"
loki:
image: grafana/loki:3.0.0
command: ['-config.file=/etc/loki/local-config.yaml']
ports:
- "3100:3100"
promtail:
image: grafana/promtail:3.0.0
volumes:
- /var/log:/var/log
- ./promtail-config.yml:/etc/promtail/config.yml
command: '-config.file=/etc/promtail/config.yml'
Key configuration — reduce collection interval to 5 seconds:
# prometheus.yml
global:
scrape_interval: 5s # Default 5-second collection
evaluation_interval: 15s # Evaluate rules every 15s
scrape_configs:
- job_name: 'node-exporter'
static_configs:
- targets: ['node-exporter:9100']
scrape_interval: 5s
2. Log Data
Collect all container stdout and application logs via Loki + Promtail. Structured logging directly impacts AI analysis quality. JSON output is recommended:
# Application logging config
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
tag: "{{.Name}}"
3. Business Health Checks
Beyond infrastructure metrics, you need business-level health signals:
#!/bin/bash
# health-check.sh - Business health probes
check_endpoint() {
local url=$1
local expected_code=${2:-200}
local http_code=$(curl -s -o /dev/null -w "%{http_code}" "$url" --max-time 5)
if [ "$http_code" -eq "$expected_code" ]; then
echo "OK: $url returned $http_code"
return 0
else
echo "WARN: $url returned $http_code (expected $expected_code)"
return 1
fi
}
# Check critical services
check_endpoint "http://localhost:8080/api/health" 200
check_endpoint "https://api.example.com/status" 200
check_db_connection
Step 2: Build the AI Reasoning Engine
This is the most critical part of the system. We use a locally-run LLM as the reasoning core.
Environment Setup
# Install Ollama (local LLM runtime)
curl -fsSL https://ollama.com/install.sh | sh
# Pull a model suitable for reasoning (7B runs on a 4GB VPS)
ollama pull qwen2.5:7b-instruct
# Verify
ollama run qwen2.5:7b-instruct "Hello"
Operations Analysis Prompt Template
We design dedicated prompt templates for different operational scenarios. Here’s the anomaly detection template:
# ai_agent/analyzer.py
import json
import requests
ANOMALY_PROMPT = """You are a senior SRE engineer. Analyze whether anomalies exist based on the following monitoring data.
## Current Time
{timestamp}
## Involved Servers
{server_info}
## Key Metrics
{metrics_snapshot}
## Recent Log Fragments
{recent_logs}
## Analysis Requirements
1. Determine if an anomaly exists (Yes/No)
2. If yes, list anomalous items and severity (P0-P3)
3. Hypothesize the root cause
4. Recommend remediation steps
Return as JSON:
{{
"anomaly_detected": true/false,
"severity": "P0"|"P1"|"P2"|"P3",
"issues": [
{{
"metric": "metric_name",
"current_value": "current",
"threshold": "threshold",
"deviation": "deviation %"
}}
],
"root_cause_hypothesis": "hypothesis",
"confidence": 0.0-1.0,
"recommended_actions": ["action1", "action2"],
"risk_level": "low"|"medium"|"high"
}}
"""
Calling the LLM for Reasoning
# ai_agent/orchestrator.py
class VPSOrchestrator:
def __init__(self):
self.ollama_url = "http://localhost:11434"
self.knowledge_base = KnowledgeBase()
self.policy_engine = PolicyEngine()
async def analyze_and_act(self, alert_data: dict):
"""Main loop: receive alert → analyze → decide → act"""
# 1. Collect context
context = await self.collect_context(alert_data)
# 2. Query knowledge base
kb_matches = self.knowledge_base.search(context['symptoms'])
# 3. Build prompt
prompt = ANOMALY_PROMPT.format(
timestamp=context['timestamp'],
server_info=context['server_info'],
metrics_snapshot=json.dumps(context['metrics'], indent=2),
recent_logs=context['logs'][-500:],
)
# 4. Call LLM
response = requests.post(
f"{self.ollama_url}/api/generate",
json={
"model": "qwen2.5:7b-instruct",
"prompt": prompt,
"stream": False,
"options": {
"temperature": 0.3,
"num_predict": 512
}
}
)
analysis = json.loads(response.json()['response'])
# 5. Risk assessment
risk = self.policy_engine.evaluate(analysis)
# 6. Decision branch
if risk.level == "low":
await self.execute_auto_fix(analysis)
elif risk.level == "medium":
await self.notify_and_wait(analysis)
else:
await self.escalate(analysis)
return analysis
Step 3: Three Core Capabilities
Capability 1: Capacity Prediction & Elastic Scaling
Traditional scaling is reactive — adding machines only after traffic spikes. The AI Agent predicts future trends via time-series analysis and scales proactively.
# ai_agent/capacity_planner.py
import numpy as np
from scipy.signal import find_peaks
def predict_capacity(metrics_history: list, horizon_hours: int = 24):
"""
Capacity prediction based on historical data
metrics_history: [{timestamp, cpu, memory, disk, bandwidth}, ...]
"""
timestamps = [m['timestamp'] for m in metrics_history]
cpu_values = [m['cpu'] for m in metrics_history]
mem_values = [m['memory'] for m in metrics_history]
# Detect periodic patterns (daily, weekly)
cpu_peaks, _ = find_peaks(cpu_values, distance=len(timestamps)//24)
mem_peaks, _ = find_peaks(mem_values, distance=len(timestamps)//24)
# Simple linear extrapolation (use Prophet or LSTM in production)
cpu_trend = np.polyfit(range(len(cpu_values)), cpu_values, 1)
mem_trend = np.polyfit(range(len(mem_values)), mem_values, 1)
# Predict future
predictions = []
for h in range(1, horizon_hours + 1):
idx = len(cpu_values) + h
predicted_cpu = cpu_trend[0] * idx + cpu_trend[1]
predicted_mem = mem_trend[0] * idx + mem_trend[1]
predictions.append({
'hours_ahead': h,
'predicted_cpu': min(predicted_cpu, 100),
'predicted_memory': min(predicted_mem, 100),
'needs_scaling': predicted_cpu > 80 or predicted_mem > 85
})
return predictions
Combined with auto-scaling policies:
# scaling-policy.yaml
policies:
- name: "cpu-overflow"
condition: "predicted_cpu_2h > 80"
action: "scale_up"
target: "add 1 core"
auto_approve: true
- name: "idle-resource"
condition: "avg_cpu_7d < 10 AND avg_mem_7d < 20"
action: "downsize"
target: "reduce to next tier"
auto_approve: false
- name: "weekend-reduction"
condition: "day_of_week == 6 AND hour > 22"
action: "schedule_downsize"
target: "temporarily reduce to 1C1G"
auto_approve: true
rollback_condition: "cpu > 60 OR response_time > 500ms"
Capability 2: Intelligent Root Cause Analysis
When multiple alerts fire simultaneously, traditional systems send dozens of messages. The AI Agent performs alert correlation and root cause inference.
Traditional approach:
[10:00] ⚠️ CPU usage > 90%
[10:00] ⚠️ Memory usage > 85%
[10:01] ⚠️ Disk I/O wait > 50%
[10:01] ⚠️ Network connection timeout
[10:02] 🔴 Service unavailable
→ 5 alerts, manual investigation for each
AI Agent approach:
[10:02] 📊 Alert correlation complete
🔍 Root cause: Database connection pool exhausted
├─ Trigger: max_connections reached limit
├─ Impact scope: All services depending on this DB
├─ Evidence chain:
│ ├─ CPU spike ← thread blocking from connection waits
│ ├─ Memory growth ← unreleased connection objects
│ └─ Disk I/O ↑ ← massive write queue buildup
└─ Recommended actions:
1. [Auto] Temporarily increase max_connections to 500
2. [Review] Check application code for connection leaks
3. [Schedule] Implement connection pool optimization next week
→ 1 aggregated report with complete analysis
Implementation:
# ai_agent/root_cause.py
class RootCauseAnalyzer:
def __init__(self):
self.dependency_graph = self.load_dependency_graph()
def correlate_alerts(self, alerts: list) -> dict:
"""Correlate scattered alerts into events"""
# Group by time window (default 5 minutes)
windows = self.time_window_group(alerts, window_minutes=5)
# Group by server
server_groups = self.server_group(windows)
# Further correlate via dependency relationships
correlated = []
for group in server_groups:
affected_services = self.find_affected_services(group)
if len(affected_services) > 1:
correlated.append({
'event_id': self.generate_event_id(),
'trigger_server': group['primary'],
'affected_services': affected_services,
'alert_count': len(group['alerts']),
'time_range': group['time_range']
})
return correlated
Capability 3: Automated Fix & Self-Healing
The AI Agent can execute predefined safe operations for true self-healing.
# ai_agent/remediation.py
class RemediationEngine:
SAFE_OPERATIONS = {
"disk_cleanup": {
"description": "Clean system logs and temp files",
"commands": [
"journalctl --vacuum-time=3d",
"find /tmp -type f -mtime +7 -delete",
"apt-get clean"
],
"max_risk": "low",
"rollback": "none_needed"
},
"service_restart": {
"description": "Restart specified service",
"commands": [
"systemctl restart {service}"
],
"max_risk": "medium",
"rollback": "systemctl start {service}"
},
"connection_pool_fix": {
"description": "Temporarily enlarge database connection pool",
"commands": [
"SELECT pg_reload_conf()",
"ALTER SYSTEM SET max_connections = 500"
],
"max_risk": "medium",
"rollback": "ALTER SYSTEM SET max_connections = 200"
},
"cache_clear": {
"description": "Clear application cache",
"commands": [
"redis-cli FLUSHDB",
"systemctl reload {app_service}"
],
"max_risk": "low",
"rollback": "none_needed"
}
}
async def execute_remediation(self, issue: dict, operation_key: str):
"""Execute remediation operations"""
operation = self.SAFE_OPERATIONS[operation_key]
# Risk check
if issue.get('risk_level', 'medium') != 'low' and operation['max_risk'] == 'low':
return {"status": "denied", "reason": "Risk level exceeds operation allowance"}
# Pre-execution snapshot
pre_snapshot = await self.take_system_snapshot()
# Execute operations
results = []
for cmd in operation['commands']:
result = await self.safe_execute(cmd.format(**issue))
results.append(result)
# Post-execution verification
post_snapshot = await self.take_system_snapshot()
verification = self.verify_improvement(pre_snapshot, post_snapshot, issue)
return {
"status": "success" if verification else "partial",
"operations": results,
"verification": verification,
"rollback_available": True
}
Step 4: Smart Reports & Visualization
The AI Agent doesn’t just solve problems — it makes operations traceable and auditable.
Daily Operations Summary
Every morning, the AI Agent generates an operations digest:
# 2026-07-07 Operations Report
summary:
total_events: 12
auto_resolved: 8
escalated: 2
avg_response_time: "45s"
events:
- time: "03:15"
type: "disk_cleanup"
server: "web-prod-01"
action: "Auto-cleaned logs, freed 2.3GB"
impact: "No user impact"
- time: "08:42"
type: "cpu_spike"
server: "api-prod-02"
action: "Detected anomalous process, auto-killed"
impact: "API latency spiked for 3 seconds"
followup: "Need to investigate process origin"
- time: "14:20"
type: "cert_expiring"
server: "all"
action: "SSL certificate expires in 7 days, auto-renewal triggered"
impact: "None"
insights:
- "Disk alerts this week concentrated on web-prod-01; consider optimizing log rotation"
- "api-prod-02 CPU peaks correlate strongly with deployment windows; adjust release strategy"
- "Mean time to recovery improved 35% vs. last week"
Generation Code
# ai_agent/reporter.py
async def generate_daily_report():
"""Generate daily operations report"""
events = await fetch_events(hours=24)
metrics = await aggregate_metrics(hours=24)
fixes = await get_remediation_log(hours=24)
prompt = DAILY_REPORT_PROMPT.format(
events=json.dumps(events, indent=2),
metrics=json.dumps(metrics, indent=2),
fixes=json.dumps(fixes, indent=2),
)
response = ollama.generate(prompt, model="qwen2.5:7b-instruct")
await send_to_channels({
'telegram': response['text'],
'email': generate_html_report(response['text']),
'slack': response['markdown']
})
Safety Boundaries & Risk Control
The AI Agent’s power also means greater risk. These safety principles are non-negotiable:
1. Operation Whitelist
# safety-policy.yaml
allowed_operations:
auto:
- "log_rotation"
- "temp_file_cleanup"
- "service_restart"
- "cache_clear"
- "cert_renewal"
review_required:
- "config_change"
- "firewall_rule"
- "user_management"
- "database_migration"
forbidden:
- "format_disk"
- "modify_kernel_params"
- "change_network_config"
- "delete_data"
2. Operation Audit Log
# audit_logger.py
class AuditLogger:
def log_operation(self, operator, action, target, result, confidence):
entry = {
"timestamp": datetime.utcnow().isoformat(),
"operator": operator, # "ai-agent" or "human"
"action": action,
"target": target,
"result": result,
"llm_confidence": confidence,
"snapshot_before": self.capture_state(),
"snapshot_after": self.capture_state(),
"approved_by": self.get_approval_chain(action)
}
self.audit_log.write(json.dumps(entry))
3. Emergency Stop Switch
#!/bin/bash
# emergency-stop.sh
# One-click stop all AI Agent automatic operations
echo "$(date): EMERGENCY STOP triggered" >> /var/log/ai-agent/audit.log
systemctl stop ai-agent
export MAINTENANCE_MODE=true
notify-all "⚠️ AI Agent paused, switched to manual operations mode"
Production Deployment
Full Docker Compose Configuration
# docker-compose.ai-agent.yml
version: '3.8'
services:
# --- Data Collection Layer ---
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus:/etc/prometheus
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'
ports:
- "9090:9090"
restart: unless-stopped
grafana:
image: grafana/grafana:latest
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
restart: unless-stopped
# --- AI Reasoning Layer ---
ai-agent:
build: ./ai-agent
volumes:
- ./ai-agent/knowledge-base:/app/knowledge-base
- ./ai-agent/policies:/app/policies
- ./ai-agent/reports:/app/reports
- agent_audit:/var/log/ai-agent
environment:
- OLLAMA_HOST=http://ollama:11434
- PROMETHEUS_URL=http://prometheus:9090
- GRAFANA_URL=http://grafana:3000
- TELEGRAM_BOT_TOKEN=${TELEGRAM_TOKEN}
depends_on:
- ollama
- prometheus
restart: unless-stopped
# --- Local LLM ---
ollama:
image: ollama/ollama:latest
volumes:
- ollama_data:/root/.ollama
ports:
- "11434:11434"
restart: unless-stopped
volumes:
prometheus_data:
grafana_data:
ollama_data:
agent_audit:
AI Agent Project Structure
ai-agent/
├── Dockerfile
├── requirements.txt
├── config.yaml
├── knowledge-base/
│ ├── disk-full.yaml
│ ├── cpu-spike.yaml
│ ├── cert-expiry.yaml
│ └── connection-pool.yaml
├── policies/
│ ├── safety-policy.yaml
│ └── scaling-policy.yaml
├── src/
│ ├── orchestrator.py # Main scheduler
│ ├── analyzer.py # Anomaly analysis
│ ├── root_cause.py # Root cause analysis
│ ├── capacity_planner.py # Capacity prediction
│ ├── remediation.py # Auto-fix
│ ├── reporter.py # Report generation
│ ├── notifier.py # Notification push
│ └── audit.py # Audit logging
└── tests/
├── test_analyzer.py
├── test_root_cause.py
└── test_remediation.py
Results & Metrics
After deploying this system, typical improvements include:
| Metric | Before | After | Improvement |
|---|---|---|---|
| Mean Time To Detect (MTTD) | 30 min | 2 min | ↓ 93% |
| Mean Time To Resolve (MTTR) | 45 min | 5 min | ↓ 89% |
| Monthly false positives | 50+ | < 5 | ↓ 90% |
| Night-time manual interventions | 10+/month | 1-2/month | ↓ 85% |
| Resource waste cost | ~$200/mo | ~$30/mo | ↓ 85% |
Summary
AI Agent-driven VPS intelligent operations doesn’t replace human engineers — it frees them from repetitive tasks so they can focus on higher-value architectural design and performance optimization.
Key takeaways:
- Data first: Complete monitoring and data collection form the foundation of AI reasoning;
- Start small: Begin with low-risk operations (log cleanup, cert renewal) and expand gradually;
- Safety net: Always maintain a human intervention channel and emergency stop switch;
- Continuous learning: Feed every incident’s resolution back into the system for closed-loop optimization.
When you no longer need to wake up at 3 AM to an alerting phone call, you’ll know this system is worth the investment.
All code and configurations in this article are open-source implementations. Full examples are available on GitHub. Fork and contribute welcome.
