AI Assistant - Executive Summary
AI Assistant - Executive Summary
Data: 22 Ottobre 2025 Destinatario: Nicola Scapaticci Oggetto: Chiarimento Architettura AI Assistant Contestualizzato
---
🎯 La Tua Richiesta (Chiarita)
Cosa Vuoi Ottenere
1. AI Assistant Contestualizzato: Non un assistente generico, ma specializzato per ambiti specifici del tuo sistema i40 2. Addestramento Profondo: Preparare una Knowledge Base dettagliata per ridurre i costi e aumentare la precisione 3. Risposte Deterministiche: Limitare la "creatività" dell'AI, preferendo risposte basate su dati storici preparati 4. Interpretazione Strutturata: Capire l'intent dell'utente senza chiamare sempre l'LLM 5. Risposte Ibride: Storico preparato (80%) + AI generativa (20%) solo quando necessario
Le Tue Preoccupazioni (Valide!)
✅ Costi API: Con approccio standard (sempre LLM), costi imprevedibili e alti ✅ Allucinazioni AI: Risposte inventate o imprecise ✅ Libertà eccessiva AI: Vuoi controllo su cosa può/non può dire ✅ Manutenzione: Modificare prompt è più difficile che modificare template JSON
---
📊 Sistema Attuale (Analisi)
Cosa Hai Già Implementato
``
3 Macchine i40
↓
Profili Import Configurabili (schema CSV dinamico)
↓
MachineOperationLog (raw_data JSON con campi variabili)
↓
Analyze View (filtri, KPI, grafici)
`
Caratteristiche Chiave
- Schema Dati Dinamico: Ogni macchina può avere campi diversi in raw_data
- Profili con Metadati: Campi hanno is_filterable
,is_aggregatable,column_namesmnemonici - Operations Log: Storico completo operazioni macchina con timestamp
- CSV Imports: Pipeline validazione → processamento → archiviazione
- Vocabolario specifico (parole chiave ricorrenti)
- Intent patterns (tipi di domande simili)
- Logica di business (calcoli/confronti tipici)
- Formato risposta (template standard)
- ✅ Rilevamento intent senza LLM (pattern matching regex)
- ✅ Template risposte deterministiche
- ✅ Costi ridotti (LLM solo quando necessario)
- "Qual è stata la produzione di ieri?"
- "Quanti pezzi abbiamo fatto oggi?"
- "Totale operazioni questa settimana"
- "Mostrami il trend mensile"
- Periodo temporale (ieri, oggi, questa settimana, questo mese)
- Metrica (pezzi, operazioni, lavorazioni)
- Filtri opzionali (operatore, materiale)
- "Perché la macchina si è fermata?"
- "Ci sono stati errori oggi?"
- "Qual è il problema?"
- "Perché ieri abbiamo prodotto meno?"
- Periodo temporale
- Tipo problema (fermo, errore, performance)
- Macchina specifica
- {causa_1}
- {causa_2}
- Operazioni: {total_ops} (atteso: {expected_ops})
- Durata media: {avg_duration}h (atteso: {expected_duration}h) `
- "Chi è l'operatore più produttivo?"
- "Performance di Mario Rossi"
- "Confronta operatori"
- "Ranking operatori del mese"
- Nome operatore
- Periodo temporale
- Metrica di confronto (pezzi, velocità, qualità)
- "Riusciremo a finire 5000 pezzi entro venerdì?"
- "Quanto ci vuole per produrre 3000 pezzi?"
- "Quando finiremo l'ordine X?"
- Quantità target
- Deadline (data)
- Macchina
- Media giornaliera: {avg_daily} pezzi/giorno
- Giorni necessari: {days_needed} giorni lavorativi
- Deadline: {deadline_date}
- Giorni disponibili: {days_available}
- "Confronta questa settimana con la scorsa"
- "Oggi vs ieri"
- "Differenza tra macchina A e B"
- "Trend ultimi 7 giorni"
- Periodo 1 (es. "questa settimana")
- Periodo 2 (es. "scorsa settimana")
- Metrica (produzione, durata, operazioni)
- Entità confrontate (macchine, operatori, periodi)
- {periodo_1}: {value_1} {unit}
- {periodo_2}: {value_2} {unit}
- "Quali profili ha la macchina?"
- "Configurazione attuale"
- "Campi disponibili"
- "Ultimo import CSV"
- File: {filename}
- Data: {import_date}
- Righe: {rows_processed}/{rows_total}
- Status: {status_badge}
- "Come posso migliorare la produttività?"
- "Suggerimenti di ottimizzazione"
- "Dove posso migliorare?"
- "Quali sono i colli di bottiglia?"
- Produttività media: {current_productivity}
- OEE: {oee_percent}%
- Downtime: {downtime_hours}h/giorno
- ❌ Ambito non rilevato (confidence < 0.7)
- ❌ Query ambigua/complessa
- ❌ Richiesta ottimizzazione/suggerimenti
- ❌ Template non disponibile
- Input: 200 tokens × $0.15 / 1M = $0.00003
- Output: 150 tokens × $0.60 / 1M = $0.00009
- Totale: ~$0.00012 per query
- Normalizza: "qual e stata la produzione di ieri"
- Match pattern: /produz(?:ione) di (ieri|oggi)/i
- Ambito rilevato: AMBITO_PRODUZIONE
- Confidence: 1.0
- Entities: { periodo: 'ieri', metrica: 'produzione' }
- Periodo: 'ieri' → date_from: 2025-10-21 00:00, date_to: 2025-10-21 23:59
- Metrica: 'produzione' → campo_raw_data: 'TotalPieces'
- Query hash: md5("produzione_ieri_machine_5_2025-10-21")
- Cache hit? NO (prima volta oggi)
- Template trovato: "prod_daily"
- Requires LLM: false
- Carica media ultimi 30 giorni: 1750 pezzi
- Calcola delta: +100 pezzi (+5.7%)
- Emoji trend: 📈
- "Confronta con l'altro ieri"
- "Mostrami il trend settimanale"
- "Chi ha prodotto di più ieri?"
- Salva risposta con TTL 1 ora
- Prossima richiesta identica → risposta istantanea da cache
- User message + Assistant response → DB
- Metadata: { ambito, template_id, execution_time_ms, used_llm: false }
- Ambito: AMBITO_OTTIMIZZAZIONE
- Confidence: 0.9
- Template: "optimization_suggestions"
- Requires LLM: true (per suggerimenti articolati)
- Analizza distribuzione oraria → Picco: 9-11am (+18%)
- Analizza operatori → Best: "Mario Rossi" (+25%)
- Analizza downtime → Media: 45 min/giorno
- Database: 30-40 template JSON in ai_knowledge_templates
- Ogni template = pattern + SQL + response_template + enrichment_rules
- Risposte completamente deterministiche
- Arricchite con contesto (medie, confronti, trend)
- Solo quando template non disponibile
- Prompt minimale (no schema completo)
- Context injection selettivo (dati pre-calcolati)
- Temperature bassa (0.2-0.3) per risposte coerenti
- ✅ 80%+ query gestite senza LLM
- ✅ Latency media < 1s
- ✅ Cache hit rate > 40%
- ✅ Costi < $5/mese (50 utenti)
- ✅ Satisfaction rate > 85%
- ✅ 60%+ utenti usano AI settimanalmente
- ✅ 50%+ domande risolte autonomamente
- ✅ Zero allucinazioni
- ✅ Risposte sempre verificabili
- ✅ Feedback negativo < 10%
- Pattern matching → Ambiti contestuali
- Template JSON → Knowledge Base preparata
- LLM fallback → AI solo quando serve
- Response templates → Risposte deterministiche
- Caching → Costi ottimizzati
---
🗂️ Ambiti Contestuali (Proposta Finale)
Perché Dividere per Ambiti?
Ogni ambito ha:
Dividere per ambiti permette:
---
Ambito 1: PRODUZIONE 📊
Dominio: Quantità prodotte, pezzi lavorati, conteggi operazioni
Query Tipiche:
Entità da Estrarre:
Dati Necessari:
`sql
-- Campi in raw_data (dipende dal profilo macchina)
TotalPieces, NumberOfPlies, Quantity, etc.
-- Query tipo
SELECT SUM(CAST(JSON_UNQUOTE(JSON_EXTRACT(raw_data, '$.TotalPieces')) AS DECIMAL))
FROM machine_operations_log
WHERE machine_id = :machine_id
AND timestamp BETWEEN :date_from AND :date_to
`
Risposta Template:
`
📊 Produzione di {periodo}:
✅ Totale pezzi: {total_quantity} 📈 Operazioni: {total_operations} ⏱️ Durata media: {avg_duration}h
Rispetto alla media degli ultimi 30 giorni ({avg_30d} pezzi),
sei {delta_percent}% {emoji_trend}.
`
Richiede LLM?: ❌ No (risposta completamente deterministica)
---
Ambito 2: DIAGNOSTICA 🔧
Dominio: Errori, fermi macchina, anomalie, performance scadenti
Query Tipiche:
Entità da Estrarre:
Logica Diagnostica (Decision Tree):
`
1. Verifica gaps timestamp > 30 min
→ "Fermo macchina rilevato dalle {start_time} alle {end_time}"
2. Verifica campi ErrorCode/AlarmCode in raw_data → "Errore registrato: {error_code} - {error_description}"
3. Verifica produzione < media - 20% → "Produzione sotto media del {delta}%" 4. Verifica Duration > avg + 2σ → "Operazioni più lente del solito (+{percent}%)"
5. Confronta con stesso giorno settimana scorsa
→ "Rispetto a {last_week_same_day}, produzione {comparison}"
`
Risposta Template:
`
🔍 Analisi {periodo}:
⚠️ Problemi identificati: 1. {problema_1} 2. {problema_2} ...
💡 Cause probabili:
📊 Dati a supporto:
Richiede LLM?: ⚠️ Parziale (solo per interpretare ErrorCode sconosciuti o suggerire cause)
---
Ambito 3: OPERATORI 👥
Dominio: Performance operatori, confronti, ranking
Query Tipiche:
Entità da Estrarre:
Dati Necessari:
`sql
SELECT
JSON_UNQUOTE(JSON_EXTRACT(raw_data, '$.UserLog')) as operator,
COUNT(*) as operations,
SUM(CAST(JSON_UNQUOTE(JSON_EXTRACT(raw_data, '$.TotalPieces')) AS DECIMAL)) as total_pieces,
AVG(CAST(JSON_UNQUOTE(JSON_EXTRACT(raw_data, '$.Duration')) AS DECIMAL)) as avg_duration
FROM machine_operations_log
WHERE machine_id = :machine_id
AND timestamp BETWEEN :date_from AND :date_to
GROUP BY operator
ORDER BY total_pieces DESC
`Risposta Template:
`
👥 Ranking Operatori ({periodo}):🥇 1. {operator_1} - {pieces_1} pezzi ({ops_1} operazioni)
🥈 2. {operator_2} - {pieces_2} pezzi ({ops_2} operazioni)
🥉 3. {operator_3} - {pieces_3} pezzi ({ops_3} operazioni)
⚡ Insight:
{operator_1} è il più veloce con {pieces_per_hour} pezzi/ora
(+{percent}% rispetto alla media di {avg_pieces_per_hour}).
`Richiede LLM?: ❌ No
---
Ambito 4: PIANIFICAZIONE 📅
Dominio: Previsioni, deadline, capacità produttiva
Query Tipiche:
Entità da Estrarre:
Logica Predittiva:
`
1. Calcola produzione_media_giornaliera (ultimi 30 giorni)
2. Calcola pezzi_già_prodotti (se order in corso)
3. Calcola pezzi_rimanenti = target - già_prodotti
4. Calcola giorni_lavorativi_rimanenti (escludi weekend)
5. Proiezione:
giorni_necessari = pezzi_rimanenti / produzione_media_giornaliera
6. Confronto:
margin = giorni_lavorativi_rimanenti - giorni_necessari
`Risposta Template:
`
📅 Previsione Completamento:🎯 Target: {target_quantity} pezzi
✅ Già prodotti: {already_produced} pezzi
⏳ Rimanenti: {remaining} pezzi
📊 Proiezione:
{verdict_emoji} {verdict_message}
💡 Scenario worst-case (-20% produzione):
Servirebbero {worst_case_days} giorni → {worst_case_deadline}
`Richiede LLM?: ❌ No (logica completamente deterministica)
---
Ambito 5: COMPARAZIONE ⚖️
Dominio: Confronti temporali, confronti macchine, delta
Query Tipiche:
Entità da Estrarre:
Logica Comparazione:
`
1. Query periodo 1
2. Query periodo 2
3. Calcola delta assoluto = valore1 - valore2
4. Calcola delta percentuale = (delta / valore2) * 100
5. Determina trend:
- Positivo (+): emoji 📈
- Negativo (-): emoji 📉
- Stabile (±3%): emoji ➡️
`Risposta Template:
`
⚖️ Confronto {periodo_1} vs {periodo_2}:📊 {metrica_label}:
📈 Variazione: {delta_abs} {unit} ({delta_percent}% {emoji_trend})
{insight_message}
`Richiede LLM?: ❌ No
---
Ambito 6: CONFIGURAZIONE ⚙️
Dominio: Info macchine, profili, setup, metadati
Query Tipiche:
Dati Necessari:
`sql
-- Tabelle metadata
machines_i40.profiles_config
import_profiles.columns, column_names
csv_imports (status, arrived_at)
`Risposta Template:
`
⚙️ Configurazione {machine_name}:📋 Profili Attivi:
1. {profile_1_name}
- Campi: {fields_count}
- Ultimo import: {last_import_date}
2. {profile_2_name}
- Campi: {fields_count}
- Ultimo import: {last_import_date}
📊 Campi Disponibili (Profilo {active_profile}):
{field_1}, {field_2}, {field_3}, ...
📁 Ultimo Import CSV:
`Richiede LLM?: ❌ No
---
Ambito 7: OTTIMIZZAZIONE 🚀
Dominio: Suggerimenti, best practices, insights, miglioramenti
Query Tipiche:
Logica Insight Engine:
`
1. Analizza distribuzione temporale (orari/giorni più produttivi)
2. Confronta operatori (best practices da replicare)
3. Identifica anomalie ricorrenti (pattern errori)
4. Calcola OEE (Overall Equipment Effectiveness)
5. Identifica downtime patterns
6. Confronta con benchmark aziendali
`Insight Rules:
`
IF orario_picco_produzione EXISTS THEN
→ "Le operazioni tra {start_hour}:{end_hour} sono {percent}% più veloci"
→ Suggerimento: "Concentra lavorazioni complesse in questa fascia"IF operatore_best_performer EXISTS THEN
→ "L'operatore {name} ha resa {percent}% superiore alla media"
→ Suggerimento: "Organizza training con {name} per condividere best practices"
IF downtime_medio > threshold THEN
→ "Fermi macchina: {downtime_hours}h/giorno in media"
→ Cause: {top_3_causes}
→ Suggerimento: "Implementa pre-staging materiali"
`Risposta Template:
`
🚀 Analisi Ottimizzazione ({periodo}):📊 Situazione Attuale:
💡 Opportunità Identificate:
1. {opportunity_1_title} (Impatto: +{impact_1}%)
{description_1}
✅ Azione: {action_1}
2. {opportunity_2_title} (Impatto: +{impact_2}%)
{description_2}
✅ Azione: {action_2}
3. {opportunity_3_title} (Impatto: +{impact_3}%)
{description_3}
✅ Azione: {action_3}
📈 Potenziale Totale: +{total_impact}%
`Richiede LLM?: ⚠️ Sì (per formulare suggerimenti articolati e insights)
---
🧠 Interpretazione Query - Architettura
Livello 1: Pattern Matching (Deterministico - 0 costi)
Obiettivo: Identificare ambito senza chiamare LLM
Metodo: Regex patterns su query normalizzata
`php
// Input
$userQuery = "Qual è stata la produzione di ieri?";// Normalization
$normalized = normalize($userQuery);
// → "qual e stata la produzione di ieri"
// Pattern Matching
foreach ($patterns['AMBITO_PRODUZIONE'] as $regex) {
if (preg_match($regex, $normalized, $matches)) {
return [
'ambito' => 'AMBITO_PRODUZIONE',
'confidence' => 1.0, // Deterministico
'entities' => extractEntities($matches),
// entities: ['periodo' => 'ieri', 'metrica' => 'produzione']
];
}
}
`Coverage Atteso: 70-80% delle query
---
Livello 2: Entity Extraction (Deterministico - 0 costi)
Obiettivo: Estrarre parametri dalla query
Metodo: Regex + Lookup Tables
`php
// Estrazione periodo temporale
$periodMap = [
'ieri' => [
'date_from' => now()->subDay()->startOfDay(),
'date_to' => now()->subDay()->endOfDay(),
'label' => 'Ieri',
],
'oggi' => [
'date_from' => now()->startOfDay(),
'date_to' => now()->endOfDay(),
'label' => 'Oggi',
],
'questa settimana' => [
'date_from' => now()->startOfWeek(),
'date_to' => now()->endOfWeek(),
'label' => 'Questa Settimana',
],
// ... altri 20-30 periodi
];// Estrazione nomi operatori (fuzzy matching)
$operatorNames = getOperatorNamesFromDB($machineId);
$matchedOperator = findClosestMatch($userQuery, $operatorNames);
// Estrazione numeri
preg_match_all('/\d+/', $userQuery, $numbers);
// "5000 pezzi entro venerdì" → entities['quantity'] = 5000
`---
Livello 3: Template Lookup (Deterministico - 0 costi)
Obiettivo: Trovare template pre-costruito
Metodo: Database lookup con pattern matching
`php
// Query database template
$template = DB::table('ai_knowledge_templates')
->where('ambito', $detectedAmbito)
->whereRaw('? REGEXP pattern', [$userQuery])
->first();if ($template) {
// Template trovato → Esegui senza LLM
return executeTemplate($template, $entities, $machineId);
}
`Template Structure (JSON in DB):
`json
{
"template_id": "prod_daily",
"pattern": "produzione di (ieri|oggi)",
"sql_query": {
"query": "SELECT SUM(...) FROM ...",
"parameters": {
"machine_id": ":machine_id",
"date_from": ":date_from",
"date_to": ":date_to"
}
},
"response_template": "Produzione di {periodo}: {total} pezzi.",
"enrichment": {
"add_comparison": true,
"compare_with": "avg_last_30_days"
}
}
`---
Livello 4: LLM Fallback (Costoso - solo se necessario)
Quando Usare LLM:
Come Minimizzare Costi:
`php
// Prompt MINIMO (no schema completo)
$systemPrompt = "Sei assistente produzione. Macchina: {$machine->name}. Rispondi in italiano, max 3 frasi.";// Context injection selettivo (solo dati necessari)
$context = [
'avg_production_last_30d' => 1500, // Pre-calcolato
'last_operation_timestamp' => '2025-10-22 10:30',
'total_operations_today' => 12,
];
// Chiamata LLM con limite tokens
$response = OpenAI::chat()->create([
'model' => 'gpt-4o-mini', // Modello più economico
'messages' => [
['role' => 'system', 'content' => $systemPrompt],
['role' => 'user', 'content' => $userQuery],
],
'temperature' => 0.2, // Basso = più deterministico
'max_tokens' => 300, // Limita risposta
]);
`Costo per Query LLM:
---
🔄 Flusso Completo - Esempio Pratico
Scenario: Utente chiede "Produzione di ieri"
`
USER INPUT:
"Qual è stata la produzione di ieri?"↓
STEP 1: Intent Router (Pattern Matching)
↓
STEP 2: Entity Extraction
↓
STEP 3: Cache Lookup
↓
STEP 4: Template Lookup
↓
STEP 5: SQL Execution
`sql
SELECT
SUM(CAST(JSON_UNQUOTE(JSON_EXTRACT(raw_data, '$.TotalPieces')) AS DECIMAL)) as total_quantity,
COUNT(*) as total_operations,
AVG(CAST(JSON_UNQUOTE(JSON_EXTRACT(raw_data, '$.Duration')) AS DECIMAL)) as avg_duration
FROM machine_operations_log
WHERE machine_id = 5
AND timestamp BETWEEN '2025-10-21 00:00:00' AND '2025-10-21 23:59:59'
`
Result: { total_quantity: 1850, total_operations: 23, avg_duration: 2.3 }↓
STEP 6: Context Enrichment
↓
STEP 7: Response Formatting
`
📊 Produzione di Ieri:✅ Totale pezzi: 1.850
📈 Operazioni: 23
⏱️ Durata media: 2.3h
Rispetto alla media degli ultimi 30 giorni (1.750 pezzi),
sei +5.7% 📈. Ottimo lavoro!
`↓
STEP 8: Follow-up Suggestions
↓
STEP 9: Save to Cache
↓
STEP 10: Save to Conversation History
↓
TOTAL TIME: ~200ms
TOTAL COST: $0 (no LLM)
`---
Scenario: Utente chiede "Come posso migliorare?"
`
USER INPUT:
"Come posso migliorare la produttività?"↓
STEP 1: Intent Router
↓
STEP 2: Template Lookup
↓
STEP 3: Data Analysis (pre-LLM)
↓
STEP 4: LLM Call (con dati pre-elaborati)
`php
$context = [
'peak_hours' => '9-11am (+18%)',
'best_operator' => 'Mario Rossi (+25%)',
'avg_downtime' => '45 min/day',
'avg_production' => 1750,
];$prompt = "Basandoti su questi dati analitici, suggerisci 3 azioni concrete per migliorare produttività:\n"
. json_encode($context);
`↓
STEP 5: LLM Response
`
🚀 Suggerimenti Ottimizzazione:1. Sfrutta le ore di picco (Impatto: +15%)
Le operazioni tra 9-11am sono 18% più veloci.
✅ Azione: Pianifica lavorazioni critiche in questa fascia.
2. Training con Mario Rossi (Impatto: +20%)
Mario ha resa 25% superiore alla media.
✅ Azione: Organizza sessione formativa per condividere best practices.
3. Riduzione downtime (Impatto: +8%)
45 minuti/giorno di fermi non pianificati.
✅ Azione: Pre-staging materiali e checklist pre-operazione.
📈 Potenziale: +43% produttività
`↓
TOTAL TIME: ~3s
TOTAL COST: ~$0.00012 (LLM usato)
`---
💡 Riepilogo: Risposta alla Tua Domanda
"Come Organizzare Interpretazione Query?"
`
1. Pattern Matching Regex (Livello 1)
→ Identifica ambito
→ Estrae entità (periodo, metrica, nomi)
→ 70-80% query risolte QUI2. Template Lookup (Livello 2)
→ Cerca template pre-costruito per ambito + pattern
→ Esegue SQL deterministico
→ Formatta risposta da template
→ 15-20% query risolte QUI
3. LLM Fallback (Livello 3)
→ Solo per query ambigue/complesse
→ Prompt minimale con dati pre-elaborati
→ 5-10% query risolte QUI
`"Come Organizzare Risposte da Storico + AI?"
`
STORICO PREPARATO (80% query):
AI GENERATIVA (20% query):
``"Cosa Evitare (Incongruenze Nella Tua Richiesta)"
❌ NON fare: Inviare schema completo database in ogni chiamata LLM ✅ Fare invece: Inviare solo dati pre-elaborati (medie, totali, anomalie)
❌ NON fare: Chiedere all'AI di generare SQL dinamico sempre ✅ Fare invece: Template SQL con parametri (prepared statements)
❌ NON fare: Usare GPT-4 per query semplici ✅ Fare invece: Pattern matching + template (0 costi)
❌ NON fare: Lasciare all'AI troppa "libertà creativa" ✅ Fare invece: Temperature bassa + response template + validation
---
🎯 Piano di Azione Concreto
Settimana 1-2: Setup Foundation
1. Crea tabelle database (migrations) 2. Seeding 30-40 template (JSON) per i 7 ambiti 3. Implementa IntentRouterService (pattern matching)Settimana 3: Services Core
1. KnowledgeBaseService (template execution) 2. QueryNormalizationService (entity extraction) 3. CacheService (redis/database)Settimana 4: LLM Integration (Fallback)
1. LLMFallbackService (OpenAI) 2. Prompt optimization (minimale) 3. Cost trackingSettimana 5: Controller & Frontend
1. AiAssistantController (API) 2. Chat Widget (Blade component) 3. Integrazione in analyze.blade.phpSettimana 6: Testing & Refinement
1. User testing con operatori 2. Template refinement basato su feedback 3. Analytics dashboard (admin)---
📊 KPI di Successo
Tecnici
Business
Qualità
---
✅ Conclusione
La tua richiesta è chiarissima e condivisibile:
Vuoi un AI Assistant che: 1. ✅ Sia contestualizzato per ambiti specifici 2. ✅ Usi una Knowledge Base preparata (80% risposte) 3. ✅ Chiami LLM solo quando necessario (20% risposte) 4. ✅ Abbia risposte deterministiche e verificabili 5. ✅ Costi prevedibili e bassi
L'architettura proposta risolve tutti questi requisiti:
Pronto per iniziare? 🚀
Analisi Codice
Blocco 1
3 Macchine i40
↓
Profili Import Configurabili (schema CSV dinamico)
↓
MachineOperationLog (raw_data JSON con campi variabili)
↓
Analyze View (filtri, KPI, grafici)
Blocco 2 sql
-- Campi in raw_data (dipende dal profilo macchina)
TotalPieces, NumberOfPlies, Quantity, etc.
-- Query tipo
SELECT SUM(CAST(JSON_UNQUOTE(JSON_EXTRACT(raw_data, '$.TotalPieces')) AS DECIMAL))
FROM machine_operations_log
WHERE machine_id = :machine_id
AND timestamp BETWEEN :date_from AND :date_to
Blocco 3
📊 Produzione di {periodo}:
✅ Totale pezzi: {total_quantity}
📈 Operazioni: {total_operations}
⏱️ Durata media: {avg_duration}h
Rispetto alla media degli ultimi 30 giorni ({avg_30d} pezzi),
sei {delta_percent}% {emoji_trend}.
Blocco 4
1. Verifica gaps timestamp > 30 min
→ "Fermo macchina rilevato dalle {start_time} alle {end_time}"
2. Verifica campi ErrorCode/AlarmCode in raw_data
→ "Errore registrato: {error_code} - {error_description}"
3. Verifica produzione < media - 20%
→ "Produzione sotto media del {delta}%"
4. Verifica Duration > avg + 2σ
→ "Operazioni più lente del solito (+{percent}%)"
5. Confronta con stesso giorno settimana scorsa
→ "Rispetto a {last_week_same_day}, produzione {comparison}"
Blocco 5
🔍 Analisi {periodo}:
⚠️ Problemi identificati:
1. {problema_1}
2. {problema_2}
...
💡 Cause probabili:
- {causa_1}
- {causa_2}
📊 Dati a supporto:
- Operazioni: {total_ops} (atteso: {expected_ops})
- Durata media: {avg_duration}h (atteso: {expected_duration}h)
Blocco 6 sql
SELECT
JSON_UNQUOTE(JSON_EXTRACT(raw_data, '$.UserLog')) as operator,
COUNT(*) as operations,
SUM(CAST(JSON_UNQUOTE(JSON_EXTRACT(raw_data, '$.TotalPieces')) AS DECIMAL)) as total_pieces,
AVG(CAST(JSON_UNQUOTE(JSON_EXTRACT(raw_data, '$.Duration')) AS DECIMAL)) as avg_duration
FROM machine_operations_log
WHERE machine_id = :machine_id
AND timestamp BETWEEN :date_from AND :date_to
GROUP BY operator
ORDER BY total_pieces DESC
Blocco 7
👥 Ranking Operatori ({periodo}):
🥇 1. {operator_1} - {pieces_1} pezzi ({ops_1} operazioni)
🥈 2. {operator_2} - {pieces_2} pezzi ({ops_2} operazioni)
🥉 3. {operator_3} - {pieces_3} pezzi ({ops_3} operazioni)
⚡ Insight:
{operator_1} è il più veloce con {pieces_per_hour} pezzi/ora
(+{percent}% rispetto alla media di {avg_pieces_per_hour}).
Blocco 8
1. Calcola produzione_media_giornaliera (ultimi 30 giorni)
2. Calcola pezzi_già_prodotti (se order in corso)
3. Calcola pezzi_rimanenti = target - già_prodotti
4. Calcola giorni_lavorativi_rimanenti (escludi weekend)
5. Proiezione:
giorni_necessari = pezzi_rimanenti / produzione_media_giornaliera
6. Confronto:
margin = giorni_lavorativi_rimanenti - giorni_necessari
Blocco 9
📅 Previsione Completamento:
🎯 Target: {target_quantity} pezzi
✅ Già prodotti: {already_produced} pezzi
⏳ Rimanenti: {remaining} pezzi
📊 Proiezione:
- Media giornaliera: {avg_daily} pezzi/giorno
- Giorni necessari: {days_needed} giorni lavorativi
- Deadline: {deadline_date}
- Giorni disponibili: {days_available}
{verdict_emoji} {verdict_message}
💡 Scenario worst-case (-20% produzione):
Servirebbero {worst_case_days} giorni → {worst_case_deadline}
Blocco 10
1. Query periodo 1
2. Query periodo 2
3. Calcola delta assoluto = valore1 - valore2
4. Calcola delta percentuale = (delta / valore2) * 100
5. Determina trend:
- Positivo (+): emoji 📈
- Negativo (-): emoji 📉
- Stabile (±3%): emoji ➡️
Blocco 11
⚖️ Confronto {periodo_1} vs {periodo_2}:
📊 {metrica_label}:
- {periodo_1}: {value_1} {unit}
- {periodo_2}: {value_2} {unit}
📈 Variazione: {delta_abs} {unit} ({delta_percent}% {emoji_trend})
{insight_message}
Blocco 12 sql
-- Tabelle metadata
machines_i40.profiles_config
import_profiles.columns, column_names
csv_imports (status, arrived_at)
Blocco 13
⚙️ Configurazione {machine_name}:
📋 Profili Attivi:
1. {profile_1_name}
- Campi: {fields_count}
- Ultimo import: {last_import_date}
2. {profile_2_name}
- Campi: {fields_count}
- Ultimo import: {last_import_date}
📊 Campi Disponibili (Profilo {active_profile}):
{field_1}, {field_2}, {field_3}, ...
📁 Ultimo Import CSV:
- File: {filename}
- Data: {import_date}
- Righe: {rows_processed}/{rows_total}
- Status: {status_badge}
Blocco 14
1. Analizza distribuzione temporale (orari/giorni più produttivi)
2. Confronta operatori (best practices da replicare)
3. Identifica anomalie ricorrenti (pattern errori)
4. Calcola OEE (Overall Equipment Effectiveness)
5. Identifica downtime patterns
6. Confronta con benchmark aziendali
Blocco 15
IF orario_picco_produzione EXISTS THEN
→ "Le operazioni tra {start_hour}:{end_hour} sono {percent}% più veloci"
→ Suggerimento: "Concentra lavorazioni complesse in questa fascia"
IF operatore_best_performer EXISTS THEN
→ "L'operatore {name} ha resa {percent}% superiore alla media"
→ Suggerimento: "Organizza training con {name} per condividere best practices"
IF downtime_medio > threshold THEN
→ "Fermi macchina: {downtime_hours}h/giorno in media"
→ Cause: {top_3_causes}
→ Suggerimento: "Implementa pre-staging materiali"
Blocco 16
🚀 Analisi Ottimizzazione ({periodo}):
📊 Situazione Attuale:
- Produttività media: {current_productivity}
- OEE: {oee_percent}%
- Downtime: {downtime_hours}h/giorno
💡 Opportunità Identificate:
1. {opportunity_1_title} (Impatto: +{impact_1}%)
{description_1}
✅ Azione: {action_1}
2. {opportunity_2_title} (Impatto: +{impact_2}%)
{description_2}
✅ Azione: {action_2}
3. {opportunity_3_title} (Impatto: +{impact_3}%)
{description_3}
✅ Azione: {action_3}
📈 Potenziale Totale: +{total_impact}%
Blocco 17 php
// Input
$userQuery = "Qual è stata la produzione di ieri?";
// Normalization
$normalized = normalize($userQuery);
// → "qual e stata la produzione di ieri"
// Pattern Matching
foreach ($patterns['AMBITO_PRODUZIONE'] as $regex) {
if (preg_match($regex, $normalized, $matches)) {
return [
'ambito' => 'AMBITO_PRODUZIONE',
'confidence' => 1.0, // Deterministico
'entities' => extractEntities($matches),
// entities: ['periodo' => 'ieri', 'metrica' => 'produzione']
];
}
}
Blocco 18 php
// Estrazione periodo temporale
$periodMap = [
'ieri' => [
'date_from' => now()->subDay()->startOfDay(),
'date_to' => now()->subDay()->endOfDay(),
'label' => 'Ieri',
],
'oggi' => [
'date_from' => now()->startOfDay(),
'date_to' => now()->endOfDay(),
'label' => 'Oggi',
],
'questa settimana' => [
'date_from' => now()->startOfWeek(),
'date_to' => now()->endOfWeek(),
'label' => 'Questa Settimana',
],
// ... altri 20-30 periodi
];
// Estrazione nomi operatori (fuzzy matching)
$operatorNames = getOperatorNamesFromDB($machineId);
$matchedOperator = findClosestMatch($userQuery, $operatorNames);
// Estrazione numeri
preg_match_all('/\d+/', $userQuery, $numbers);
// "5000 pezzi entro venerdì" → entities['quantity'] = 5000
Blocco 19 php
// Query database template
$template = DB::table('ai_knowledge_templates')
->where('ambito', $detectedAmbito)
->whereRaw('? REGEXP pattern', [$userQuery])
->first();
if ($template) {
// Template trovato → Esegui senza LLM
return executeTemplate($template, $entities, $machineId);
}
Blocco 20 json
{
"template_id": "prod_daily",
"pattern": "produzione di (ieri|oggi)",
"sql_query": {
"query": "SELECT SUM(...) FROM ...",
"parameters": {
"machine_id": ":machine_id",
"date_from": ":date_from",
"date_to": ":date_to"
}
},
"response_template": "Produzione di {periodo}: {total} pezzi.",
"enrichment": {
"add_comparison": true,
"compare_with": "avg_last_30_days"
}
}
Blocco 21 php
// Prompt MINIMO (no schema completo)
$systemPrompt = "Sei assistente produzione. Macchina: {$machine->name}. Rispondi in italiano, max 3 frasi.";
// Context injection selettivo (solo dati necessari)
$context = [
'avg_production_last_30d' => 1500, // Pre-calcolato
'last_operation_timestamp' => '2025-10-22 10:30',
'total_operations_today' => 12,
];
// Chiamata LLM con limite tokens
$response = OpenAI::chat()->create([
'model' => 'gpt-4o-mini', // Modello più economico
'messages' => [
['role' => 'system', 'content' => $systemPrompt],
['role' => 'user', 'content' => $userQuery],
],
'temperature' => 0.2, // Basso = più deterministico
'max_tokens' => 300, // Limita risposta
]);
Blocco 22
USER INPUT:
"Qual è stata la produzione di ieri?"
↓
STEP 1: Intent Router (Pattern Matching)
- Normalizza: "qual e stata la produzione di ieri"
- Match pattern: /produz(?:ione) di (ieri|oggi)/i
- Ambito rilevato: AMBITO_PRODUZIONE
- Confidence: 1.0
- Entities: { periodo: 'ieri', metrica: 'produzione' }
↓
STEP 2: Entity Extraction
- Periodo: 'ieri' → date_from: 2025-10-21 00:00, date_to: 2025-10-21 23:59
- Metrica: 'produzione' → campo_raw_data: 'TotalPieces'
↓
STEP 3: Cache Lookup
- Query hash: md5("produzione_ieri_machine_5_2025-10-21")
- Cache hit? NO (prima volta oggi)
↓
STEP 4: Template Lookup
- Template trovato: "prod_daily"
- Requires LLM: false
↓
STEP 5: SQL Execution
Blocco 23
**Result**: { total_quantity: 1850, total_operations: 23, avg_duration: 2.3 }
↓
STEP 6: Context Enrichment
- Carica media ultimi 30 giorni: 1750 pezzi
- Calcola delta: +100 pezzi (+5.7%)
- Emoji trend: 📈
↓
STEP 7: Response Formatting
Blocco 24
↓
STEP 8: Follow-up Suggestions
- "Confronta con l'altro ieri"
- "Mostrami il trend settimanale"
- "Chi ha prodotto di più ieri?"
↓
STEP 9: Save to Cache
- Salva risposta con TTL 1 ora
- Prossima richiesta identica → risposta istantanea da cache
↓
STEP 10: Save to Conversation History
- User message + Assistant response → DB
- Metadata: { ambito, template_id, execution_time_ms, used_llm: false }
↓
TOTAL TIME: ~200ms
TOTAL COST: $0 (no LLM)
Blocco 25
USER INPUT:
"Come posso migliorare la produttività?"
↓
STEP 1: Intent Router
- Ambito: AMBITO_OTTIMIZZAZIONE
- Confidence: 0.9
↓
STEP 2: Template Lookup
- Template: "optimization_suggestions"
- Requires LLM: true (per suggerimenti articolati)
↓
STEP 3: Data Analysis (pre-LLM)
- Analizza distribuzione oraria → Picco: 9-11am (+18%)
- Analizza operatori → Best: "Mario Rossi" (+25%)
- Analizza downtime → Media: 45 min/giorno
↓
STEP 4: LLM Call (con dati pre-elaborati)
Blocco 26
↓
STEP 5: LLM Response
Blocco 27
↓
TOTAL TIME: ~3s
TOTAL COST: ~$0.00012 (LLM usato)
Blocco 28
1. Pattern Matching Regex (Livello 1)
→ Identifica ambito
→ Estrae entità (periodo, metrica, nomi)
→ 70-80% query risolte QUI
2. Template Lookup (Livello 2)
→ Cerca template pre-costruito per ambito + pattern
→ Esegue SQL deterministico
→ Formatta risposta da template
→ 15-20% query risolte QUI
3. LLM Fallback (Livello 3)
→ Solo per query ambigue/complesse
→ Prompt minimale con dati pre-elaborati
→ 5-10% query risolte QUI
Blocco 29
STORICO PREPARATO (80% query):
- Database: 30-40 template JSON in ai_knowledge_templates
- Ogni template = pattern + SQL + response_template + enrichment_rules
- Risposte completamente deterministiche
- Arricchite con contesto (medie, confronti, trend)
AI GENERATIVA (20% query):
- Solo quando template non disponibile
- Prompt minimale (no schema completo)
- Context injection selettivo (dati pre-calcolati)
- Temperature bassa (0.2-0.3) per risposte coerenti