Il problema: report di manutenzione che nessuno vuole scrivere
Gestire 40+ siti WordPress per clienti significa una cosa che tutti odiano: i report mensili. Ogni mese, 8 ore perse a copiare dati da dashboard, scrivere frasi generiche tipo “aggiornati 12 plugin” e impaginare PDF che il cliente apre una volta (forse).
Non era sostenibile. Con l’automazione della gestione WordPress avevamo già risolto gli aggiornamenti e il monitoraggio. Ma i report restavano manuali. Un collo di bottiglia assurdo.
Così abbiamo costruito il sistema di report automatici di AgencyPilot, alimentato da Claude API. Questo articolo racconta come funziona, con il codice reale che usiamo in produzione.
TL;DR
AgencyPilot raccoglie dati di manutenzione (uptime, aggiornamenti, sicurezza, performance) tramite REST API WordPress, li invia a Claude API con un prompt strutturato, e genera report personalizzati per ogni cliente. Tempo di generazione: 12 secondi per report. Tempo risparmiato: 8+ ore al mese.
Architettura del sistema di report automatici
Il sistema si compone di tre parti. Niente di complicato, ma ogni pezzo ha un ruolo preciso.
1. Raccolta dati via REST API
AgencyPilot ha un plugin WordPress installato su ogni sito gestito. Questo plugin espone endpoint REST API personalizzati che restituiscono i dati di manutenzione del mese:
// Endpoint REST API nel plugin AgencyPilot
add_action('rest_api_init', function() {
register_rest_route('agencypilot/v1', '/maintenance-report', [
'methods' => 'GET',
'callback' => 'ap_get_maintenance_data',
'permission_callback' => 'ap_verify_api_key',
]);
});
function ap_get_maintenance_data(WP_REST_Request $request) {
$period = $request->get_param('period') ?? 'last_month';
return [
'site_url' => home_url(),
'wp_version' => get_bloginfo('version'),
'uptime' => ap_get_uptime_percentage($period),
'updates' => ap_get_update_log($period),
'security' => ap_get_security_events($period),
'performance' => ap_get_performance_metrics($period),
'backups' => ap_get_backup_log($period),
];
}
Ogni campo restituisce dati strutturati. Per esempio, updates include il nome del plugin, la versione precedente, la nuova versione e la data dell’aggiornamento. Dati grezzi, nessuna interpretazione.
2. Aggregazione e prompt engineering
Il backend FastAPI di AgencyPilot raccoglie i dati da tutti i siti di un cliente e costruisce il prompt per Claude. Questa è la parte che ha richiesto più iterazioni (e più tentativi falliti).
import anthropic
from datetime import datetime
client = anthropic.Anthropic()
def generate_report(client_name: str, sites_data: list[dict]) -> str:
system_prompt = """Sei un tecnico WordPress senior che scrive report
di manutenzione per clienti non tecnici. Regole:
- Scrivi in italiano naturale, non burocratese
- Ogni sezione deve spiegare PERCHÉ un'azione è importante
- Segnala criticità con priorità (alta/media/bassa)
- Includi raccomandazioni specifiche quando serve
- Usa numeri concreti, mai frasi vaghe
- Tono professionale ma diretto"""
user_prompt = f"""Genera un report di manutenzione mensile per il
cliente {client_name}.
Periodo: {datetime.now().strftime('%B %Y')}
Dati raccolti dai siti:
{format_sites_data(sites_data)}
Struttura richiesta:
1. Riepilogo esecutivo (3-4 frasi)
2. Stato uptime e disponibilità
3. Aggiornamenti effettuati (plugin, temi, core)
4. Sicurezza: scansioni e eventi
5. Performance: Core Web Vitals
6. Backup: stato e test di ripristino
7. Raccomandazioni per il prossimo mese"""
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=4096,
system=system_prompt,
messages=[{"role": "user", "content": user_prompt}]
)
return response.content[0].text
Un dettaglio importante: usiamo claude-sonnet-4-20250514, non Opus. Per i report, Sonnet ha il rapporto qualità/costo migliore. Con Opus la qualità del testo migliora del 10-15%, ma il costo per report triplica. Per 40+ report al mese, la differenza si sente.
3. Generazione PDF e invio
L’output di Claude è in Markdown strutturato. Lo convertiamo in HTML con il branding del cliente (logo, colori) e poi in PDF con weasyprint:
from weasyprint import HTML
import markdown
def report_to_pdf(report_md: str, client_config: dict) -> bytes:
html_content = markdown.markdown(report_md, extensions=['tables'])
styled_html = f"""
<html>
<head><style>
body {{ font-family: 'Inter', sans-serif; color: #1a1a1a; }}
h1 {{ color: {client_config['brand_color']}; }}
.metric {{ font-size: 2em; font-weight: 700; }}
.status-ok {{ color: #16a34a; }}
.status-warn {{ color: #d97706; }}
.status-critical {{ color: #dc2626; }}
</style></head>
<body>
<img src="{client_config['logo_url']}" height="40">
{html_content}
</body>
</html>"""
return HTML(string=styled_html).write_pdf()
Il PDF viene salvato in S3 e il link inviato al cliente via email (o reso disponibile nel portale clienti di AgencyPilot).
Le 4 lezioni apprese in 6 mesi di produzione
Il sistema è in produzione da settembre 2025. Non è stato tutto liscio. Ecco cosa abbiamo imparato.
Lezione 1: i dati grezzi battono i dati pre-interpretati
La prima versione inviava a Claude dati già interpretati (“uptime buono”, “plugin aggiornati regolarmente”). Errore. Claude produceva report generici, quasi identici per ogni cliente.
La soluzione: inviare solo numeri grezzi. Uptime 99.7%. Plugin aggiornati: 14 su 18. Tempo medio di risposta: 340ms. Claude interpreta i numeri nel contesto e produce osservazioni specifiche. Se un sito ha uptime del 97.2%, Claude lo segnala come problema e suggerisce di investigare (perché un sito WordPress ben configurato dovrebbe stare sopra il 99.5%).
Lezione 2: un prompt non basta, servono esempi
Il prompt generico produceva report accettabili. Ma “accettabile” non è il livello che vogliamo per i clienti. Abbiamo aggiunto few-shot examples al prompt: due report reali scritti da noi, con annotazioni su cosa li rendeva buoni.
Risultato: la qualità è salita al punto che 3 clienti ci hanno scritto per dire che i report erano “molto migliorati”. Non sapevano che li generava un’AI.
Lezione 3: il costo scala bene (se non sprechi token)
Con 42 siti gestiti, generiamo circa 25 report al mese (alcuni clienti hanno più siti). Costo medio per report con Claude Sonnet: circa $0.08. Totale mensile: sotto i $2. Otto ore di lavoro risparmiate per meno di 2 dollari. Il ROI non ha bisogno di spiegazioni.
Il trucco: comprimere i dati. La prima versione inviava JSON verboso (con timestamp completi, metadati inutili). Abbiamo ridotto il payload medio da 12.000 a 3.500 token tagliando tutto ciò che Claude non aveva bisogno di sapere.
Lezione 4: la revisione umana resta indispensabile
Ogni report passa da una revisione manuale prima dell’invio. Dura 2-3 minuti per report (contro i 20-25 minuti della scrittura manuale). Claude a volte enfatizza troppo problemi minori o sottovaluta pattern che solo chi conosce il cliente può cogliere.
Abbiamo automatizzato il 90% del lavoro. Quel 10% umano è ciò che mantiene la qualità al livello giusto.
Integrazione con il monitoring di AgencyPilot
I report non esistono in isolamento. Sono il risultato di tutto il sistema di monitoring che AgencyPilot esegue continuamente.
Uptime monitoring
AgencyPilot controlla ogni sito ogni 5 minuti. Se un sito non risponde per 2 check consecutivi (10 minuti), parte una notifica. I dati di uptime che finiscono nel report sono calcolati su questi check: percentuale di check riusciti sul totale del mese.
Con la sicurezza WordPress configurata correttamente, la maggior parte dei downtime è causata da problemi hosting, non da attacchi.
Security scanning
Lo scanner gira una volta al giorno. Controlla: integrità dei file core, plugin con vulnerabilità note (via WPScan API), permessi file anomali, utenti admin sospetti. Ogni evento viene loggato e finisce nel report mensile.
Performance tracking
Una volta a settimana, AgencyPilot misura i Core Web Vitals di ogni sito tramite PageSpeed Insights API. I dati di performance WordPress vengono tracciati nel tempo, così il report può mostrare trend (“LCP migliorato del 15% rispetto al mese scorso”).
Il codice completo: dalla raccolta dati al PDF
Ecco il flusso completo in un singolo script Python che usiamo come job schedulato:
import asyncio
import httpx
import anthropic
from weasyprint import HTML
from datetime import datetime, timedelta
async def collect_site_data(site_url: str, api_key: str) -> dict:
async with httpx.AsyncClient(timeout=30) as http:
response = await http.get(
f"{site_url}/wp-json/agencypilot/v1/maintenance-report",
headers={"X-AP-Key": api_key},
params={"period": "last_month"}
)
response.raise_for_status()
return response.json()
async def generate_all_reports(clients: list[dict]):
ai = anthropic.Anthropic()
for client in clients:
# Raccolta parallela dati da tutti i siti del cliente
tasks = [
collect_site_data(site['url'], site['api_key'])
for site in client['sites']
]
sites_data = await asyncio.gather(*tasks, return_exceptions=True)
# Filtra errori di connessione
valid_data = [d for d in sites_data if not isinstance(d, Exception)]
failed = [client['sites'][i]['url'] for i, d in enumerate(sites_data)
if isinstance(d, Exception)]
if failed:
print(f"⚠️ Raccolta fallita per: {', '.join(failed)}")
# Genera report con Claude
report_md = generate_report_with_claude(
ai, client['name'], valid_data
)
# Converti in PDF
pdf_bytes = report_to_pdf(report_md, client['branding'])
# Salva e notifica
report_path = save_report(pdf_bytes, client['id'])
await notify_client(client, report_path)
print(f"✅ Report generato per {client['name']}")
if __name__ == "__main__":
clients = load_clients_config()
asyncio.run(generate_all_reports(clients))
Lo script gira il primo giorno di ogni mese alle 6:00. In 15 minuti genera tutti i report. Il bottleneck non è Claude (12 secondi per report), ma la raccolta dati dai siti (alcuni hosting economici rispondono lentamente).
Costi reali e numeri di produzione
Dopo 6 mesi di utilizzo, ecco i numeri reali:
| Metrica | Prima (manuale) | Dopo (Claude API) |
|---|---|---|
| Tempo per report | 20-25 minuti | 2-3 minuti (revisione) |
| Tempo totale mensile | 8-10 ore | ~1 ora |
| Costo API Claude/mese | – | ~$2 |
| Costo hosting aggiuntivo | – | $0 (stesso VPS) |
| Soddisfazione clienti | “ok, grazie” | 3 feedback positivi spontanei |
| Errori nei report | 2-3 al mese | <1 al mese |
Il dato sugli errori è interessante. I report manuali avevano più errori perché dopo il quinto report consecutivo la concentrazione cala. Claude non si stanca.
Errori da evitare nell’integrazione Claude API
Abbiamo fatto tutti gli errori possibili, così non devi farli tu.
Non inviare HTML a Claude. La prima versione raccoglieva l’output di wp-admin e lo passava direttamente. Claude si confondeva con i tag HTML. Passa sempre dati strutturati (JSON pulito).
Non fidarti dei numeri generati da Claude. Se il dato non è nel prompt, Claude potrebbe inventarlo. Abbiamo aggiunto un post-processing che verifica che ogni numero nel report corrisponda a un numero nei dati di input.
Gestisci i rate limit. Con 25 report da generare, lanciare tutte le richieste in parallelo supera il rate limit. Usiamo un semaforo asyncio con max 3 richieste simultanee:
semaphore = asyncio.Semaphore(3)
async def generate_with_limit(ai, client_name, data):
async with semaphore:
return generate_report_with_claude(ai, client_name, data)
Testa il prompt con dati edge case. Un sito con zero aggiornamenti nel mese. Un sito con uptime del 100% (Claude scriveva “performance eccellente” senza aggiungere valore). Un sito nuovo con meno di 30 giorni di dati. Ogni caso limite ha richiesto aggiustamenti al prompt.
Prossimi passi: report interattivi e feedback loop
Il sistema attuale funziona bene, ma stiamo lavorando su due evoluzioni.
La prima: report interattivi nel portale clienti di AgencyPilot. Invece del PDF statico, una dashboard dove il cliente può cliccare su una metrica e vedere il dettaglio. Claude genererà le spiegazioni on-demand, solo quando il cliente le richiede.
La seconda: un feedback loop. Quando il revisore umano modifica il report generato da Claude, tracciamo le modifiche. Dopo 50+ modifiche tracciate, usiamo quei pattern per migliorare il prompt. Il report dovrebbe migliorare mese dopo mese senza intervento manuale sul prompt.
Se gestisci un’agenzia WordPress e perdi tempo sui report, il consiglio è semplice: parti con Claude API e un prompt base. Non serve un’architettura complessa dal giorno uno. Noi abbiamo iniziato con uno script Python di 80 righe. Il resto è cresciuto con le esigenze reali.
Se vuoi vedere come AgencyPilot integra tutto questo (monitoring, sicurezza, backup, report), dai un’occhiata alla guida completa alla gestione WordPress per agenzie.
FAQ
Claude API è affidabile per generare report in produzione?
Sì, con una precisazione: serve sempre una revisione umana. In 6 mesi non abbiamo mai avuto un’interruzione di servizio che bloccasse la generazione. L’uptime delle API Anthropic è stato superiore al 99.9% nel nostro monitoraggio.
Quanto costa integrare Claude API per i report automatici?
Il costo API è trascurabile: circa $0.08 per report con Claude Sonnet. Il costo vero è nello sviluppo iniziale. Con le competenze giuste (Python, REST API WordPress), un’integrazione base richiede 2-3 giorni di sviluppo.
I clienti si accorgono che il report è generato da AI?
Finora nessuno. Tre clienti hanno commentato positivamente la qualità migliorata. Il segreto: dati specifici nel prompt. Quando Claude scrive “aggiornato WooCommerce da 8.4.0 a 8.5.1” invece di “aggiornati i plugin”, il report suona umano perché è specifico.
Posso usare GPT-4 invece di Claude per i report?
Puoi usare qualsiasi LLM. Abbiamo testato GPT-4, Claude Sonnet e Claude Opus. Sonnet offre il miglior rapporto qualità/prezzo per questo caso d’uso. GPT-4 tende a produrre report più verbosi senza aggiungere valore informativo.
Serve un server dedicato per il sistema di report?
No. Lo script gira sullo stesso VPS Debian che ospita il backend AgencyPilot. Requisiti: Python 3.11+, weasyprint per i PDF, e le librerie anthropic e httpx. Consumo risorse durante la generazione: trascurabile.