Un arnés de agentes en el móvil: DeepSeek Harness contra tu modelo local, con avisos de aprobación
DSH es el arnés agéntico oficial de DeepSeek: sesiones, planes, subagentes y herramientas. Lo tenemos en la GX10 y en el portátil, apuntando al modelo residente, y lo usamos desde el iPhone. Arquitectura, relay con clave propia y las trampas del camino.
Un arnés es el programa que convierte un modelo en un agente: le da herramientas (leer
ficheros, ejecutar comandos, buscar en la web), gestiona sesiones y planes, y te pide permiso
antes de hacer algo delicado. DeepSeek Harness (dsh) es el oficial de DeepSeek, está en
developer preview y tiene una interfaz web muy cuidada.
Nosotros no lo usamos con la API de DeepSeek: lo apuntamos a nuestro propio modelo, el que esté residente en las GX10 en ese momento. Y lo usamos, sobre todo, desde el móvil.
La arquitectura, salto a salto
iPhone / Mac
└► https://agente.tudominio.es Cloudflare + Nginx del servidor + TLS
└► Tailscale Serve :9080 solo dentro de la red privada
└► portátil 127.0.0.1:3082 bridge: login, PWA, avisos de aprobación
└► portátil 127.0.0.1:3080 DSH, fijado a una versión concreta
└► GX10 :8110 /gx10-1/v1 relay privado: solo acepta la IP del portátil
└► GX10 127.0.0.1:8099/v1 gateway del laboratorio
└► modelo residente (el que haya elegido Mission Control)
Parece una torre de Babel. En realidad son tres capas que ya conoces de la serie: publicación (guía 3), arnés (esta guía) y modelo (guía 10).
¿Por qué el arnés en el portátil y el modelo en la GX10?
Porque los proyectos están en el portátil y los pesos en la GX10. El arnés tiene que
estar donde puede leer y editar tu código; el modelo, donde hay 128 GB de memoria. El portátil
no carga ni un byte del modelo: usa un alias, gx10-local, y la GX10 decide qué hay detrás.
Consecuencia agradable: cuando rotamos el modelo desde Mission Control, el arnés no se
entera. Sigue hablando con gx10-local y el gateway enruta al nuevo residente. Durante la
rotación las peticiones reciben un 503 deliberado; al terminar, vuelven a funcionar.
El relay: una clave distinta para cada tramo
Entre el portátil y la GX10 hay un relay pequeño. Existe por dos motivos:
- Solo acepta peticiones desde la IP de Tailscale del portátil. Cualquier otro dispositivo de la red recibe un rechazo.
- Tiene su propia clave. El portátil presenta la clave del relay; el relay la cambia por la del gateway. El portátil nunca conoce la clave del gateway y el relay nunca devuelve su clave al cliente.
Esto nos costó una tarde de confusión, así que lo dejamos escrito: hay tres credenciales
distintas en juego (la del gateway, la del relay y la de cada modelo detrás del gateway).
Apuntar el arnés directo al gateway con la clave del relay da api key invalid. Y peor: fijar
por error la clave equivocada en una variable de entorno del portátil no rompe nada en
caliente —el proceso vivo conserva su entorno— pero al primer reinicio lo tumba.
El bridge: lo que hace que se use de verdad desde el móvil
Además del login de 30 días y la reescritura de Host de la guía 3, nuestro bridge para DSH
hace tres cosas específicas:
- Fuerza la interfaz en inglés. DSH solo tiene chino e inglés; un Safari configurado en español cae en chino y la preferencia no se puede guardar desde fuera de loopback (P-073). El bridge declara inglés antes de que cargue el cliente.
- Reescribe las URL
127.0.0.1que genera el agente. Si el agente crea un HTML y arranca un servidorcito en127.0.0.1:8765, esa URL en el iPhone apunta… al iPhone (P-075). El bridge sirve esas previsualizaciones por su propia ruta. - Avisa cuando un agente pide permiso. Detecta el mensaje nativo de «aprobación solicitada» del WebSocket de DSH y muestra una tarjeta amarilla fija arriba, cambia el título de la pestaña y, si lo has permitido, lanza una notificación del sistema.
El aviso nunca aprueba ni rechaza nada por sí mismo: la decisión sigue siendo tuya, en el diálogo de DSH. Y tiene un límite honesto: funciona mientras la web esté abierta. Avisar con la app totalmente cerrada requiere Web Push con un emisor de servidor, y no lo hemos montado sin una revisión de seguridad aparte.
En Windows: tareas, no servicios
En el portátil, DSH, el bridge y un pequeño buscador web local son tareas programadas que arrancan al iniciar sesión. Tres lecciones:
- Solo una tarea por puerto. Teníamos una tarea antigua que lanzaba otra copia del arnés
y la nueva fallaba con
EADDRINUSEen el 3080. La antigua quedó deshabilitada y respaldada. - Nada de parar en batería (P-090). Nos tumbó el acceso exterior entero al cambiar el portátil de habitación.
- Versión fijada. DSH está en preview y cambia mucho; el runtime vive en una carpeta aislada con la versión exacta y no se actualiza solo.
La búsqueda web, en local
DSH puede buscar en internet con un plugin. Lo montamos con un servicio local en
127.0.0.1:8899. Ojo con una cosa: algunas librerías de búsqueda en modo automático reparten
la consulta entre varios motores y dejan las consultas en sus logs (P-077).
Si te importa la privacidad, fija un único motor.
Comprobar que todo el camino está vivo
# portátil
Get-NetTCPConnection -State Listen | Where-Object LocalPort -in 3080,3082 |
Select-Object LocalAddress,LocalPort,OwningProcess
tailscale serve status
# desde cualquier sitio: sin sesión, HTML → login (200), API → 401
curl -sS -I -H 'Accept: text/html' https://agente.tudominio.es/
# portátil → GX10, leyendo la clave solo en memoria
$k = (Get-Content -Raw "$env:USERPROFILE\secretos\clave-relay").Trim()
(Invoke-WebRequest -UseBasicParsing -Uri http://100.x.y.z:8110/gx10-1/v1/models `
-Headers @{ Authorization = "Bearer $k" }).StatusCode # 200
Si los menús de configuración de DSH dan 403 desde fuera y funcionan en local, revisa la
reescritura de Host del bridge antes que ninguna otra cosa.
Siguiente: escritorio remoto en una máquina sin monitor.