![]()
Come ho costruito il mio assistente AI locale per lo sviluppo di plugin WordPress (guida pratica)
20 minuti di lettura
📋 Indice
- Introduzione
- Perché un’assistente AI locale?
- L’architettura del sistema
- Step 1: Installazione e configurazione di LM Studio
- Step 2: Integrazione con VS Code (Continue)
- Step 3: Il mio form PHP personalizzato con Laragon
- Step 4: Specializzazione WordPress
- Step 5: Test e risultati
- Considerazioni sui costi e privacy
- Conclusioni
1️⃣ Introduzione
Come sviluppatore WordPress, mi sono sempre trovato di fronte a un dilemma: da un lato gli assistenti AI come ChatGPT sono incredibilmente utili, dall’altro non mi sentivo a mio agio a condividere codice proprietario di plugin e clienti su server di terze parti.
La soluzione? Costruire un assistente AI completamente locale, che girasse sul mio PC, specializzato in WordPress e perfettamente integrato nel mio flusso di lavoro.
In questo post ti mostro passo-passo come ho fatto, con tanto di screenshot e codice che puoi copiare e adattare.
*Figura 1: Il risultato finale – tre modalità di interazione con la stessa AI locale*


2️⃣Perché un’assistente AI locale?
Prima di entrare nel tecnico, vale la pena chiedersi: perché tutto questo sforzo quando esistono decine di servizi cloud?
| Caratteristica | Cloud (ChatGPT, Claude) | Locale (LM Studio) |
|---|---|---|
| Privacy | ❌ I tuoi dati vanno ai server | ✅ Tutto rimane sul tuo PC |
| Costo | 💰 Canone mensile o a consumo | ✅ Una tantum (hardware) |
| Offline | ❌ Necessaria connessione | ✅ Funziona ovunque |
| Personalizzazione | Limitata | ✅ Totale (system prompt) |
| Vendor lock-in | ❌ Dipendi da terzi | ✅ Sei tu il padrone |
*Figura 2: Architettura cloud vs architettura locale – i dati non lasciano mai il tuo computer

3️⃣ L’architettura del sistema
Il sistema che ho realizzato è composto da 4 elementi chiave che comunicano tra loro:
┌─────────────────────────────────────────────────────────────┐
│ │
│ VS CODE (Continue) FORM PERSONALIZZATA │
│ (Assistente nell'editor) (Interfaccia web PHP) │
│ │ │ │
│ └──────────┬───────────────┘ │ │
│ ↓ │ │
│ LM STUDIO (DeepSeek) │ │
│ (Il "cervello" sulla 1234) │ │
│ ↑ │ │
│ │ │ │
│ LARAGON (PHP Server) ─────────┘ │
│ (Solo per la form web) |
└─────────────────────────────────────────────────────────────┘
Il bello è che il modello è uno solo (DeepSeek-Coder-V2-Lite-Instruct), ma può essere chiamato da diverse interfacce a seconda delle esigenze del momento.
4️⃣ Step 1: Installazione e configurazione di LM Studio
4.1 Il primo passo è stato scaricare LM Studio dal sito ufficiale. L’installazione è semplicissima su Windows (su macOS e Linux funziona altrettanto bene).
4.2 Scelta del modello
Ho scelto DeepSeek-Coder-V2-Lite-Instruct per diversi motivi:
- Specializzato in codice (perfetto per plugin WordPress)
- Leggero abbastanza per girare su PC normale (~4-5GB di RAM)
- Supporto contesto 4K token (sufficiente per la maggior parte delle richieste)
- Gratuito e open source
4.3 Avvio del server
La parte fondamentale: una volta caricato il modello, ho attivato il server locale dalla scheda Developer:
L’endpoint da ricordare è: http://localhost:1234/v1/chat/completions (API compatibile OpenAI).
4.4 Test rapido dal browser
Per verificare che tutto funzioni, ho aperto:
http://localhost:1234/api/v1/models
5️⃣ Step 2: Integrazione con VS Code (Continue)
5.1 Installazione dell’estensione
In VS Code ho cercato e installato l’estensione Continue.
*Figura 7: L’estensione Continue – il ponte tra VS Code e LM Studio*

5.2 Configurazione del file config.yaml
La magia avviene nel file di configurazione. Ecco il mio config.yaml:
name: Local Config
version: 1.0.0
schema: v1
models:
- name: DeepSeek WP Expert
provider: lmstudio
model: deepseek-coder-v2-lite-instruct
apiBase: http://localhost:1234/v1
systemMessage: |
Sei un esperto sviluppatore WordPress con 10+ anni di esperienza.
Quando scrivi codice PHP per WordPress:
- Usa sempre if (!defined('ABSPATH')) come prima riga
- Implementa nonce per form security
- Segui le WordPress Coding Standards
- Preferisci funzioni WordPress a PHP nudo
- Usa escaping appropriato (esc_html, esc_attr)
Figura 8: La configurazione che specializza DeepSeek per WordPress

5.3 Prime interazioni
Una volta configurato, ho selezionato il modello “DeepSeek WP Expert” dal menu a tendina di Continue e ho iniziato a testarlo.
Il test chiave: ho chiesto “Crea un plugin WordPress base” e ho subito visto il codice iniziare con if ( ! defined( 'ABSPATH' ) ). Segno che il system prompt funziona! 👍
6️⃣ Step 3: Il mio form PHP personalizzato con Laragon
Questa è la parte che preferisco: un’interfaccia web costruita su misura per le mie esigenze, ospitata localmente con Laragon.
6.1 Perché Laragon?
Uso Laragon per lo sviluppo WordPress locale, quindi ho pensato: “Perché non usarlo anche per questo?”. L’idea è semplice:
- Laragon serve pagine PHP sulla porta 80 (
http://localhost) - Il mio script PHP chiama LM Studio sulla porta 1234
- Nessun problema CORS (le chiamate sono server-to-server)
6.2 Lo script completo
Ecco il codice che ho inserito in C:\laragon\www\lm-chat\chat-ai.php:
<?php
// chat-ai.php - Il mio client personalizzato per LM Studio
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: POST, GET, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit();
}
// Configurazione
$lmStudioUrl = 'http://127.0.0.1:1234/v1/chat/completions';
$modelName = 'deepseek-coder-v2-lite-instruct';
// System prompt per WordPress
$wordpressPrompt = "Sei un esperto sviluppatore WordPress...";
// System prompt per PHP puro
$phpPrompt = "Sei un esperto sviluppatore PHP (puro, senza framework)...";
function callLMStudio($message, $mode) {
global $lmStudioUrl, $modelName, $wordpressPrompt, $phpPrompt;
$systemPrompt = ($mode === 'wordpress') ? $wordpressPrompt : $phpPrompt;
$data = [
'model' => $modelName,
'messages' => [
['role' => 'system', 'content' => $systemPrompt],
['role' => 'user', 'content' => $message]
],
'temperature' => 0.5,
'max_tokens' => 2000
];
$ch = curl_init($lmStudioUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$result = json_decode($response, true);
return $result['choices'][0]['message']['content'] ?? 'Errore';
} else {
return "Errore HTTP $httpCode";
}
}
// Gestione richiesta AJAX
if (isset($_GET['ajax']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
$userMessage = $_POST['message'] ?? '';
$mode = $_POST['mode'] ?? 'wordpress';
$aiResponse = callLMStudio($userMessage, $mode);
// Pulisce i backtick markdown
$aiResponse = preg_replace('/```(php|html|javascript)?\s*/', '', $aiResponse);
$aiResponse = str_replace('```', '', $aiResponse);
echo json_encode(['response' => trim($aiResponse)]);
exit();
}
// Gestione richiesta normale
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !isset($_GET['ajax'])) {
$userMessage = $_POST['message'] ?? '';
$mode = $_POST['mode'] ?? 'wordpress';
$aiResponse = callLMStudio($userMessage, $mode);
$aiResponse = preg_replace('/```(php|html|javascript)?\s*/', '', $aiResponse);
$aiResponse = str_replace('```', '', $aiResponse);
}
?>
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Locale per WordPress</title>
<style>
body { font-family: 'Segoe UI', sans-serif; max-width: 900px; margin: 0 auto; padding: 20px; background: #f9f9f9; }
h1 { color: #23282d; border-bottom: 3px solid #0073aa; padding-bottom: 10px; }
textarea { width: 100%; height: 120px; padding: 15px; border: 1px solid #ddd; border-radius: 4px; font-family: monospace; }
select, button { padding: 10px 15px; margin: 10px 0; border-radius: 4px; }
button { background: #0073aa; color: white; border: none; cursor: pointer; }
button:hover { background: #005a87; }
.response { margin-top: 20px; background: white; border-left: 4px solid #46b450; padding: 15px; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.response pre { background: #f1f1f1; padding: 15px; border-radius: 4px; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word; font-family: 'Consolas', monospace; }
.mode-selector { margin: 15px 0; background: #fff; padding: 15px; border-radius: 4px; border: 1px solid #e5e5e5; }
.loading { display: none; margin-left: 10px; color: #666; }
</style>
</head>
<body>
<h1>🤖 Assistente WordPress Locale</h1>
<div class="mode-selector">
<strong>Modalità:</strong>
<select name="mode" id="mode">
<option value="wordpress" selected>WordPress Expert</option>
<option value="pure-php">PHP Puro</option>
</select>
<span style="margin-left: 20px; color: #666;">(Il modello gira localmente - zero dati in cloud!)</span>
</div>
<form method="POST" id="chatForm">
<textarea name="message" placeholder="Chiedimi qualcosa su WordPress o PHP..."><?php echo htmlspecialchars($_POST['message'] ?? '') ?></textarea>
<button type="submit">Invia</button>
<span class="loading" id="loading">Elaborazione in corso...</span>
</form>
<?php if (isset($aiResponse)): ?>
<div class="response">
<strong>Risposta:</strong>
<pre><?php echo htmlspecialchars($aiResponse) ?></pre>
</div>
<?php endif; ?>
<script>
document.getElementById('chatForm').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
formData.append('mode', document.getElementById('mode').value);
const loading = document.getElementById('loading');
loading.style.display = 'inline';
try {
const response = await fetch('?ajax=1', {
method: 'POST',
body: formData
});
const data = await response.json();
let responseDiv = document.querySelector('.response');
if (!responseDiv) {
responseDiv = document.createElement('div');
responseDiv.className = 'response';
document.body.appendChild(responseDiv);
}
responseDiv.innerHTML = `<strong>Risposta:</strong><pre>${data.response}</pre>`;
} catch (error) {
alert('Errore: ' + error.message);
} finally {
loading.style.display = 'none';
}
});
</script>
</body>
</html>
Figura 10: La mia interfaccia personalizzata – WordPress o PHP puro con un click

6.3 La magia della pulizia delle risposte
Un dettaglio che ho scoperto: i modelli tendono a rispondere con blocchi di codice delimitati da “`, che nel tag <pre> vengono visualizzati letteralmente. Ho risolto con due semplici righe:
$aiResponse = preg_replace('/```(php|html|javascript)?\s*/', '', $aiResponse);
$aiResponse = str_replace('```', '', $aiResponse);
7️⃣ Step 4: Specializzazione WordPress
7.1 Il system prompt che fa la differenza
Il vero segreto per avere un assistente specializzato in WordPress è il system prompt. Ecco quello che uso:
Sei un esperto sviluppatore WordPress con 10+ anni di esperienza.
Hai conoscenza approfondita di:
- WordPress Coding Standards (WPCS)
- Plugin development best practices
- Hooks (action e filter)
- REST API di WordPress
- Security best practices (nonce, capability checks)
Quando scrivi codice PHP per WordPress:
- Usa sempre if (!defined('ABSPATH')) come prima riga
- Implementa nonce per form security
- Segui le convenzioni di nomenclatura WordPress
- Preferisci funzioni WordPress a PHP nudo quando possibile
- Includi commenti PHPDoc
- Usa escaping appropriato (esc_html, esc_attr, wp_kses)
7.2 I risultati
Con questo prompt, il modello inizia automaticamente ogni plugin con:
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Impedisce accesso diretto
}
8️⃣ Step 5: Test e risultati
8.1 Velocità di risposta
Ho fatto dei test comparativi:
| Richiesta | Tempo LM Studio (chat) | Tempo VS Code (Continue) |
|---|---|---|
| Funzione PHP semplice | 3-4 secondi | 5-6 secondi |
| Plugin WordPress completo | 8-10 secondi | 12-15 secondi |
8.2 Qualità del codice
La qualità del codice generato è sorprendentemente alta:
- ✅ Rispetta gli standard WordPress
- ✅ Include controlli di sicurezza
- ✅ Commenti PHPDoc completi
- ✅ Codice pronto all’uso
8.3 Scenari
| Scenario | Strumento | Perché |
|---|---|---|
| Debug rapido nel codice | Continue (Ctrl+L) | Contestuale al file aperto |
| Generare plugin interi | Form PHP personalizzata | Interfaccia pulita, cronologia |
| Test veloci | LM Studio Chat | Massima velocità |
9️⃣ Considerazioni sui costi e privacy
9.1 Costi hardware
L’investimento iniziale:
- PC con 32GB RAM (già in mio possesso)
- DeepSeek-Coder (gratuito)
- LM Studio (gratuito)
- VS Code + Continue (gratuiti)
Costo totale: 0€ (oltre all’hardware già posseduto)
9.2 Confronto con soluzioni cloud
| Voce | ChatGPT Plus | GitHub Copilot | Locale (questo) |
|---|---|---|---|
| Canone mensile | 20€/mese | 10€/mese | 0€ |
| Privacy dati | ❌ Su server OpenAI | ❌ Su server Microsoft | ✅ Sul tuo PC |
| Limiti richieste | ✅ 40 messaggi/3h | ✅ Illimitato? | ✅ Illimitato |
| Offline | ❌ No | ❌ No | ✅ Sì |
9.3 Il vantaggio principale
“I miei plugin proprietari, il codice dei clienti, le logiche di business – tutto rimane sul mio PC. Nessuna NDA violata, nessun dubbio su chi vede cosa.“
🔟 Conclusioni
10.1 Cosa ho imparato
Costruire questo sistema mi ha insegnato che:
- L’AI locale è matura – modelli come DeepSeek sono competitivi con i servizi cloud
- La personalizzazione è tutto – con un buon system prompt, l’AI diventa uno specialista del tuo dominio
- L’integrazione è semplice – API standard (OpenAI-compatible) rendono tutto facile
10.2 Prossimi passi
Ora che ho questa base, voglio:
- Aggiungere un database per salvare la cronologia delle chat
- Implementare RAG con la documentazione WordPress
- Provare modelli più grandi (quando aggiornerò il PC)
- Creare un plugin WordPress che usi questa API locale
10.3 Consigli per chi vuole provare
Se vuoi replicare questo setup:
- Inizia con LM Studio e un modello piccolo
- Prova Continue in VS Code (è immediato)
- Costruisci la tua interfaccia solo se ti serve
- Sperimenta con i system prompt – è lì che sta la magia
📚 Risorse utili
💬 Commenti e domande
Hai provato a configurare un assistente AI locale? Hai domande su qualche passaggio? Lascia un commento qui sotto o contattami direttamente!
📖 Letto da: 24








