Inicio rápido del conmutador de modelos llama.swap para LLMs locales compatibles con OpenAI
Intercambio en caliente de modelos LLM locales sin modificar los clientes.
Pronto estarás manejando vLLM, llama.cpp y más, cada pila en su propio puerto. Todo lo que hay aguas abajo sigue queriendo una URL base /v1; de lo contrario, seguirás reorganizando puertos, perfiles y scripts de una sola vez. llama-swap es el proxy /v1 antes de esas pilas.
llama-swap proporciona una puerta de entrada única compatible con OpenAI y Anthropic, con un archivo YAML que asigna cada nombre de model al comando que inicia el servidor aguas arriba correcto. Solicita un modelo y el proxy lo inicia o cambia a él; configura TTLs y grupos cuando la VRAM es escasa o varios modelos deben coexistir. Esta guía cubre las rutas de instalación, un config.yaml práctico, la superficie HTTP y los modos de fallo que aparecen una vez que entran en juego el streaming y los proxies inversos.
Para una comparación más amplia de las opciones de alojamiento de LLM, consulta LLM Hosting in 2026: Local, Self-Hosted & Cloud Infrastructure Compared
Resumen del cambiador de modelos llama-swap para APIs LLM locales compatibles con OpenAI
llama-swap es un servidor proxy ligero construido alrededor de un modelo operativo sencillo: un único binario, un archivo de configuración YAML, sin dependencias. Está escrito en Go, lo que significa un único binario estático junto al resto de la pila: no se requiere tiempo de ejecución de Python ni ninguna aplicación de escritorio. Se sitúa delante de cualquier servidor aguas arriba compatible con OpenAI y Anthropic como la capa de cambio de modelos.
Conceptualmente, esto responde a una pregunta muy práctica que surge en las pilas de LLM locales:
¿Cómo cambio de modelos con un cliente compatible con OpenAI?
Con llama-swap, sigues usando las solicitudes normales /v1/..., pero cambias el model que solicitas. llama-swap lee ese valor de model, carga la configuración del servidor correspondiente y, si el servidor aguas arriba “incorrecto” está ejecutándose, lo cambia por el correcto.
Algunos detalles de diseño son importantes para configuraciones de tipo producción:
llama-swap tiene licencia MIT y no tiene telemetría: aún así, vale la pena confirmarlo para cualquier host que vea prompts reales.
Está diseñado para la carga bajo demanda de backends como llama.cpp, vLLM, Whisper y stable-diffusion.cpp, no para encerrarte en un motor de inferencia único.
De fábrica (sin agrupación especial), ejecuta un modelo a la vez: solicita un model diferente y detiene el servidor aguas arriba actual e inicia el correcto. Para más de un modelo residente o un control más fino sobre la coexistencia, configura groups.
Aquí está el modelo mental que la mayoría de los desarrolladores encuentran útil:
flowchart LR
C[Tu app o SDK\nCliente compatible con OpenAI] -->|/v1/chat/completions\nmodel = qwen-coder| LS[llama-swap proxy\núnico endpoint]
LS -->|inicia o enruta a| U1[Servidor aguas arriba A\nllama-server]
LS -->|inicia o enruta a| U2[Servidor aguas arriba B\nvLLM OpenAI server]
LS --> M[Endpoints de gestión\nrunning, unload, events, metrics]
Esto es también por qué un proxy cambiador de modelos es diferente a “simplemente ejecutar un modelo”: es orquestación y enrutamiento sobre uno o más servidores de inferencia.
llama-swap vs Ollama vs LM Studio vs servidor llama.cpp
Las cuatro opciones pueden darte una “API LLM local”, pero optimizan para flujos de trabajo diferentes. La forma más rápida de elegir es decidir si quieres un runtime (descarga de modelo + ejecución) o un router/proxy (cambio + orquestación entre runtimes).
llama-swap
llama-swap se centra en ser un proxy transparente que soporta endpoints compatibles con OpenAI (incluyendo /v1/chat/completions, /v1/completions, /v1/embeddings y /v1/models) y enruta las solicitudes al servidor aguas arriba correcto basándose en el modelo solicitado. También proporciona endpoints operativos no relacionados con la inferencia como /running, /logs/stream y una interfaz web en /ui.
Ollama
Ollama expone su propia API HTTP (POST /api/chat, POST /api/generate y el local habitual en el puerto 11434).
keep_alive controla cuánto tiempo se mantiene cargado un modelo, incluyendo 0 para descargarlo inmediatamente.
Se adapta a usuarios que quieren descargar un modelo y chatear con un cableado mínimo. llama-swap se adapta a comandos por modelo, backends mixtos y una URL con forma OpenAI para cada cliente: orquestar vLLM junto a llama-server con diferentes flags por modelo está fuera de lo que Ollama persigue.
LM Studio
LM Studio es una aplicación de escritorio con un servidor API local desde la pestaña Developer (localhost o LAN), incluyendo modos compatibles con OpenAI y compatibles con Anthropic, además de lms server start desde la terminal.
Se adapta a un ciclo primero GUI: navegar modelos, hacer clic, probar. llama-swap se adapta a un rol de estilo servidor: YAML, supervisión de procesos, upstreams mixtos, sin sesión de escritorio.
Servidor llama.cpp
llama-server expone /v1/completions, /v1/chat/completions, /v1/responses, y el patrón habitual es apuntar un cliente OpenAI a él vía base_url.
llama.cpp también incluye un modo router: ejecuta llama-server como router, --models-dir, luego POST /models/load y POST /models/unload para manejar modelos GGUF sin un proxy separado.
Si cada modelo está bajo un router llama.cpp, un proxy extra a menudo es innecesario. Cuando llama.cpp debe estar junto a vLLM u otros servidores con forma OpenAI, llama-swap proporciona una superficie /v1 única y muchos procesos detrás de ella.
Para soluciones de alojamiento compatibles con OpenAI similares, consulta LocalAI QuickStart: Run OpenAI-Compatible LLMs Locally o SGLang QuickStart: Install, Configure, and Serve LLMs via OpenAI API
Instala llama-swap model switcher con Docker, Homebrew, WinGet o binarios
Linux, macOS y Windows son de primera clase: Docker, Homebrew, WinGet, binarios de GitHub o compilar desde el código fuente. Elecciones comunes: Docker en servidores headless, Homebrew o WinGet en estaciones de trabajo, binarios independientes cuando la huella de instalación debe permanecer mínima.
Instalación con Docker
Descarga una imagen que coincida con tu hardware. Las imágenes siguen de cerca el upstream (compilaciones diarias) y cubren CUDA, Vulkan, Intel, MUSA y CPU: elige la que coincida con cómo aceleras realmente, no la “latest” por costumbre.
# Ejemplo de descargas de plataforma
docker pull ghcr.io/mostlygeek/llama-swap:cuda
docker pull ghcr.io/mostlygeek/llama-swap:vulkan
docker pull ghcr.io/mostlygeek/llama-swap:intel
docker pull ghcr.io/mostlygeek/llama-swap:musa
docker pull ghcr.io/mostlygeek/llama-swap:cpu
Prefiere las variantes de imagen no root cuando puedas: menos lamentar si el límite del contenedor alguna vez es incorrecto.
Instalación con Homebrew
En macOS y Linux, usa el tap e instala:
brew tap mostlygeek/llama-swap
brew install llama-swap
llama-swap --config path/to/config.yaml --listen localhost:8080
Instalación con WinGet
En Windows:
winget install llama-swap
winget upgrade llama-swap
Binarios precompilados y lanzamientos
GitHub Releases ofrece binarios para Linux, macOS, Windows y FreeBSD si no quieres un gestor de paquetes.
Los números de lanzamiento cambian rápido (por ejemplo v198, v197 a principios de 2026): fija una versión en la automatización en lugar de flotar “lo que haya sido ayer”.
Configura llama-swap con config.yaml para cambio de modelos, TTL y grupos
Todo en llama-swap está impulsado por la configuración. La configuración mínima viable es simplemente un diccionario models: y un cmd para cada modelo, a menudo iniciando llama-server con ${PORT} sustituido por modelo.
El sistema de configuración va mucho más allá de “iniciar un proceso”, y algunas opciones valen la pena entender temprano porque responden directamente a problemas comunes de estilo FAQ (descarga automática, seguridad y clientes que dependen de /v1/models).
Ajustes globales que realmente usarás
healthCheckTimeout es cuánto tiempo llama-swap espera para que un modelo se vuelva saludable después del inicio (predeterminado 120s, mínimo 15s). Para cargas de varios GB en discos lentos, aumenta esto antes de culpar al proxy.
globalTTL es los segundos de inactividad antes de la descarga automática; el predeterminado 0 significa “nunca descargar” a menos que lo configures: elige explícitamente TTLs para cualquier cosa más allá de una configuración de juguete para que la VRAM no se llene de modelos olvidados.
startPort siembra el macro ${PORT} (predeterminado 5800); la asignación es determinista por ID de modelo alfabético, lo cual es una función cuando depuras “quién agarró qué puerto” y un problema si renomas modelos descuidadamente.
includeAliasesInList decide si los alias aparecen como filas separadas en /v1/models; actívalo si tu UI solo ofrece modelos enumerados.
apiKeys protege cualquier cosa accesible fuera de localhost: Basic, Bearer o x-api-key. llama-swap elimina esos encabezados antes de reenviar para que los registros aguas arriba sean menos propensos a retener secretos del cliente.
Ajustes a nivel de modelo que desbloquean ergonomía de producción
Por modelo, cmd es el único campo requerido.
proxy predetermina a http://localhost:${PORT}: ese es el objetivo de reenvío para el upstream de ese modelo.
checkEndpoint predetermina a /health; establece "none" cuando el backend no tiene ruta de salud o el inicio en frío excede lo que estás dispuesto a esperar: no dejes un /health roto y preguntes por qué nada llega a ready.
ttl: -1 hereda globalTTL, 0 nunca descarga, N > 0 descarga después de N segundos inactivos: usa TTL por modelo cuando un modelo debería quedarse y otro debería desaparecer rápidamente.
aliases y useModelName mantienen nombres estables frente al cliente mientras satisfacen upstreams que requieren un identificador específico.
cmdStop es no opcional para contenedores: asígnalo a docker stop (o equivalente); sin él obtienes POSIX SIGTERM / Windows taskkill contra cualquier PID que llama-swap iniciara: bien para un binario desnudo, mal para un nombre de contenedor.
concurrencyLimit limita las solicitudes paralelas por modelo con HTTP 429 cuando se excede: configúralo cuando preferirías soltar carga que hacer cola para siempre.
groups cubren coexistencia (swap, exclusive) y modelos siempre activos (persistent). Los hooks pueden precargar al inicio; si precargas varios modelos a la vez sin un grupo, espera que luchen: define un grupo primero para que la precarga coincida con cómo quieres que los modelos compartan la GPU.
Ejemplo mínimo de config.yaml para llama.cpp y vLLM
Este ejemplo apunta a ser “justo lo suficiente” para ilustrar los controles de mejores prácticas: un TTL predeterminado, verificación de salud explícita, alias estables y un grupo que mantiene un modelo pequeño “siempre activo” ejecutándose mientras los modelos de chat más grandes cambian.
# config.yaml
healthCheckTimeout: 180
globalTTL: 900 # 15 minutos inactivo luego descarga
includeAliasesInList: true
startPort: 5800
# Opcional pero recomendado para cualquier cosa más allá del desarrollo local
apiKeys:
- "${env.LLAMASWAP_API_KEY}"
models:
llama-chat:
cmd: |
llama-server --port ${PORT} --model /models/llama-chat.gguf
--ctx-size 8192
aliases:
- "llama-chat-latest"
# Usa predeterminados:
# proxy: http://localhost:${PORT}
# checkEndpoint: /health
# ttl: -1 (heredar globalTTL)
qwen-coder:
cmd: |
llama-server --port ${PORT} --model /models/qwen-coder.gguf
--ctx-size 8192
aliases:
- "qwen-coder-latest"
vllm-coder:
# Patrón ilustrativo: gestionar un servidor compatible con OpenAI en contenedor
proxy: "http://127.0.0.1:${PORT}"
cmd: |
docker run --name ${MODEL_ID} --init --rm -p ${PORT}:8000 vllm/vllm-openai:latest
cmdStop: docker stop ${MODEL_ID}
checkEndpoint: "none"
ttl: 0 # nunca descargar automáticamente (ej. mantener en GPU)
groups:
chat-models:
swap: true
exclusive: true
members: ["llama-chat", "qwen-coder"]
always-on:
persistent: true
swap: false
exclusive: false
members: ["vllm-coder"]
Ninguna de esto es decorativa: cmd impulsa el proceso, proxy/checkEndpoint/ttl controlan el enrutamiento y ciclo de vida, cmdStop es lo que hace que los upstreams basados en Docker realmente se detengan, y groups son lo que separa “un modelo grande a la vez” de “estos dos modelos de chat pueden coexistir mientras el servidor de embeddings se mantiene fijo”.
Ejecuta y cambia modelos vía endpoints compatibles con OpenAI
Una vez que llama-swap está ejecutándose, interactúas con él como con cualquier otro endpoint compatible con OpenAI. La superficie de la API incluye endpoints principales como /v1/chat/completions, /v1/completions, /v1/embeddings y /v1/models, y llama-swap usa el model solicitado para decidir qué upstream ejecutar y enrutar.
Un flujo práctico de inicio rápido:
# 1) Iniciar llama-swap
llama-swap --config ./config.yaml --listen localhost:8080
# 2) Descubrir modelos disponibles
curl http://localhost:8080/v1/models
La lista de modelos es una característica de gestión de primera clase e incluye comportamientos como ordenar por ID, excluir modelos unlisted e incluir opcionalmente alias.
# 3) Hacer una solicitud de chat completion para un modelo específico
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${LLAMASWAP_API_KEY}" \
-d '{
"model": "qwen-coder",
"messages": [{"role":"user","content":"Escribe una función TypeScript que reintent fetch con backoff."}]
}'
Si ahora repites la llamada con "model": "llama-chat", llama-swap cambiará los procesos aguas arriba (a menos que tu configuración de grupo permita que coexistan) porque extrae el modelo solicitado de la solicitud y carga la configuración del servidor apropiada.
Si estás usando un SDK, apunta el cliente a http://localhost:8080/v1—el mismo truco que apuntar la librería Python de OpenAI a llama-server, excepto que la URL estable ahora es llama-swap y el campo model elige el upstream.
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8080/v1",
api_key="sk-your-llamaswap-key"
)
resp = client.chat.completions.create(
model="qwen-coder",
messages=[{"role": "user", "content": "Explica la diferencia entre mutexes y semáforos."}],
)
print(resp.choices[0].message.content)
Para calentar un modelo antes de la primera solicitud real (ocultar latencia de inicio en frío), usa /upstream/<model>: auto-carga si es necesario y reenvía directamente a ese upstream. Forma directa de asegurar que los pesos estén residentes antes de un benchmark o prueba scriptada.
Control y monitoriza llama-swap vía endpoints de API de gestión y eventos SSE
llama-swap no es solo “un proxy”; también expone endpoints de control operativo que te permiten construir herramientas alrededor del ciclo de vida del modelo y la observabilidad.
Verifica qué está ejecutándose
GET /running devuelve el estado de tiempo de ejecución para modelos cargados, incluyendo valores de estado como ready, starting, stopping, stopped y shutdown.
curl http://localhost:8080/running
Descarga modelos para liberar VRAM
Para descargar todo inmediatamente, usa el endpoint versionado de la API POST /api/models/unload. Para descargar un solo modelo (por ID o alias), usa POST /api/models/unload/<model>. Un GET /unload legacy existe para compatibilidad hacia atrás.
# descargar todo
curl -X POST http://localhost:8080/api/models/unload
# descargar un modelo
curl -X POST http://localhost:8080/api/models/unload/qwen-coder
Usa estos endpoints cuando la VRAM se necesita de vuelta ahora en lugar de esperar al TTL—benchmarks, cambios rápidos de modelo, o después de cargar un checkpoint mucho más grande del previsto.
Transmite eventos en vivo vía SSE
GET /api/events establece un flujo de Eventos Enviados por el Servidor (Server-Sent Events) y está diseñado para actualizaciones en tiempo real que incluyen cambios de estado del modelo, registros, métricas y conteos de solicitudes en vuelo.
curl -N http://localhost:8080/api/events
SSE y streaming de tokens se rompen cuando cualquier caja intermedia hace buffer: desactiva el buffer en nginx (o tu equivalente) para /api/events y /v1/chat/completions. llama-swap establece X-Accel-Buffering: no en SSE; desactiva el buffer en el proxy también: los encabezados no son un sustituto de una configuración de proxy correcta.
Métricas y capturas de solicitudes
GET /api/metrics devuelve métricas de uso de tokens, con retención en memoria controlada por metricsMaxInMemory (predeterminado 1000).
GET /api/captures/<id> puede recuperar capturas completas de solicitud/respuesta, pero solo cuando captureBuffer > 0 está configurado.
Registros y la Interfaz Web
llama-swap expone /ui para una interfaz web, y endpoints de registros operativos como /logs y /logs/stream para monitoreo en tiempo real.

Si habilitas apiKeys, asume defensa en profundidad: /health y partes de /ui permanecen accesibles sin una clave—bien para límites de confianza locales, no bien si el host está en una red compartida. Pon llama-swap detrás de algo que haga cumplir tu política real; la autenticación integrada es para mantener a los clientes casuales honestos, no para una API pública multitenante.
Solución de problemas de cambio de modelos llama-swap en producción
La mayoría de los problemas de llama-swap caen en un pequeño conjunto de categorías operativas: streaming a través de un proxy inverso, verificaciones de salud durante inicios en frío, puertos y ciclo de vida de procesos, y autenticación.
El streaming se rompe detrás de nginx u otro proxy inverso
nginx hará felizmente buffer de tus SSE y completamientos stream. Desactiva proxy_buffering (y proxy_cache) para /api/events y /v1/chat/completions. llama-swap emite X-Accel-Buffering: no en SSE, lo cual ayuda—corrige el proxy de todos modos.
Un modelo nunca se vuelve listo
Por defecto, checkEndpoint por modelo es /health y debe devolver HTTP 200 para que el proceso sea considerado listo. Puedes establecer checkEndpoint a otra ruta o a "none" para desactivar las verificaciones de salud completamente.
Si los modelos grandes tardan más en cargar, aumenta healthCheckTimeout (predeterminado 120s), o usa verificaciones de salud a medida para tu upstream específico.
Cambiar modelos deja un contenedor antiguo ejecutándose
Si el upstream es Docker o Podman, establece cmdStop—de lo contrario llama-swap detiene el proceso envoltorio mientras el contenedor sigue comiendo VRAM en segundo plano.
Obtengo respuestas 401 después de habilitar seguridad
Cuando apiKeys está configurado, llama-swap requiere una clave válida y acepta tres métodos (autenticación Basic, token Bearer, x-api-key). También elimina los encabezados de autenticación antes de reenviar aguas arriba.
Obtengo 429 Too Many Requests
concurrencyLimit devuelve 429 cuando se excede—por diseño. Sube el límite si lo subdimensionaste, o baja el límite si no querías hacer throttling.
Conflictos de puerto o problemas extraños de enrutamiento
Evita puertos codificados en duro en cmd; usa ${PORT} y mueve startPort si 5800+ colisiona con algo más. Recuerda que los puertos se asignan en orden alfabético por ID de modelo—renombra un modelo y el mapeo de puertos cambia.
Lista de verificación de depuración operativa
/running para la verdad, /logs/stream cuando el inicio es opaco, POST /api/models/unload cuando la VRAM se necesita de vuelta ahora. Esa tríada cubre la mayoría de las sesiones de “por qué está llena la GPU”.