Data Governance e Data Quality per AI Affidabile
Il 72% dei progetti AI aziendali fallisce prima di arrivare in produzione. Non per mancanza di algoritmi sofisticati, non per architetture inadeguate, non per talento mancante nel team. Falliscono per dati di qualità insufficiente, per assenza di governance, per pipeline che producono silenziosamente risultati errati senza che nessuno se ne accorga.
In un contesto in cui l'AI Act EU impone per la prima volta requisiti legali sulla qualità dei dati di addestramento per i sistemi ad alto rischio, e in cui le PMI italiane stanno investendo sempre più in progetti data-driven grazie al PNRR Transizione 5.0, costruire una fondazione solida di data governance e data quality non e più una scelta: e un prerequisito per competere e per restare conformi.
Questo articolo ti guida attraverso i framework operativi, gli strumenti open source e le implementazioni pratiche che consentono di costruire sistemi AI affidabili: dalla definizione delle dimensioni di qualità dei dati, all'implementazione di test automatici con Great Expectations e dbt, fino alla gestione della data lineage con OpenMetadata e alla compliance con l'AI Act.
Cosa Imparerai in Questo Articolo
- Le 6 dimensioni DAMA di data quality e come misurarle in modo automatizzato
- Implementazione di data quality checks con Great Expectations e dbt-expectations
- Data catalog e data lineage con OpenMetadata e Apache Atlas
- Data governance framework: ruoli, processi e struttura organizzativa
- Requisiti AI Act EU (Articolo 10) per i dati di addestramento: cosa fare prima di agosto 2026
- Data observability con Soda Core e Monte Carlo per pipeline in produzione
- Bias detection nei dataset ML e strategie di mitigazione
- Case study: framework di data governance per una PMI manifatturiera italiana
La Serie Data Warehouse, AI e Trasformazione Digitale
| # | Articolo | Focus |
|---|---|---|
| 1 | Evoluzione del Data Warehouse | Da SQL Server a Data Lakehouse |
| 2 | Data Mesh e Architettura Decentralizzata | Domain ownership dei dati |
| 3 | ETL vs ELT Moderno | dbt, Airbyte e Fivetran |
| 4 | Orchestrazione Pipeline | Airflow, Dagster e Prefect |
| 5 | AI nella Manifattura | Predictive Maintenance e Digital Twin |
| 6 | AI nel Finance | Fraud Detection e Credit Scoring |
| 7 | AI nel Retail | Demand Forecasting e Recommendation |
| 8 | AI in Healthcare | Diagnostica e Drug Discovery |
| 9 | AI nella Logistica | Route Optimization e Warehouse Automation |
| 10 | LLM in Azienda | RAG Enterprise e Guardrails |
| 11 | Vector Database Enterprise | pgvector, Pinecone e Weaviate |
| 12 | MLOps per Business | Modelli AI in Produzione con MLflow |
| 13 | Sei qui - Data Governance | Data Quality per AI Affidabile |
| 14 | Roadmap Data-Driven per PMI | Come adottare AI e DWH |
Il Problema della qualità dei Dati nell'Era AI
"Garbage in, garbage out" e un principio che i data engineer conoscono da decenni, ma con l'AI generativa e i modelli di machine learning in produzione, le conseguenze di dati scadenti sono diventate esponenzialmente più gravi. Un modello di fraud detection addestrato su dati sbilanciati genera falsi positivi che bloccano transazioni legittime. Un sistema di raccomandazione addestrato su dati con bias demografici amplifica le discriminazioni. Un modello di previsione della domanda addestrato su dati inconsistenti genera ordini errati con impatto diretto sul cash flow.
Il Costo dei Dati di Scarsa qualità - Dati 2025
| Indicatore | Valore | Fonte |
|---|---|---|
| Costo medio per azienda (dati scarsa qualità) | $12.9 milioni/anno | Gartner 2024 |
| Progetti AI che falliscono per qualità dati | 72% | McKinsey 2025 |
| Tempo data scientist su data cleaning | 45-60% | Multiple surveys |
| PMI italiane con programma data quality formale | 18% | Osservatorio AI Polimi 2025 |
| Riduzione errori ML con data governance | fino al 35% | IBM Institute 2025 |
La distinzione fondamentale che molte organizzazioni non colgono e la differenza tra data quality per analytics e data quality per AI. Nel reporting tradizionale, un dato anomalo produce un numero sbagliato su un dashboard - qualcuno lo nota, lo corregge, si va avanti. Nel machine learning, un dato anomalo nel training set contamina silenziosamente il modello, che poi si comporta in modo errato in produzione per mesi prima che il problema venga identificato. La latenza tra il problema e la sua manifestazione e infinitamente più alta.
Le 6 Dimensioni DAMA della Data Quality
Il framework DAMA-DMBOK (Data Management Body of Knowledge) definisce 6 dimensioni fondamentali di qualità dei dati, che nel 2025 rimangono il riferimento standard per qualsiasi programma di data quality enterprise:
Dimensioni DAMA per AI - Framework Esteso
| Dimensione | Definizione | Metrica AI-Specifica | Soglia Critica |
|---|---|---|---|
| Accuracy | I dati rappresentano correttamente la realta | % label corrette nel training set | >99% per classificazione critica |
| Completeness | Tutti i dati necessari sono presenti | % valori non-null per feature critiche | >95% per feature di input |
| Consistency | I dati sono uniformi tra sistemi diversi | % record concordanti tra sorgenti | >98% per feature condivise |
| Timeliness | I dati sono aggiornati e disponibili quando servono | Lag medio dati di produzione vs training | <24h per modelli real-time |
| Validity | I dati rispettano formati e vincoli definiti | % violazioni di schema e range | <0.1% violazioni |
| Uniqueness | Assenza di duplicati non intenzionali | % record duplicati nel training set | <0.5% duplicati |
Implementazione Pratica: Data Quality con Great Expectations
Great Expectations e il framework open source Python più diffuso per i test di data quality. L'approccio e simile ai unit test per il codice: si definiscono "expectations" (aspettative) sui dati, si eseguono automaticamente nella pipeline, e si genera documentazione automatica. L'integrazione con Airflow, Prefect e dbt lo rende un componente naturale di qualsiasi data stack moderno.
# data_quality_pipeline.py
# Framework completo di data quality con Great Expectations
import great_expectations as gx
from great_expectations.core.batch import RuntimeBatchRequest
import pandas as pd
import numpy as np
from datetime import datetime
import logging
logger = logging.getLogger(__name__)
class DataQualityFramework:
"""
Framework di data quality per pipeline ML enterprise.
Implementa le 6 dimensioni DAMA con Great Expectations.
"""
def __init__(self, datasource_name: str = "ml_training_data"):
self.context = gx.get_context()
self.datasource_name = datasource_name
self.validation_results = {}
def build_expectation_suite_for_ml(
self,
suite_name: str,
target_column: str,
feature_columns: list[str]
):
"""
Crea una suite di expectations per dataset ML.
Copre tutte le 6 dimensioni DAMA.
"""
suite = self.context.add_expectation_suite(
expectation_suite_name=suite_name
)
# === DIMENSIONE: COMPLETENESS ===
# Feature critiche devono avere meno del 5% di valori nulli
for col in feature_columns:
suite.add_expectation(
gx.core.ExpectationConfiguration(
expectation_type="expect_column_values_to_not_be_null",
kwargs={
"column": col,
"mostly": 0.95 # 95% non-null
}
)
)
# Target column deve essere 100% non-null
suite.add_expectation(
gx.core.ExpectationConfiguration(
expectation_type="expect_column_values_to_not_be_null",
kwargs={"column": target_column}
)
)
# === DIMENSIONE: VALIDITY ===
# Valori numerici in range atteso (es. eta 0-120)
suite.add_expectation(
gx.core.ExpectationConfiguration(
expectation_type="expect_column_values_to_be_between",
kwargs={
"column": "customer_age",
"min_value": 18,
"max_value": 120,
"mostly": 0.999
}
)
)
# === DIMENSIONE: UNIQUENESS ===
# Chiavi primarie devono essere uniche
suite.add_expectation(
gx.core.ExpectationConfiguration(
expectation_type="expect_column_values_to_be_unique",
kwargs={"column": "transaction_id"}
)
)
# === DIMENSIONE: CONSISTENCY ===
# Il target deve avere solo valori attesi (no label noise)
suite.add_expectation(
gx.core.ExpectationConfiguration(
expectation_type="expect_column_values_to_be_in_set",
kwargs={
"column": target_column,
"value_set": [0, 1], # Classificazione binaria
}
)
)
# === DIMENSIONE: ACCURACY - Distribuzione statistica ===
# La distribuzione non deve essere degenere
suite.add_expectation(
gx.core.ExpectationConfiguration(
expectation_type="expect_column_proportion_of_unique_values_to_be_between",
kwargs={
"column": "customer_id",
"min_value": 0.3, # Almeno 30% utenti unici
"max_value": 1.0
}
)
)
# Bilanciamento classi per training set (max 10:1 ratio)
suite.add_expectation(
gx.core.ExpectationConfiguration(
expectation_type="expect_column_most_common_value_to_be_in_set",
kwargs={
"column": target_column,
"value_set": [0, 1],
"ties_okay": True
}
)
)
# === DIMENSIONE: TIMELINESS ===
# Dati non più vecchi di 90 giorni
suite.add_expectation(
gx.core.ExpectationConfiguration(
expectation_type="expect_column_values_to_be_between",
kwargs={
"column": "event_timestamp",
"min_value": "2024-11-01", # Rolling window
"max_value": datetime.now().strftime("%Y-%m-%d"),
"parse_strings_as_datetimes": True,
"mostly": 0.99
}
)
)
self.context.save_expectation_suite(suite)
logger.info(f"Suite {suite_name} creata con {len(suite.expectations)} expectations")
return suite
def validate_dataset(
self,
df: pd.DataFrame,
suite_name: str,
run_name: str = None
) -> dict:
"""
Valida un DataFrame contro la suite definita.
Restituisce risultati strutturati per monitoring.
"""
run_name = run_name or f"run_{datetime.now().isoformat()}"
batch_request = RuntimeBatchRequest(
datasource_name=self.datasource_name,
data_connector_name="runtime_connector",
data_asset_name="training_data",
runtime_parameters={"batch_data": df},
batch_identifiers={"run_id": run_name}
)
checkpoint = self.context.add_or_update_checkpoint(
name="ml_data_checkpoint",
validations=[
{
"batch_request": batch_request,
"expectation_suite_name": suite_name
}
]
)
results = checkpoint.run(run_name=run_name)
# Estrai metriche aggregate
validation_result = results.list_validation_results()[0]
stats = validation_result.statistics
quality_report = {
"run_name": run_name,
"timestamp": datetime.now().isoformat(),
"success": results.success,
"evaluated_expectations": stats["evaluated_expectations"],
"successful_expectations": stats["successful_expectations"],
"unsuccessful_expectations": stats["unsuccessful_expectations"],
"success_rate": stats["success_percent"] / 100,
"failed_checks": [
{
"expectation": r.expectation_config.expectation_type,
"column": r.expectation_config.kwargs.get("column"),
"details": r.result
}
for r in validation_result.results
if not r.success
]
}
self.validation_results[run_name] = quality_report
return quality_report
# Utilizzo nella pipeline
def run_data_quality_checks(raw_data_path: str):
framework = DataQualityFramework()
# Definisci le expectations per il dataset
framework.build_expectation_suite_for_ml(
suite_name="ml_training_v1",
target_column="churn_label",
feature_columns=["customer_age", "tenure_months", "monthly_charges",
"total_charges", "contract_type", "payment_method"]
)
# Carica e valida i dati
df = pd.read_parquet(raw_data_path)
report = framework.validate_dataset(df, "ml_training_v1")
if not report["success"]:
failed = report["unsuccessful_expectations"]
logger.error(f"Data quality FALLITA: {failed} check falliti su {report['evaluated_expectations']}")
for check in report["failed_checks"]:
logger.error(f" - {check['expectation']} su colonna '{check['column']}'")
raise DataQualityError(f"Dataset non conforme agli standard di qualità")
logger.info(f"Data quality OK: {report['success_rate']:.1%} success rate")
return report
Data Quality con dbt: Test Dichiarativi nella Pipeline di Trasformazione
Per i team che usano dbt come layer di trasformazione, il pacchetto dbt-expectations porta le stesse capabilities di Great Expectations direttamente nei modelli dbt, definendo i test in YAML vicino al codice SQL. Questo approccio "quality as code" garantisce che ogni trasformazione venga validata automaticamente.
# models/schema.yml
# Test di data quality con dbt-expectations
version: 2
models:
- name: ml_features_customer
description: "Feature store per modello churn prediction"
columns:
- name: customer_id
description: "Identificativo univoco cliente"
tests:
- unique
- not_null
- dbt_expectations.expect_column_values_to_be_of_type:
column_type: VARCHAR
- name: customer_age
description: "Eta del cliente in anni"
tests:
- not_null
- dbt_expectations.expect_column_values_to_be_between:
min_value: 18
max_value: 120
mostly: 0.999
- name: monthly_charges
description: "Addebiti mensili in EUR"
tests:
- not_null
- dbt_expectations.expect_column_values_to_be_between:
min_value: 0
max_value: 10000
- dbt_expectations.expect_column_mean_to_be_between:
min_value: 50
max_value: 200
- name: churn_label
description: "Label target: 1=churned, 0=retained"
tests:
- not_null
- accepted_values:
values: [0, 1]
# Verifica che il dataset non sia troppo sbilanciato
- dbt_expectations.expect_column_proportion_of_unique_values_to_be_between:
min_value: 0.01 # Almeno 1% di churn (altrimenti dataset anomalo)
max_value: 0.5 # Max 50% di churn (dataset equilibrato)
- name: event_date
description: "Data dell'evento"
tests:
- not_null
- dbt_expectations.expect_column_values_to_be_between:
min_value: "2023-01-01"
max_value: "{{ var('max_date', modules.datetime.date.today().isoformat()) }}"
parse_strings_as_datetimes: true
- name: ml_features_customer
tests:
# Test a livello di tabella: volumetria attesa
- dbt_expectations.expect_table_row_count_to_be_between:
min_value: 10000
max_value: 10000000
# Nessuna riga duplicata su chiave composta
- dbt_expectations.expect_compound_columns_to_be_unique:
column_list: ["customer_id", "snapshot_date"]
Data Catalog e Data Lineage con OpenMetadata
La data lineage - la capacità di tracciare il percorso di un dato dalla sorgente fino al modello AI finale - e diventata un requisito imprescindibile per due ragioni convergenti: la compliance con l'AI Act EU (che richiede documentazione dell'origine dei dati di addestramento) e la necessità pratica di debugging quando un modello produce risultati inaspettati.
OpenMetadata e la piattaforma open source più avanzata per data catalog e lineage nel 2025, costruita da ex-ingegneri di Uber e fondatori di Apache Hadoop. Supporta lineage a livello di colonna, integrazione nativa con dbt, Airflow, Spark e i principali data warehouse.
# openmetadata_lineage.py
# Registrazione automatica della data lineage per pipeline ML
from metadata.ingestion.api.workflow import Workflow
from metadata.generated.schema.entity.data.pipeline import Pipeline
from metadata.generated.schema.entity.data.table import Table
from metadata.generated.schema.type.entityLineage import (
ColumnLineage,
EntitiesEdge,
LineageDetails
)
from metadata.generated.schema.api.lineage.addLineage import AddLineageRequest
from metadata.ingestion.ometa.ometa_api import OpenMetadata
from metadata.generated.schema.security.client.openMetadataJWTClientConfig import (
OpenMetadataJWTClientConfig
)
import json
from typing import Optional
class MLPipelineLineageTracker:
"""
Tracker automatico di data lineage per pipeline ML.
Registra ogni trasformazione in OpenMetadata.
"""
def __init__(self, server_url: str, jwt_token: str):
from metadata.generated.schema.entity.services.connections.metadata.openMetadataConnection import (
OpenMetadataConnection
)
server_config = OpenMetadataConnection(
hostPort=server_url,
authProvider="openmetadata",
securityConfig=OpenMetadataJWTClientConfig(jwtToken=jwt_token)
)
self.metadata = OpenMetadata(server_config)
def register_training_data_lineage(
self,
source_tables: list[str],
feature_store_table: str,
ml_model_name: str,
transformation_description: str
):
"""
Registra il percorso: raw_data -> feature_store -> ml_model
Essenziale per compliance AI Act (Art. 10 - Data Governance)
"""
# 1. Recupera entità sorgente
source_entities = []
for table_fqn in source_tables:
table = self.metadata.get_by_name(
entity=Table,
fqn=table_fqn
)
if table:
source_entities.append(table)
# 2. Recupera/crea feature store table
feature_table = self.metadata.get_by_name(
entity=Table,
fqn=feature_store_table
)
# 3. Costruisci lineage con dettagli di trasformazione
for source in source_entities:
lineage_request = AddLineageRequest(
edge=EntitiesEdge(
fromEntity={
"id": str(source.id.__root__),
"type": "table"
},
toEntity={
"id": str(feature_table.id.__root__),
"type": "table"
},
lineageDetails=LineageDetails(
description=transformation_description,
columnsLineage=[
ColumnLineage(
fromColumns=[f"{source.fullyQualifiedName.__root__}.customer_id"],
toColumn=f"{feature_store_table}.customer_id"
),
ColumnLineage(
fromColumns=[f"{source.fullyQualifiedName.__root__}.event_date"],
toColumn=f"{feature_store_table}.snapshot_date"
)
]
)
)
)
self.metadata.add_lineage(lineage_request)
# 4. Aggiungi tag di compliance (AI Act)
self._tag_for_ai_act_compliance(feature_store_table, ml_model_name)
def _tag_for_ai_act_compliance(
self,
table_fqn: str,
model_name: str
):
"""
Aggiunge tag AI Act per tracciabilita compliance.
Essenziale per sistemi high-risk (AI Act Art. 10).
"""
table = self.metadata.get_by_name(entity=Table, fqn=table_fqn)
# Tag strutturati per AI Act
compliance_tags = {
"ai_act_article_10": "training_data",
"ai_system": model_name,
"data_governance_reviewed": "true",
"bias_assessment_date": "2025-01-15",
"data_quality_score": "98.5"
}
# Aggiorna custom properties
self.metadata.patch_entity(
entity=Table,
source=table,
destination=table.copy(
update={"customMetrics": compliance_tags}
)
)
print(f"Compliance tags aggiunti per {table_fqn} -> modello {model_name}")
# Utilizzo pratico
def setup_ml_lineage():
tracker = MLPipelineLineageTracker(
server_url="http://openmetadata.internal:8585/api",
jwt_token="your-jwt-token"
)
tracker.register_training_data_lineage(
source_tables=[
"default.raw_crm.customers",
"default.raw_billing.transactions",
"default.raw_support.tickets"
],
feature_store_table="default.feature_store.ml_churn_features_v3",
ml_model_name="churn_prediction_xgboost_v2",
transformation_description="Feature engineering per churn prediction: "
"aggregazioni mensili, calcolo tenure, "
"encoding categoriche. Approvato data steward 2025-01-15."
)
Data Governance Framework: Struttura Organizzativa e Processi
La data governance non e uno strumento software: e un sistema di persone, processi e tecnologie che garantisce che i dati siano gestiti come un asset strategico. Per le PMI italiane che si avvicinano all'AI, costruire questa struttura in modo pragmatico e essenziale.
I Ruoli Chiave della Data Governance
Struttura di Governance per PMI (50-500 dipendenti)
| Ruolo | Responsabilità | FTE Stimato | Profilo |
|---|---|---|---|
| Chief Data Officer (CDO) | Strategia dati, sponsor esecutivo, budget, compliance AI Act | 0.25 FTE (parziale) | C-level o manager senior |
| Data Steward | Ownership dominio dati, definizione standard, approvazione modifiche | 1 per dominio dati | Business + tecnica |
| Data Engineer | Pipeline, qualità tecnica, strumenti di monitoring | 1-2 FTE | Profilo tecnico |
| Data Quality Analyst | Definizione KPI qualità, audit, reportistica | 0.5 FTE | Analitico/ibrido |
| DPO (Data Protection Officer) | GDPR, AI Act, sicurezza dati, privacy by design | 0.25-0.5 FTE | Legale/tecnica |
Data Governance Policy: I 5 Processi Fondamentali
Un programma di data governance operativo si basa su 5 processi ricorrenti che devono essere documentati, assegnati e monitorati:
- Data Classification: Ogni dataset classificato per sensibilita (pubblico, interno, confidenziale, segreto) e per tipo (PII, dati finanziari, dati operativi, dati di training ML). Questa classificazione determina i controlli di accesso, la retention policy e i requisiti di qualità applicabili.
- Data Quality SLA: Per ogni dataset critico, definizione formale di SLA di qualità: completeness > 98%, latency < 2h, accuracy validata trimestralmente. Gli SLA devono essere misurabili e monitorati automaticamente.
- Change Management: Processo formale per modifiche agli schema dei dati critici. Nessuna modifica senza impatto assessment, test di regression e approvazione del data steward di dominio.
- Data Access Management: Principio del minimo privilegio applicato ai dati. Accesso ai dati di training ML limitato al team ML con audit log completo. Review trimestrale degli accessi.
- Incident Response: Procedura di escalation per data quality incidents: rilevamento automatico (alerting), triage (<4h), remediation, post-mortem e aggiornamento dei check automatici.
AI Act EU e Requisiti per i Dati di Training
L'AI Act EU introduce per la prima volta nella storia requisiti legalmente vincolanti sulla qualità dei dati di addestramento per i sistemi AI ad alto rischio. L'Articolo 10 del regolamento e specificamente dedicato a "Data and Data Governance" ed e diventato operativo per i GPAI models dal 2 agosto 2025. Per i sistemi high-risk, la piena compliance e richiesta entro il 2 agosto 2026.
Timeline AI Act EU - Cosa Fare Prima di Agosto 2026
| Data | Milestone | Azione Richiesta |
|---|---|---|
| Feb 2025 | Pratiche AI vietate operative | Audit dei sistemi AI per pratiche proibite |
| Ago 2025 | GPAI models e governance operativi | Governance per LLM e modelli fondazionali |
| Ago 2026 | High-risk AI systems full compliance | Data governance Art. 10 completamente implementata |
| Ago 2027 | Legacy systems compliance | Sistemi AI esistenti adeguati |
Articolo 10 AI Act: Requisiti Tecnici per i Dati
L'Articolo 10 dell'AI Act impone requisiti specifici per i dataset usati nell'addestramento, validazione e test dei sistemi AI ad alto rischio. Ecco cosa deve essere documentato e implementato concretamente:
# ai_act_compliance_checker.py
# Verifica compliance AI Act Art. 10 per dataset di training
from dataclasses import dataclass, field
from typing import Optional
import pandas as pd
import numpy as np
from scipy import stats
import json
from datetime import datetime
@dataclass
class DatasetComplianceReport:
"""Report di compliance AI Act Articolo 10."""
dataset_name: str
assessment_date: str
assessor: str
compliant: bool = False
checks: dict = field(default_factory=dict)
recommendations: list = field(default_factory=list)
class AIActArticle10Checker:
"""
Verifica conformità AI Act Art. 10 per dataset di training high-risk.
Art. 10 richiede che i dataset siano:
1. Rilevanti e sufficientemente rappresentativi
2. Liberi da errori per quanto possibile
3. Completi rispetto allo scopo
4. Con proprietà statistiche appropriate
5. Privi di bias che potrebbero discriminare gruppi protetti
"""
def __init__(self, dataset_name: str, assessor: str):
self.report = DatasetComplianceReport(
dataset_name=dataset_name,
assessment_date=datetime.now().isoformat(),
assessor=assessor
)
def check_representativeness(
self,
df: pd.DataFrame,
demographic_columns: list[str],
reference_distributions: dict
) -> bool:
"""
Art. 10(3): Verifica rappresentativita demografica.
Confronta distribuzione del dataset con popolazione di riferimento.
"""
is_representative = True
self.report.checks["representativeness"] = {}
for col in demographic_columns:
if col not in df.columns:
continue
# Distribuzione nel dataset
observed = df[col].value_counts(normalize=True).to_dict()
# Distribuzione attesa (es. ISTAT per demografia italiana)
expected = reference_distributions.get(col, {})
if not expected:
continue
# Test chi-quadro per significativita statistica
categories = list(set(observed.keys()) | set(expected.keys()))
obs_counts = [df[col].value_counts().get(c, 0) for c in categories]
exp_props = [expected.get(c, 0.001) for c in categories]
# Normalizza expected
total_exp = sum(exp_props)
exp_normalized = [p / total_exp * len(df) for p in exp_props]
chi2, p_value = stats.chisquare(obs_counts, exp_normalized)
deviation = {
"chi2_statistic": chi2,
"p_value": p_value,
"is_representative": p_value > 0.05, # p > 0.05 = no significant deviation
"observed_distribution": observed,
"expected_distribution": expected
}
self.report.checks["representativeness"][col] = deviation
if p_value <= 0.05:
is_representative = False
self.report.recommendations.append(
f"CRITICO: Colonna '{col}' non e rappresentativa della popolazione target "
f"(chi2={chi2:.2f}, p={p_value:.4f}). "
f"Richiesta oversampling o raccolta dati aggiuntiva."
)
return is_representative
def check_bias_protected_attributes(
self,
df: pd.DataFrame,
target_column: str,
protected_attributes: list[str]
) -> bool:
"""
Art. 10(5): Verifica assenza bias su attributi protetti.
Usa disparate impact ratio (soglia 0.8 = 80% rule).
"""
is_unbiased = True
self.report.checks["bias_assessment"] = {}
for attr in protected_attributes:
if attr not in df.columns:
continue
groups = df[attr].unique()
positive_rates = {}
for group in groups:
mask = df[attr] == group
group_df = df[mask]
if len(group_df) == 0:
continue
positive_rate = (group_df[target_column] == 1).mean()
positive_rates[str(group)] = positive_rate
if len(positive_rates) < 2:
continue
max_rate = max(positive_rates.values())
min_rate = min(positive_rates.values())
# Disparate Impact = min_rate / max_rate
# AI Act richiede > 0.8 (80% rule)
disparate_impact = min_rate / max_rate if max_rate > 0 else 1.0
bias_result = {
"disparate_impact": disparate_impact,
"compliant": disparate_impact >= 0.8,
"group_rates": positive_rates,
"max_group": max(positive_rates, key=positive_rates.get),
"min_group": min(positive_rates, key=positive_rates.get)
}
self.report.checks["bias_assessment"][attr] = bias_result
if disparate_impact < 0.8:
is_unbiased = False
self.report.recommendations.append(
f"CRITICO: Bias rilevato su attributo protetto '{attr}'. "
f"Disparate impact = {disparate_impact:.3f} (soglia AI Act: 0.80). "
f"Applicare re-weighting, resampling o fairness constraints."
)
return is_unbiased
def check_completeness_and_errors(
self,
df: pd.DataFrame,
critical_features: list[str]
) -> bool:
"""
Art. 10(2): Verifica completezza e assenza di errori.
"""
is_complete = True
self.report.checks["completeness"] = {}
for col in critical_features:
null_rate = df[col].isna().mean()
is_col_complete = null_rate < 0.05 # Soglia 5%
self.report.checks["completeness"][col] = {
"null_rate": null_rate,
"compliant": is_col_complete
}
if not is_col_complete:
is_complete = False
self.report.recommendations.append(
f"AVVISO: Feature '{col}' ha {null_rate:.1%} valori mancanti. "
f"Applicare imputation strategy o raccogliere dati aggiuntivi."
)
return is_complete
def generate_compliance_report(self) -> str:
"""Genera report JSON per audit AI Act."""
self.report.compliant = all([
check.get("is_representative", True)
for check in self.report.checks.get("representativeness", {}).values()
] + [
check.get("compliant", True)
for check in self.report.checks.get("bias_assessment", {}).values()
] + [
check.get("compliant", True)
for check in self.report.checks.get("completeness", {}).values()
])
return json.dumps({
"dataset": self.report.dataset_name,
"assessment_date": self.report.assessment_date,
"assessor": self.report.assessor,
"ai_act_article_10_compliant": self.report.compliant,
"checks": self.report.checks,
"recommendations": self.report.recommendations,
"next_review_date": "2025-04-15"
}, indent=2, default=str)
# Esempio di utilizzo per un sistema HR high-risk
def assess_hr_model_dataset(df: pd.DataFrame):
checker = AIActArticle10Checker(
dataset_name="hr_promotion_training_v3",
assessor="Maria Rossi, Data Steward HR"
)
# Distribuzione di riferimento: composizione forza lavoro italiana
reference_distributions = {
"gender": {"M": 0.54, "F": 0.46},
"age_group": {"18-30": 0.20, "31-45": 0.40, "46-60": 0.35, "60+": 0.05}
}
# Esegui tutti i check
checker.check_representativeness(df, ["gender", "age_group"], reference_distributions)
checker.check_bias_protected_attributes(df, "promoted", ["gender", "age_group", "nationality"])
checker.check_completeness_and_errors(df, ["performance_score", "tenure", "education_level"])
report = checker.generate_compliance_report()
print(report)
return report
Data Observability: Monitoring Continuo delle Pipeline in Produzione
La data quality non si garantisce solo al momento dell'ingestion: i dati si degradano nel tempo. Il fenomeno del data drift - in cui la distribuzione dei dati in produzione si discosta progressivamente dal training set - e una delle cause principali di degradazione silente dei modelli AI. La data observability affronta questo problema con monitoring continuo e alerting proattivo.
Confronto Strumenti Data Observability 2025
| Strumento | Tipo | Punti di Forza | Caso d'Uso Ideale |
|---|---|---|---|
| Soda Core | Open source | YAML-based, CLI, integrabile in CI/CD | PMI con budget limitato, pipeline dbt |
| Monte Carlo | SaaS (enterprise) | ML-powered, zero-config anomaly detection | Enterprise, volume elevato, team piccolo |
| Great Expectations | Open source | Python-native, flessibile, documentazione auto | Team data engineering, pipeline Python |
| dbt tests | Open source | Quality as code, integrato nel workflow dbt | Teams che usano dbt come layer principale |
| Metaplane | SaaS (mid-market) | Lineage + observability, UI intuitiva | Scale-up con più data sources |
Data Drift Detection con Soda Core
Soda Core permette di definire check di qualità in YAML e di eseguirli in modo schedulato o on-demand. Per il monitoring del data drift, e possibile confrontare le distribuzioni di feature critiche tra periodi diversi, rilevando automaticamente cambiamenti significativi che potrebbero degradare i modelli AI.
# soda_checks_ml_pipeline.yml
# Check Soda Core per data observability pipeline ML
checks for ml_features_customer:
# === FRESHNESS: timeliness dei dati ===
- freshness(event_date) < 24h:
name: "Dati non più vecchi di 24 ore"
fail:
when freshness(event_date) > 24h
warn:
when freshness(event_date) > 12h
# === VOLUME: anomalie di volumetria ===
- row_count > 50000:
name: "Minimo 50K record per inference affidabile"
- row_count between 50000 and 5000000:
name: "Volume nel range atteso (no spike anomali)"
# === COMPLETENESS ===
- missing_count(customer_age) = 0:
name: "Customer age: zero null tollerati"
- missing_percent(monthly_charges) < 2%:
name: "Monthly charges: max 2% null"
# === VALIDITY ===
- invalid_percent(customer_age) < 0.1%:
name: "Customer age nel range 18-120"
valid min: 18
valid max: 120
- duplicate_count(customer_id) = 0:
name: "Nessun customer_id duplicato"
# === DISTRIBUTION DRIFT ===
# Confronto con baseline storica (riferimento: settimana precedente)
- distribution_difference_index(monthly_charges) < 0.1:
name: "Monthly charges: drift < 10% vs baseline"
method: psi # Population Stability Index
baseline: soda://ml_features_customer/monthly_charges_baseline
- distribution_difference_index(customer_age) < 0.1:
name: "Customer age: drift < 10% vs baseline"
method: ks # Kolmogorov-Smirnov test
# === BUSINESS RULES ===
- failed_rows(monthly_charges_anomaly):
name: "Nessun addebito negativo"
fail condition: monthly_charges < 0
- failed_rows(contract_consistency):
name: "Contratti annuali: addebito >= 100 EUR"
fail condition: contract_type = 'annual' AND monthly_charges < 100
# Configurazione alerting
alert config:
slack:
webhook: "https://hooks.slack.com/services/..."
channel: "#data-quality-alerts"
email:
to:
- "data-team@azienda.it"
- "ml-team@azienda.it"
severity:
fail: immediate
warn: daily_digest
Bias Detection nei Dataset ML: Approccio Sistematico
Il bias nei dati e uno dei problemi più insidiosi nel machine learning aziendale: silenzioso, difficile da rilevare senza metodologie appropriate, e potenzialmente discriminatorio verso gruppi protetti. Con l'AI Act che classifica come "high-risk" i sistemi AI usati in decisioni su accesso al lavoro, credito, servizi pubblici e istruzione, la bias detection e diventata un requisito di compliance oltre che di etica professionale.
I bias nei dati di training derivano da tre sorgenti principali: historical bias (dati che riflettono discriminazioni passate, es. tassi di promozione storicamente sbilanciati), representation bias (gruppi sottorappresentati nel training set), e measurement bias (feature che servono come proxy per attributi protetti, es. codice postale come proxy del reddito e dell'etnia).
Metriche di Fairness - Standard IBM AIF360 e AI Act
| Metrica | Formula | Soglia AI Act | Uso Tipico |
|---|---|---|---|
| Disparate Impact | P(Y=1|A=0) / P(Y=1|A=1) | >= 0.80 | Hiring, credit |
| Equal Opportunity | TPR(A=0) - TPR(A=1) | |diff| < 0.05 | Healthcare, justice |
| Demographic Parity | P(Y=1|A=0) - P(Y=1|A=1) | |diff| < 0.05 | Recommendations |
| Calibration | P(Y=1|score=s, A=a) uniforme | RMSE < 0.02 | Risk scoring |
Case Study: Data Governance per una PMI Manifatturiera Italiana
Una PMI manifatturiera lombarda con 180 dipendenti ha avviato nel 2024 un programma di data governance per supportare tre iniziative AI: un modello di predictive maintenance per i macchinari CNC, un sistema di quality control visivo basato su computer vision, e un demand forecasting per la pianificazione della produzione.
Sfida: I Dati Erano Ovunque e Nessuno ne Era Responsabile
La situazione iniziale era tipica delle PMI italiane: sensori IoT che scrivevano dati in formati proprietari, dati di produzione in un ERP SAP Business One, dati di qualità in fogli Excel condivisi via email, dati di vendita in un CRM non integrato. Il team IT aveva una visione tecnica dell'infrastruttura ma nessuna governance formale.
Risultati Programma Data Governance (12 mesi)
| Indicatore | Prima | Dopo 12 mesi | Impatto |
|---|---|---|---|
| Data quality score medio | 61% | 94% | +33 punti |
| Tempo preparazione dati ML | 3-4 settimane | 2-3 giorni | -90% |
| Dataset con lineage documentata | 0% | 87% | +87 punti |
| Modelli AI in produzione | 0 | 3 | +3 sistemi |
| Conformità AI Act Art. 10 | Non valutata | Conforme | Pronto per audit |
Il Roadmap Implementativo in 4 Fasi
Il programma e stato strutturato in 4 fasi trimestrali, con un investimento totale di circa 85.000 EUR (in parte coperto dal PNRR Transizione 5.0):
- Fase 1 - Inventario e Assessment (Q1 2024): Mappatura di tutti i sistemi dati, classificazione dei dataset per criticita AI, assessment qualità iniziale. Strumenti: foglio di inventario + questionario self-assessment per i responsabili di dominio. Output: mappa completa dei dati critici con gap analysis.
- Fase 2 - Foundation (Q2 2024): Deployment di OpenMetadata on-premise, configurazione dei primi cataloghi dati, definizione dei data steward per ogni dominio (produzione, qualità, vendite). Implementazione dei primi check automatici con dbt tests.
- Fase 3 - Quality Automation (Q3 2024): Deploy Great Expectations per validazione automatica dei dataset ML, integrazione con Airflow per alerting, definizione delle SLA di qualità per i 3 progetti AI. Prima valutazione AI Act Art. 10.
- Fase 4 - Optimization e Governance Matura (Q4 2024): Data Council mensile attivo, KPI di qualità su dashboard Metabase, processo di change management formale, training al personale. I 3 modelli AI sono stati deployati in produzione con data governance completa.
Lezioni Apprese: i 5 Errori da Evitare
- Partire dagli strumenti invece che dai processi: La tecnologia viene dopo le persone e i processi. Nominare i data steward prima di installare qualsiasi software.
- Voler fare tutto subito: Un programma di governance evolutivo e più sostenibile di un big bang. Iniziare dai dataset critici per l'AI, espandere gradualmente.
- Sottovalutare la formazione: Il 40% del budget e' stato investito in training e change management. Senza questo, gli strumenti vengono ignorati.
- Non coinvolgere il business: I data steward devono essere figure ibride business-tecnica, non solo IT. Il business sa quali dati sono critici, l'IT sa come misurarli.
- Ignorare la compliance fin dall'inizio: I requisiti AI Act non sono un vincolo: sono la struttura che giustifica l'investimento in governance agli occhi del management.
Best Practices e Anti-Pattern
Best Practices Fondamentali
- Quality as Code: Definisci i requisiti di qualità nel codice (YAML, Python) versionato in Git, non in documenti Word. Questo rende i check automatici, riproducibili e parte del processo di CI/CD.
- Fail Fast, Fail Loud: I check di data quality devono bloccare la pipeline (non solo generare un warning) quando i dati sono fuori soglia. Un modello addestrato su dati scadenti causa danni peggiori di una pipeline ferma.
- Separate Validation da Transformation: Valida i dati prima di trasformarli (validazione schema e range a ingestion), durante la trasformazione (test dbt nei modelli), e prima dell'uso in ML (Great Expectations sul feature store). La qualità si verifica in più punti, non solo alla fine.
- Monitora il Drift, Non Solo la qualità Statica: I dati cambiano nel tempo. PSI (Population Stability Index) e test KS (Kolmogorov-Smirnov) sono strumenti standard per rilevare derive distribuzionali che degradano i modelli silenziosamente.
- Documenta le Decisioni di Governance: Ogni scelta (soglia di qualità, strategia di imputation, esclusione di un dataset) deve essere documentata con data, autore e razionale. Questa documentazione e richiesta dall'AI Act per i sistemi high-risk.
Anti-Pattern da Evitare
Anti-Pattern Critici nella Data Governance per AI
- Data quality "best effort": Definire SLA vaghi ("dati il più possibile completi") invece di soglie numeriche precise e misurabili. Senza metriche, non c'e governance reale.
- Silencing degli alerts: Configurare i check di qualità e poi silenziare gli alert perchè "disturbano". Ogni alert ignorato e un futuro problema di modello in produzione.
- Governance solo per i nuovi progetti: I dataset legacy usati per riaddestramento dei modelli hanno gli stessi requisiti di qualità. Spesso sono i più problematici.
- Bias check "one-shot": Verificare il bias solo prima del training iniziale. Il bias può emergere con i nuovi dati di produzione nel tempo (concept drift).
- Confondere data quality per analytics e per ML: Soglie accettabili per un dashboard (5% null in una colonna) possono essere catastrofiche per un feature di input ML. I due contesti richiedono standard diversi.
Conclusioni e Next Steps
La data governance e la data quality per AI non sono burocrazia: sono l'infrastruttura invisibile che determina se i tuoi modelli funzionano in produzione o falliscono silenziosamente. Con l'AI Act EU che porta requisiti legalmente vincolanti sui dati di training, investire in governance non e solo una buona pratica - e un prerequisito per operare nel mercato europeo con sistemi AI ad alto rischio.
Il punto di partenza pratico per qualsiasi organizzazione - PMI o enterprise - e lo stesso: identifica i 3-5 dataset più critici per le tue iniziative AI, nomina un data steward per ognuno, implementa i check automatici con gli strumenti open source descritti in questo articolo (Great Expectations, dbt-expectations, Soda Core), e costruisci gradualmente la struttura di governance attorno a questi dataset.
La perfezione non e il requisito iniziale: il 94% di data quality score raggiunto dalla PMI manifatturiera del nostro case study dopo 12 mesi e partita dal 61%. Il viaggio conta quanto la destinazione, e ogni punto percentuale di miglioramento della qualità dei dati si traduce direttamente in modelli AI più affidabili, meno incidenti in produzione, e decisioni aziendali più solide.
Checklist Avvio Programma Data Governance per AI
- Inventario dei dataset critici per AI completato
- Data steward nominati per ogni dominio dati chiave
- SLA di qualità definiti e approvati (completeness, freshness, validity)
- Check automatici implementati in pipeline (GE, dbt-expectations o Soda)
- Data catalog con lineage configurato (OpenMetadata o Apache Atlas)
- Bias assessment eseguito per tutti i dataset usati in sistemi high-risk
- Documentazione AI Act Art. 10 per sistemi high-risk avviata
- Alerting configurato e canali di escalation definiti
- Primo Data Council mensile pianificato
- Formazione al team completata
Approfondimenti Correlati
- MLOps per Business: Come monitorare il drift dei modelli in produzione con MLflow - Articolo #12 di questa serie
- LLM in Azienda: Data governance per RAG enterprise e sicurezza dei dati nei Large Language Models - Articolo #10 di questa serie
- AI Engineering: Feature store e embedding governance per sistemi RAG enterprise - Serie AI Engineering
- PostgreSQL AI: pgvector e data quality per vector databases - Serie PostgreSQL AI







