Problema

Los asistentes basados en LLM que actúan de forma autónoma (agentic AI) necesitan acceder a datos de usuario para tareas como gestión de notas, correos o calendario. Cuando el modelo se ejecuta fuera de la UE, la transferencia de información personal viola GDPR y expone datos a legislaciones como el CLOUD Act. Las alternativas locales garantizan soberanía, pero el coste de hardware y el consumo energético pueden ser prohibitivos. En la práctica, muchos despliegues terminan mezclando varios proveedores: APIs chinas baratas, servicios estadounidenses costosos y modelos europeos con capacidades limitadas. El reto consiste en garantizar que cualquier dato sensible nunca abandone la frontera europea, sin sacrificar la calidad de los resultados ni la capacidad de encadenar herramientas (tool calling).

Causa

  1. Falta de separación lógica en la orquestación – La mayoría de los frameworks de agentes envían todas las peticiones al mismo endpoint, sin distinguir la sensibilidad del contenido.
  2. Ausencia de filtros PII automáticos – Los LLM no pueden confiarse a que respeten directivas de privacidad; sin un pre‑procesado, cualquier texto puede filtrarse a un modelo externo.
  3. Rutas de red indistintas – Cuando el contenedor que ejecuta el agente comparte la misma red que los proxies externos, no hay forma de bloquear tráfico saliente basado en la carga útil.
  4. Modelos europeos con capacidades reducidas – Los proveedores GDPR‑clean suelen ofrecer versiones “inference‑only” que no soportan llamadas a herramientas dinámicas, lo que obliga a usar modelos externos para flujos complejos.
  5. Configuraciones de hardware insuficientes – Ejecutar modelos de 30 B en CPUs de bajo consumo genera latencias que hacen inviable la interacción diaria.

Solución

Una arquitectura basada en capa de enrutamiento + filtro PII + orquestación separada permite cumplir con el privacy split sin depender de la buena voluntad del modelo.

1. Separar orquestadores por nivel de sensibilidad

  • Orquestador “público” (Docker compose o n8n) gestiona flujos que solo usan datos públicos (búsqueda web, generación de texto sin PII).
  • Orquestador “privado” (otro stack Docker o VM) ejecuta los agentes que manejan notas, correos o calendario. Este stack no tiene salida a internet excepto a través del proxy de filtrado.

2. Implementar un proxy de inspección (PII‑Gate)

Utiliza un contenedor Envoy o Traefik con un filtro Lua/Go que:

  1. Analiza la carga JSON antes de enviarla a un modelo externo.
  2. Busca patrones de PII (números de identificación, direcciones, correos) usando expresiones regulares o una pequeña modelo NER local (por ejemplo, spaCy).
  3. Si detecta PII, redirige la petición a un endpoint interno (modelo europeo o hardware local).
  4. Si no hay PII, permite el paso a la API externa (China o EE. UU.).

El proxy se coloca entre el orquestador privado y cualquier salida de red; el orquestador público puede conectar directamente a APIs externas porque no maneja datos sensibles.

3. Definir “rutas de modelo” en la configuración del agente

En el framework (por ejemplo, OpenClaw) agrega una regla de enrutamiento:

routes:
  - name: public
    model: anthropic/claude-3
    condition: "metadata.sensitivity == 'public'"
  - name: eu_local
    model: mistral-large
    condition: "metadata.sensitivity == 'eu'"
  - name: eu_hosted
    model: custom-eu-inference
    condition: "metadata.sensitivity == 'eu' && metadata.tool_calls == true"

Cada petición incluye un campo metadata.sensitivity que el orquestador asigna según la fuente de datos (NFS de notas = eu, búsqueda web = public). El proxy garantiza que la condición sea respetada incluso si el agente intenta cambiarla.

4. Persistencia de conocimiento en NAS con control de acceso

Montar la vault de Obsidian vía NFS en la VM privada y exportarla solo a los contenedores del orquestador privado. Configura exports con root_squash y rw limitado a la IP del host Proxmox. De esta forma, el orquestador público no puede montar el share y, por ende, no tiene acceso a la información personal.

5. Escalado de hardware según carga

  • Modelos ligeros (≤7 B) en CPUs con AVX2 pueden servir para tareas de clasificación y filtrado PII.
  • Modelos medianos (7‑13 B) en GPUs de consumo (Intel Arc B60) son suficientes para generación de texto de calidad aceptable.
  • Modelos grandes (≥30 B) solo se activan bajo demanda mediante torchrun en una VM dedicada; el resto del tiempo el agente delega en el modelo europeo.

6. Automatizar el despliegue con Terraform + Ansible

Mantén la infraestructura declarativa: Terraform crea la red, VMs y volúmenes; Ansible instala Docker, configura los contenedores de proxy, orquestadores y modelos. Así, cualquier reposición de hardware mantiene la misma topología y las reglas de privacidad no se pierden.

Cuándo aplicar esta solución

  • Necesitas cumplir con GDPR y evitar que cualquier dato personal salga de la UE.
  • Tu flujo incluye llamadas a herramientas (tool calling) que requieren modelos con capacidad de razonamiento multi‑step.
  • Cuentas con al menos un nodo con capacidad de red aislada (VM o contenedor sin salida directa a internet).
  • Los costos de hardware son limitados, pero puedes combinar modelos locales ligeros con APIs externas para contenido no sensible.

No es apropiado cuando:

  • Solo se usan modelos internos sin necesidad de tool calling.
  • La carga de trabajo es esporádica y el coste de una solución completa supera el beneficio.
  • No se manejan datos personales (por ejemplo, un bot de juegos).

Código

# Deploy PII‑Gate with Docker Compose
cat > docker-compose.yml <<'EOF'
version: "3.8"
services:
  proxy:
    image: envoyproxy/envoy:v1.28-latest
    ports:
      - "8080:8080"
    volumes:
      - ./envoy.yaml:/etc/envoy/envoy.yaml
      - ./pii_filter.lua:/etc/envoy/pii_filter.lua
    restart: unless-stopped
EOF

docker compose up -d
# Example Envoy Lua filter (pii_filter.lua)
function envoy_on_request(request_handle)
  local body = request_handle:body():getBytes(0, request_handle:body():length())
  if string.find(body, "%d%d%d%d%-%d%d%-%d%d") then
    request_handle:logInfo("PII detected, routing to EU model")
    request_handle:headers():replace(":authority", "eu-model.internal")
  end
end

Verificación

  1. Prueba de filtrado – Envía una petición con un número de identificación a través del proxy y verifica que el encabezado :authority cambie a eu-model.internal.
  2. Aislamiento de red – Desde la VM privada, ejecuta curl -s http://169.254.169.254/latest/meta-data/; debería fallar porque la salida está bloqueada por el proxy.
  3. Cadena de herramientas – Configura un flujo que invoque search_web (público) y add_calendar_event (privado). Observa que el primer paso usa la API externa y el segundo se enruta al modelo local sin salir de la red interna.
  4. Cumplimiento GDPR – Genera un informe de logs del proxy que muestre todas las redirecciones a modelos EU; revisa que no haya peticiones con PII hacia dominios fuera de la UE.

Notas adicionales

  • Mantén la lista de expresiones regulares del filtro PII actualizada; los patrones de datos personales varían según el país.
  • Si usas un modelo open‑weight hospedado en un proveedor EU, verifica que el contrato incluya cláusulas de procesamiento de datos bajo GDPR.
  • En entornos con varios usuarios, asigna un tenant_id en la metadata y crea reglas de enrutamiento por inquilino para evitar fugas cruzadas.
  • Monitorea la latencia del proxy; un filtro Lua mal optimizado puede añadir 50‑100 ms a cada llamada, lo que se vuelve perceptible en flujos largos.
  • Cuando el hardware local no pueda atender una carga pico, considera un “burst” a un modelo EU en la nube mediante un túnel VPN que también pase por el proxy.