IA air-gapped: ejecutar LLM completamente offline con Ollama
Una arquitectura práctica para IA sin conectividad saliente: Ollama como LLM local, LanceDB para vectores, redacción DLP en cada prompt, todo en un contenedor offline.
Por qué el air-gap es una forma de despliegue, no un flag de funcionalidad
La mayoría de los productos de IA «self-hosted» siguen filtrando datos. Una llamada a una API de modelo aquí, una petición de embedding allá, un ping de telemetría, una verificación de licencia que llama a casa - cada uno defendible por separado, y en conjunto significan que tus documentos internos, prompts y respuestas cruzan una frontera de red que no controlas. Para contratistas de defensa, hospitales, bancos y cualquier organización con un mandato de residencia de datos, eso es descalificatorio. El requisito no es «casi offline» - es un sistema de IA que funcione con el cable de red desconectado.
Simmetric Chat está construido en torno a ese requisito. El funcionamiento air-gapped no es un modo que desbloqueas ni un plugin que compras: la configuración por defecto de la plataforma comunitaria ya es la offline - un LLM local, embeddings locales, un store vectorial local basado en archivos y una pipeline documental que nunca necesita Internet. Este artículo recorre cada capa que hace funcionar la conectividad cero saliente, y a qué renuncias - muy poco - al cerrar el perímetro.
La pila local: cada capa tiene un default offline
Un chat de IA tiene cuatro dependencias externas en una arquitectura SaaS típica: el modelo de lenguaje, el modelo de embedding, el store vectorial y la pipeline documental. Los defaults de Simmetric Chat sustituyen las cuatro por componentes locales:
- El LLM corre en Ollama. El provider por defecto de la plataforma es Ollama en la red local, y el modelo por defecto (
gemma4:latest) se descarga en el momento de la instalación para que el chat funcione antes de cualquier descarga de modelo en tiempo de ejecución. Ollama habla HTTP compatible con OpenAI en tu propia red, y la configuración del provider apunta a él con una URL - no un endpoint cloud. - Los embeddings corren en local. El provider de embedding por defecto es un modelo transformers local (384 dimensiones, ejecutado in-process en el collector), no una API de embeddings alojada. Los embeddings locales son compatibles con air-gap por construcción, y la guarda de mismatch de embeddings significa que cambiar entre providers locales y remotos después es seguro - el retrieval degrada a búsqueda por palabras clave hasta que termina la re-indexación, en lugar de servir puntuaciones de espacios mezclados.
- Los vectores viven en LanceDB. El store vectorial por defecto está basado en archivos, guardado en el directorio de almacenamiento del propio despliegue, con una colección por workspace. Sin servidor de base de datos vectorial, sin salto de red. Qdrant, pgvector y Chroma siguen disponibles para equipos cuya escala exige un índice en red, pero nada los requiere.
- El parseo de documentos ocurre en tu red. El collector - el servicio que parsea, trocea y embebe las subidas - forma parte de tu despliegue. PDFs, archivos Word y Excel, presentaciones y transcripciones de YouTube se procesan dentro del perímetro, incluidos los documentos escaneados que pasan por la pipeline OCR con modelo de visión del lado del servidor, que usa un modelo de visión local.
Nada de esa lista está tratado de forma especial ni añadido a posteriori. El patrón de estrategia en cada frontera hace que la opción local sea simplemente el provider por defecto, seleccionado por configuración como cualquier otro.
DLP: redacción antes de que algo salga - o antes incluso de que se mueva
Cerrar la conectividad saliente no cierra todos los caminos de exfiltración, porque el contenido también se mueve dentro de tu red: los prompts entran en la plataforma, las respuestas salen hacia los usuarios, y ambos pasan por interfaces de chat de las que la gente copia. El filtro de data-loss-prevention de Simmetric Chat escanea ambas direcciones - el prompt entrante y la respuesta saliente, incluidos los flushes de streaming token a token - y redacta las coincidencias antes de que el contenido se almacene o se muestre.
El escáner reconoce las clases de PII que importan en un contexto de chat: direcciones de correo, números de tarjeta de crédito, claves API y claves privadas, y - añadidos en v0.22 - identificadores europeos estructurados: Partita IVA italiana, codice fiscale e IBAN, sembrados como patterns integrados idempotentes y anclados a la etiqueta para que los números ordinarios nunca los activen. La configuración de patterns la gestiona el admin y está respaldada por base de datos: activa o desactiva cualquier pattern, añade hasta cincuenta patterns personalizados con validación de compilación en vivo y vista previa de prueba, e inspecciona un panel de historial de coincidencias filtrado por origen.
La intención de diseño es que el DLP sea la última línea, no la primera. La primera línea es la arquitectura: con modelos locales, embeddings locales y vectores locales, no hay ningún endpoint de terceros al que pueda llegar contenido sensible en primer lugar. El DLP cubre entonces los caminos que quedan - contenido que sale de la plataforma hacia tus propios usuarios, o que un empleado bienintencionado pega en un prompt. También cubre la superficie del widget, de modo que las conversaciones dirigidas a visitantes en tu web se redactan con la misma cadena de filtros, con la traza de auditoría distinguiendo el tráfico de chat del de widget.
El despliegue en contenedor único: todo en un host
Cerrar el perímetro es una cosa; llevar el software a un perímetro es otra. Los entornos air-gap normalmente no pueden ejecutar cómodamente un stack compose de cinco servicios - ejecutan un host con una sola imagen, y cuantas menos partes móviles, menos artefactos hay que verificar y transferir.
Simmetric Chat envía una imagen all-in-one en contenedor único exactamente para este caso. Un contenedor, supervisado por un gestor de procesos, lo ejecuta todo: PostgreSQL 16 (con la extensión pgvector compilada desde el código fuente en el build de la imagen, así que instalada offline), el servidor API, el collector documental y el servicio widget. El contenedor expone tres puertos - 3000 para la API, 3210 para el collector, 3211 para el widget - y monitorea su propio endpoint /api/health, que informa del estado de la base de datos, el collector y el disco.
Meter la imagen dentro es la misma disciplina que con cualquier otro artefacto: transfiere el tarball de la imagen (o el espejo de registry que hayas verificado), cárgala y ejecútala. Los valores por defecto de entorno de la imagen son placeholders de andamiaje - producción sobrescribe JWT_SECRET, COLLECTOR_SECRET y la clave de cifrado mediante la configuración de entorno, y el servidor falla en voz alta al arrancar si faltan los secretos de producción, para que un despliegue air-gap a medio configurar nunca arranque en silencio. Tras el arranque, las actualizaciones de software son nuevas versiones de imagen, no instalaciones de paquetes - no se requiere acceso a Internet en ningún punto del ciclo de vida.
# Transfiere dentro del perímetro, luego:
docker load -i simmetric-chat-all-in-one.tar
docker run -d \
-p 3000:3000 -p 3210:3210 -p 3211:3211 \
-v simmetric-storage:/app/storage \
-e JWT_SECRET=$(openssl rand -hex 32) \
-e COLLECTOR_SECRET=$(openssl rand -hex 32) \
simmetric-chat:all-in-oneLos pesos de los modelos siguen el mismo camino. Los modelos Ollama se descargan en una máquina conectada, se guardan como blobs y se importan dentro del perímetro - la plataforma los trata después como cualquier otro modelo local. Nada en el stack llama a casa para verificar un modelo, una licencia o a sí mismo: la telemetría está desactivada por defecto, no hay dependencia externa de reporte de errores, y la validación de licencia es una comprobación local de firma RS256 contra una clave pública embebida.
Qué sigue funcionando offline - y qué falta de verdad
Un despliegue air-gapped debería ser honesto sobre sus márgenes. Qué funciona con conectividad cero saliente:
- Chat con LLM locales a través de Ollama, en streaming token a token por SSE
- Subida e ingestión de documentos - parseo, chunking, embeddings locales, vectores LanceDB
- Retrieval híbrido con citas, filtrado por metadatos y pipelines de síntesis
- RBAC, workspaces, proyectos, trazas de auditoría y toda la superficie de administración
- Webhooks (entregados a tus propios receptores), Web Push (VAPID desde tu propio servidor) y claves API
- El widget embebible, ejecutándose contra tu propio servicio widget
Qué falta de verdad: providers LLM cloud, embeddings alojados, búsqueda web externa y cualquier otra cosa que requiera una llamada saliente. El diseño de degradación graciosa significa que cada una de esas integraciones es un añadido de configuración, no un cambio de código - pero el default offline se envía simplemente sin ellas. La plataforma arranca, sirve peticiones y procesa documentos de forma idéntica tanto si el perímetro está abierto como si está cerrado.
El resultado es un workspace de IA cuya postura de seguridad no depende de confiar en la gestión de datos de un proveedor, porque no hay ningún proveedor en la ruta de los datos. Todo lo que toca tus documentos - el modelo, los embeddings, el índice vectorial, el parser - corre en hardware que posees, dentro de una red que controlas, en una imagen de contenedor que puedes auditar.
