Modelos autoalojados

Takuto Core puede manejar un servidor de modelos autoalojado y compatible con OpenAI — LM Studio, Ollama, vLLM y similares — a través del proveedor OpenCode. Esto mantiene el código fuente y los prompts enteramente en infraestructura que tú controlas. Esta página cubre el setup y los modos de fallo con los que nos topamos al conectar LM Studio con Docker Desktop, para que no tengas que volver a deducirlos.

Cada ajuste de abajo es editable desde Configuración → AI Settings → OpenCode en el dashboard. No hace falta editar config.toml a mano.

Setup básico

  1. Fija el proveedor en OpenCode en Configuración → AI Settings.

  2. Fija el campo Model. El flag -m de OpenCode espera <providerId>/<modelId>, y la configuración generada por Takuto Core siempre nombra al proveedor self_hosted, así que el valor debe verse así:

    self_hosted/<model-id-as-reported-by-the-server>
    Id de modelo reportado por el servidorFija en Takuto
    qwen/qwen2.5-vl-7bself_hosted/qwen/qwen2.5-vl-7b
    lmstudio-community/Llama-3.1-8B-Instruct-GGUFself_hosted/lmstudio-community/Llama-3.1-8B-Instruct-GGUF
  3. Fija la Base URL al endpoint compatible con OpenAI, incluido el /v1 final:

    http://host.docker.internal:1234/v1
  4. Si tu servidor no necesita una API key real (LM Studio y Ollama normalmente no), marca Allow shared default token para que Takuto Core inyecte un bearer de marcador.

  5. Fija Context limit / Output limit para que coincidan con tu modelo — los endpoints locales no pueden reportarlos, así que OpenCode depende de los valores que proporciones.

El lado del servidor de modelos

Haz que el servidor sea alcanzable desde los containers:

  • LM Studio: activa Developer → Local Server → “Serve on Local Network”. Sin eso, LM Studio se enlaza solo a 127.0.0.1 y ningún container puede alcanzarlo.
  • Firewall de macOS: o apagado, o con el servidor de modelos explícitamente permitido.

Confirma que está enlazado a todas las interfaces, no solo a loopback:

lsof -nP -iTCP -sTCP:LISTEN | grep 1234
# Want: *:1234 (LISTEN)   — bound to all interfaces
# If it shows 127.0.0.1:1234, "Serve on Local Network" is OFF.

El sidecar puente (workaround para gVisor)

Solo necesitas esto cuando el servidor de modelos corre en el Mac anfitrión y Docker Desktop usa el stack de red gVisor (el valor por defecto desde 4.34+). No lo necesitas para proveedores en la nube, ni cuando el servidor de modelos corre como un container dentro de la red de compose de Takuto Core — en ese caso apunta la Base URL al nombre del servicio (p. ej. http://lm-studio:1234/v1) y sáltate el puente.

Con gVisor, el tráfico de los containers hacia IPs privadas en la LAN del Mac — incluido host.docker.internal (que resuelve a 192.168.65.254 dentro del container) — puede agotar el tiempo en silencio, mientras que las IPs públicas funcionan bien. Comprueba tu tipo de red:

ps ax | grep com.docker.virtualization | grep -o 'networkType [a-z]*'
# networkType gvisor   ← affected

Confirma que es el problema de gVisor

Si el servidor se enlaza a *:1234, el firewall está apagado, internet público funciona desde un container, pero tanto host.docker.internal:1234 como la IP de la LAN del Mac agotan el tiempo desde dentro del container — es el stack de gVisor.

# Public internet works from a container:
docker exec <takuto-container> sh -c 'wget -q -O - -T 3 https://1.1.1.1 | head -3'

# host.docker.internal resolves but connections time out:
docker exec <takuto-container> sh -c 'curl -v -m 3 http://host.docker.internal:1234/v1/models 2>&1 | tail -5'
# * Connection timed out after 3001 milliseconds

Solución: el sidecar socat lm-bridge

Takuto Core incluye un pequeño container socat que se adjunta a ambas redes: la bridge por defecto (que alcanza el host correctamente bajo gVisor) y la red de compose (para que los workers anidados en DinD puedan enrutar hacia él). Levántalo con un solo flag — los targets de make de abajo son el envoltorio de comodidad del repo del motor Takuto Core (la vía de crea-tu-propio-container); por debajo, LM_BRIDGE=1 simplemente fusiona docker-compose.lm-bridge.yml en el stack de Compose:

make start BACKEND=postgres LM_BRIDGE=1

Eso arranca maestro-lm-bridge en la IP fijada 172.20.0.250, reenviando TCP/1234 → host.docker.internal:${LM_HOST_PORT:-1234}. Luego fija la Base URL en AI Settings a:

http://172.20.0.250:1234/v1

Para un puerto distinto del por defecto (el 11434 de Ollama, por ejemplo):

LM_HOST_PORT=11434 make start BACKEND=postgres LM_BRIDGE=1

Smoke test una vez que el puente está arriba

docker exec maestro-core-dind-1 docker run --rm --entrypoint /bin/bash \
  maestro:latest -c \
  'exec 3<>/dev/tcp/172.20.0.250/1234;
   printf "GET /v1/models HTTP/1.0\r\nHost: x\r\n\r\n" >&3;
   timeout 5 cat <&3 | head -5'

Un 200 OK seguido de JSON significa que la ruta del worker está sana.

Checklist para OpenCode error: unknown error

Cuando el dashboard muestra el críptico OpenCode error: unknown error, recorre estos en orden — cada uno es un modo de fallo real:

  1. El campo Model empieza por self_hosted/.
  2. Allow shared default token está marcado (a menos que hayas guardado un bearer por usuario). Cuando está desmarcado y no hay ningún bearer guardado, no se monta ningún opencode.json en el worker y OpenCode sale justo después de su migración de base de datos del primer arranque.
  3. La Base URL termina en /v1.
  4. El servidor de modelos tiene “Serve on Local Network” activo (*:<port>, no 127.0.0.1:<port>).
  5. La red de Docker Desktop está sana — ejecuta el smoke test; si agota el tiempo, usa el sidecar LM_BRIDGE de arriba.

Si los cinco están en verde y la ejecución aún falla, ejecuta opencode run manualmente dentro del container con --print-logs --log-level WARN para ver el stderr propio de OpenCode en lugar del oculto “unknown error”.