Pràctica PR5073/03: Dashboard d'IA amb Metabase
Objectius
- Desplegar Metabase amb Docker Compose i PostgreSQL
- Dissenyar i crear una base de dades de prediccions d'IA
- Connectar Metabase a la base de dades del model
- Construir preguntes amb Query Builder i SQL natiu
- Crear un dashboard de monitoratge complet
- Configurar alertes i compartir el dashboard
Prerequisits
| Requisit | Detall |
|---|---|
| Temps estimat | 8 hores |
| RAM mínima | 4 GB |
| Docker Desktop | v4.25+ instal·lat i funcionant |
| Coneixements | SQL bàsic, conceptes de models d'IA |
Introducció
En aquesta pràctica construiràs un sistema complet de monitoratge d'un model d'IA fictici (predicció de churn de clients) utilitzant Metabase com a eina de visualització.
Simularàs les dades que un model en producció real generaria i construiràs el dashboard que un equip de dades i una direcció empresarial necessitaria per prendre decisions.
Fase 1: Preparar l'entorn Docker
1.1 Estructura de directoris
1.2 Docker Compose
Crea el fitxer docker-compose.yml:
version: '3.8'
services:
# Base de dades per a les dades del model d'IA
ia-db:
image: postgres:16-alpine
container_name: ia-db-[el-teu-nom]
environment:
POSTGRES_DB: ia_produccion
POSTGRES_USER: ia_admin
POSTGRES_PASSWORD: ia_password_2025
volumes:
- ./init-sql:/docker-entrypoint-initdb.d
- ia_db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ia_admin -d ia_produccion"]
interval: 10s
timeout: 5s
retries: 5
# Base de dades per a la configuració de Metabase
metabase-db:
image: postgres:16-alpine
container_name: metabase-db-[el-teu-nom]
environment:
POSTGRES_DB: metabase
POSTGRES_USER: metabase
POSTGRES_PASSWORD: metabase_password_2025
volumes:
- metabase_db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U metabase"]
interval: 10s
timeout: 5s
retries: 5
# Metabase
metabase:
image: metabase/metabase:latest
container_name: metabase-[el-teu-nom]
ports:
- "3000:3000"
environment:
MB_DB_TYPE: postgres
MB_DB_DBNAME: metabase
MB_DB_PORT: 5432
MB_DB_USER: metabase
MB_DB_PASS: metabase_password_2025
MB_DB_HOST: metabase-db
MB_SITE_URL: http://localhost:3000
depends_on:
metabase-db:
condition: service_healthy
ia-db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "--fail", "-I", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 5
start_period: 90s
volumes:
ia_db_data:
metabase_db_data:
1.3 Script SQL d'inicialització
Crea el fitxer init-sql/01_schema.sql:
-- Esquema per a les dades del model d'IA
-- Taula de models
CREATE TABLE models (
id SERIAL PRIMARY KEY,
nom VARCHAR(100) NOT NULL,
versio VARCHAR(20) NOT NULL,
tipus VARCHAR(50) NOT NULL, -- classificacio, regressio, nlp...
actiu BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT NOW()
);
-- Taula de prediccions
CREATE TABLE prediccions (
id SERIAL PRIMARY KEY,
model_id INTEGER REFERENCES models(id),
client_id INTEGER NOT NULL,
prediccio VARCHAR(50) NOT NULL, -- 'churn' o 'no_churn'
valor_real VARCHAR(50), -- NULL fins que es confirma
confianca FLOAT NOT NULL, -- 0.0 a 1.0
correcta BOOLEAN, -- NULL fins que es confirma
latencia_ms INTEGER NOT NULL,
segment_client VARCHAR(50), -- premium, standard, basic
regio VARCHAR(50),
created_at TIMESTAMP NOT NULL
);
-- Índexs per a millor rendiment
CREATE INDEX idx_pred_model ON prediccions(model_id);
CREATE INDEX idx_pred_created ON prediccions(created_at);
CREATE INDEX idx_pred_correcta ON prediccions(correcta);
-- Usuari de només lectura per a Metabase
CREATE USER metabase_ro WITH PASSWORD 'metabase_ro_2025';
GRANT CONNECT ON DATABASE ia_produccion TO metabase_ro;
GRANT USAGE ON SCHEMA public TO metabase_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO metabase_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO metabase_ro;
Crea el fitxer init-sql/02_data.sql per generar dades de prova:
-- Inserir models
INSERT INTO models (nom, versio, tipus) VALUES
('Predictor Churn v1', '1.0.0', 'classificacio'),
('Predictor Churn v2', '2.1.3', 'classificacio'),
('Segmentador Clients', '1.2.0', 'classificacio');
-- Generar 90 dies de prediccions (script PL/pgSQL)
DO $$
DECLARE
segments VARCHAR[] := ARRAY['premium', 'standard', 'basic'];
regions VARCHAR[] := ARRAY['nord', 'sud', 'est', 'oest', 'centre'];
pred VARCHAR;
real_v VARCHAR;
conf FLOAT;
correcta BOOLEAN;
lat INTEGER;
i INTEGER;
dia TIMESTAMP;
model_id INTEGER;
BEGIN
FOR day_offset IN 0..89 LOOP
dia := NOW() - (day_offset || ' days')::INTERVAL;
-- Model v2 (actiu, 80 prediccions/dia)
FOR i IN 1..80 LOOP
conf := 0.60 + random() * 0.39;
-- Accuracy decreix lleugerament en els últims 7 dies (drift)
IF day_offset < 7 THEN
correcta := random() < 0.88;
ELSE
correcta := random() < 0.94;
END IF;
IF random() < 0.23 THEN
pred := 'churn';
ELSE
pred := 'no_churn';
END IF;
IF correcta THEN
real_v := pred;
ELSIF pred = 'churn' THEN
real_v := 'no_churn';
ELSE
real_v := 'churn';
END IF;
lat := 80 + (random() * 300)::INTEGER;
IF day_offset < 3 THEN lat := lat + 150; END IF; -- latència alta recent
INSERT INTO prediccions (
model_id, client_id, prediccio, valor_real, confianca,
correcta, latencia_ms, segment_client, regio, created_at
) VALUES (
2,
(1000 + (random() * 9000)::INTEGER),
pred,
real_v,
ROUND(conf::NUMERIC, 4),
correcta,
lat,
segments[1 + (random() * 2)::INTEGER],
regions[1 + (random() * 4)::INTEGER],
dia + (random() * INTERVAL '23 hours')
);
END LOOP;
-- Model v1 (antic, 30 prediccions/dia, menys accuracy)
FOR i IN 1..30 LOOP
conf := 0.55 + random() * 0.35;
correcta := random() < 0.87;
IF random() < 0.25 THEN pred := 'churn'; ELSE pred := 'no_churn'; END IF;
IF correcta THEN real_v := pred;
ELSIF pred = 'churn' THEN real_v := 'no_churn';
ELSE real_v := 'churn'; END IF;
INSERT INTO prediccions (
model_id, client_id, prediccio, valor_real, confianca,
correcta, latencia_ms, segment_client, regio, created_at
) VALUES (
1,
(1000 + (random() * 9000)::INTEGER),
pred, real_v,
ROUND(conf::NUMERIC, 4),
correcta,
100 + (random() * 500)::INTEGER,
segments[1 + (random() * 2)::INTEGER],
regions[1 + (random() * 4)::INTEGER],
dia + (random() * INTERVAL '23 hours')
);
END LOOP;
END LOOP;
END $$;
Fase 2: Engegar i configurar Metabase
# Engegar tots els serveis
docker compose up -d
# Esperar ~90 segons i comprovar
docker compose logs metabase | tail -20
Obre http://localhost:3000 i configura el compte d'administrador.
2.1 Connectar la base de dades d'IA
- Admin → Databases → Add a database
- Selecciona: PostgreSQL
- Configuració:
Display name: Prediccions Model Churn
Host: ia-db
Port: 5432
Database name: ia_produccion
Username: metabase_ro
Password: metabase_ro_2025
- Fes clic a Save i espera que la connexió es verifiqui.
Fase 3: Crear les preguntes
Crea les següents preguntes a Metabase i guarda-les a una col·lecció PR5073/03 - [el teu nom].
Pregunta 1: Accuracy del model v2 per dia (Query Builder)
- Font:
prediccions - Filtra:
model_id = 2icreated_at >= últims 30 dies - Agrupa per:
created_at(per dia) - Mètrica:
% de correcta = true - Visualització: Línia
- Afegeix una línia de referència a 0.90 (90%)
Pregunta 2: Comparació d'accuracy entre models (SQL)
SELECT
m.nom AS model,
DATE_TRUNC('week', p.created_at) AS setmana,
COUNT(*) AS total,
ROUND(AVG(CASE WHEN p.correcta THEN 1.0 ELSE 0.0 END)::NUMERIC, 3) AS accuracy,
ROUND(AVG(p.confianca)::NUMERIC, 3) AS confianca_mitjana
FROM prediccions p
JOIN models m ON p.model_id = m.id
WHERE p.created_at >= NOW() - INTERVAL '60 days'
GROUP BY 1, 2
ORDER BY 2 DESC, 1;
Visualització: Línia amb múltiples sèries (una per model)
Pregunta 3: Distribució de prediccions per segment (Query Builder)
- Font:
prediccions - Filtra:
model_id = 2icreated_at: últims 7 dies - Agrupa per:
segment_client - Mètrica:
COUNTi% correcta - Visualització: Barres agrupades
Pregunta 4: Latència P95 per dia (SQL)
SELECT
DATE_TRUNC('day', created_at) AS dia,
ROUND(PERCENTILE_CONT(0.50) WITHIN GROUP (ORDER BY latencia_ms)::NUMERIC, 0) AS p50_ms,
ROUND(PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY latencia_ms)::NUMERIC, 0) AS p95_ms,
MAX(latencia_ms) AS max_ms
FROM prediccions
WHERE model_id = 2
AND created_at >= NOW() - INTERVAL '30 days'
GROUP BY 1
ORDER BY 1;
Visualització: Línia. Afegeix línia de referència a 500ms.
Pregunta 5: KPI Accuracy actual (número)
- Font:
prediccions - Filtra:
model_id = 2icreated_at: avui - Mètrica:
% correcta = true - Visualització: Número (gran, centrat)
Pregunta 6: Taula d'errors recents (SQL)
SELECT
p.created_at,
p.client_id,
p.prediccio,
p.valor_real,
ROUND(p.confianca::NUMERIC, 3) AS confianca,
p.segment_client,
p.regio
FROM prediccions p
WHERE p.model_id = 2
AND p.correcta = FALSE
AND p.created_at >= NOW() - INTERVAL '7 days'
ORDER BY p.created_at DESC
LIMIT 50;
Visualització: Taula
Fase 4: Construir el dashboard
- Nou → Dashboard → Nom:
Monitor Model Churn - PR5073/03 [nom] - Afegeix totes les preguntes creades
- Organitza el layout:
[KPI Accuracy] [KPI Total pred.] [KPI Latència P95] [KPI % Churn]
[─────────────────────────────────────────────────────────────────────]
[Accuracy per dia — últims 30d (línia) | Per segment (barres) ]
[─────────────────────────────────────────────────────────────────────]
[Comparació v1 vs v2 (línia multi-sèrie) ]
[─────────────────────────────────────────────────────────────────────]
[Latència P50/P95 (línia) | Errors recents (taula) ]
- Afegeix filtres globals:
- Data: rang de dates (connectat a totes les preguntes)
-
Model: selecció de model (connectat a les preguntes que filtren per model_id)
-
Guarda el dashboard.
Fase 5: Alertes i subscripcions
Alerta d'accuracy baixa
- Obre la pregunta "KPI Accuracy actual"
- Fes clic a la campaneta (Alerts) → Create an alert
- Configura:
- Condició:
Valor < 0.90 - Freqüència: cada hora
- Notificació: al teu email
Subscripció setmanal
- Obre el dashboard
- Subscriptions → Email it
- Configura:
- Recipients: el teu email
- Freqüència: setmanal, dilluns a les 8:00
- Format: PDF
Lliurament
Lliura al campus virtual:
- Fitxer
docker-compose.yml - Fitxers SQL d'inicialització (
init-sql/) - Captura del dashboard complet (tots els cards visibles)
- Captura de cada una de les 6 preguntes amb les dades i la visualització
- Captura de la configuració de l'alerta d'accuracy
- Captura de la configuració de la subscripció setmanal
- Captura de la URL pública del dashboard (si l'habilites)
- Document de reflexió (max 1 pàgina):
- Per quin ús real d'IA seria útil aquest dashboard?
- Quines mètriques afegiries si fos un projecte real?
- Quan triaries Power BI en lloc de Metabase?
Rúbrica d'avaluació
Veure Rúbrica PR5073/03