Inteligencia Artificial · Serie LLMs y n8n
Privacidad, PII y cumplimiento: buenas prácticas al trabajar con datos sensibles
Un asistente útil no tiene por qué ser indiscreto. Con minimización, cifrado, controles de acceso y retención adecuada, reduces riesgo sin perder valor.
En el post anterior optimizamos costos. Ahora toca proteger lo que más importa: datos personales y sensibles. Este guía es técnica (Laravel + n8n) y pragmática: lo mínimo para operar con responsabilidad.
Clasifica antes de procesar
- Pública: textos y FAQs sin restricciones.
- PII (identificable): nombre, email, teléfono, dirección, identificaciones.
- Sensible: salud, biométricos, financieros (tarjetas), menores, credenciales.
- Confidencial empresarial: secretos, contratos, claves, IDs internos.
Regla de oro: si no necesitas el dato, no lo recolectes. Si lo recolectas, limítalo y bórralo cuando cumpla su propósito.
Mapa de flujo de datos (MVP)
- Entrada → normaliza y detecta PII.
- RAG → solo colecciones allowlist; anonimiza antes de indexar.
- LLM → contrato de salida; sin PII innecesaria en prompts.
- Salida → guardrails de salida (post #16) con redacción si aparece PII.
- Logs/Trazas → redactados y con retención limitada.
Controles técnicos clave
1) Redacción de PII en la entrada y en logs
// app/Support/Pii.php
function redact(string $t): string {
$patterns = [
'/[\\w._%+-]+@[\\w.-]+\\.[A-Za-z]{2,7}/' => '[EMAIL]',
'/\\+?\\d[\\d\\s().-]{7,}/' => '[PHONE]',
'/\\b\\d{13,19}\\b/' => '[CARD]',
];
return array_reduce(array_keys($patterns), fn($s,$k)=>preg_replace($k,$patterns[$k],$s), $t);
}
// app/Http/Middleware/RedactInput.php
public function handle($req, Closure $next) {
$all = $req->all();
array_walk_recursive($all, fn(&$v)=>$v=is_string($v)?redact($v):$v);
$req->merge($all);
return $next($req);
}
2) Cifrado en reposo (modelo Eloquent)
// app/Casts/EncryptedJson.php
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Support\Facades\Crypt;
class EncryptedJson implements CastsAttributes {
public function get($model, string $key, $value, array $attrs) {
return $value ? json_decode(Crypt::decryptString($value), true) : null;
}
public function set($model, string $key, $value, array $attrs) {
return ['attributes' => [$key => Crypt::encryptString(json_encode($value))]];
}
}
// app/Models/Conversation.php
class Conversation extends Model {
protected $casts = ['payload' => EncryptedJson::class];
}
3) Logs sin secretos (processor de Monolog)
// app/Logging/SanitizeProcessor.php
class SanitizeProcessor {
public function __invoke(array $record) {
$s = json_encode($record['context']);
$s = redact($s ?? '');
$record['context'] = json_decode($s, true) ?? [];
return $record;
}
}
// config/logging.php (canal "app")
'processors' => [App\Logging\SanitizeProcessor::class],
4) Política de retención
// app/Console/Commands/PurgeTelemetry.php
public function handle() {
DB::table('llm_metrics')->where('created_at','<',now()->subDays(30))->delete();
}
Ejecuta por cron (n8n/CRON o scheduler de Laravel). Mantén retenciones distintas para métricas vs. contenidos.
5) Embeddings SIN PII cruda
- Anonimiza con surrogates (“[CLIENTE_123]”) antes de vectorizar.
- Guarda un mapping seguro (tabla aparte, cifrada) para rehidratar solo si es imprescindible.
Acceso y permisos
- Scopes y roles (API keys con permisos mínimos).
- ABAC (atributos): tenant, país, sensibilidad del dato.
- Registro de accesos con
request_idy reason codes (auditoría).
Solicitudes de sujetos de datos (DSR): acceso/borrado/export
// routes/api.php
Route::post('/privacy/export', ExportDataController::class)->middleware('auth:api');
Route::delete('/privacy/delete', DeleteDataController::class)->middleware('auth:api');
// app/Jobs/DeleteUserData.php
public function handle() {
DB::transaction(function() {
Conversation::where('user_id',$this->userId)->delete();
DB::table('llm_metrics')->where('user_id',$this->userId)->delete();
});
}
Responde con plazos, confirma recepción y registra el cumplimiento (fecha, alcance, excepción si aplica).
Micro-workflows n8n útiles
1) “PII Guard” en la entrada
- Webhook → recibe
{query, userId}. - Function → aplica redacción (regex/NER) y clasifica riesgo.
- IF → si riesgo alto → “modo seguro” (post #16) o revisión humana.
- HTTP → envía al backend redaccionado.
- Database → registra risk_level y pii_types (sin ejemplos crudos).
2) “DSR Manager”
- Form Trigger → recibe solicitud de usuario.
- HTTP → crea ticket y dispara Export/Delete.
- Wait + Notifier → confirma cumplimiento al usuario.
Políticas mínimas (no asesoría legal)
- Propósito definido por caso de uso; no “todo vale”.
- Base legal/consentimiento cuando aplique; registra fecha y alcance.
- Privacy by design: minimiza, anonimiza, cifra y borra a tiempo.
- Acuerdos con terceros (proveedor LLM): asegúrate de contrato y región de datos.
Métricas operativas de privacidad
- % prompts redaccionados y tipos de PII detectados.
- Tiempo de respuesta DSR y tasa de cumplimiento.
- Incidentes por fuga/violación de políticas.
- Retención efectiva: filas purgadas por día/colección.
Anti-patrones
- Registrar prompts crudos y completions sin redacción.
- Indexar en vector DB PII sin anonimizar.
- Retención infinita “por si acaso”.
- Compartir datasets con claves/API keys o URLs internas.
Conclusión
Privacidad efectiva = menos datos + datos mejor protegidos + operación medible. Con redacción, cifrado, acceso mínimo y retención, tu asistente será útil y respetuoso.
← Anterior: Cost engineering: cómo reducir el gasto de tu sistema de IA