Guida introduttiva al Model Switcher di llama.swap per LLM locali compatibili con OpenAI

Sostituzione a caldo di LLM locali senza modificare i client.

Indice

Presto ti troverai a gestire vLLM, llama.cpp e altro ancora, con ogni stack sul proprio porto. Tutto il downstream desidera comunque un URL base /v1; altrimenti continuerai a spostare porti, profili e script ad hoc. llama-swap è il proxy /v1 che precede questi stack.

llama-swap fornisce un’interfaccia frontale compatibile con OpenAI e Anthropic, con un file YAML che mappa ogni nome model al comando che avvia l’upstream corretto. Richiedi un modello e il proxy lo avvia o esegue il cambio; configura i TTL e i gruppi quando la VRAM è limitata o diversi modelli devono coesistere. Questa guida copre i percorsi di installazione, un config.yaml pratico, la superficie HTTP e i modi di fallimento che emergono una volta che streaming e proxy inversi entrano in gioco.

llama swap llm infographic Per un confronto più ampio delle opzioni di hosting LLM, vedi LLM Hosting in 2026: Confronto tra Infrastruttura Locale, Self-Hosted e Cloud

Panoramica dello switcher di modelli llama-swap per API LLM locali compatibili con OpenAI

llama-swap è un server proxy leggero basato su un modello operativo semplice: un singolo binario, un file di configurazione YAML, zero dipendenze. È scritto in Go, il che significa un singolo binario statico a fianco del resto dello stack: nessun runtime Python o app desktop richiesti. Si posiziona davanti a qualsiasi upstream compatibile con OpenAI e Anthropic come livello di cambio modelli.

Concettualmente, questo risponde a una domanda molto pratica che sorge negli stack LLM locali:

Come cambio modelli con un client compatibile con OpenAI?
Con llama-swap continui a usare le normali richieste /v1/..., ma cambi il model richiesto. llama-swap legge quel valore model, carica la configurazione del server corrispondente e, se l’upstream “sbagliato” è in esecuzione, lo sostituisce con quello corretto.

Alcuni dettagli di progettazione sono importanti per setup quasi di produzione:

llama-swap è licenziato MIT con nessuna telemetria—utile confermare per qualsiasi host che veda prompt reali.
È costruito per il caricamento on-demand di backend come llama.cpp, vLLM, Whisper e stable-diffusion.cpp, non per bloccarti su un singolo motore di inferenza.
Di default (senza raggruppamento speciale), esegue un modello alla volta: richiedi un model diverso e ferma l’upstream corrente per avviare quello giusto. Per più di un modello residente o un controllo più fine sulla coesistenza, configura i groups.

Ecco il modello mentale che la maggior parte degli sviluppatori trova utile:

flowchart LR
  C[Tua app o SDK\nClient compatibile con OpenAI] -->|/v1/chat/completions\nmodel = qwen-coder| LS[Proxy llama-swap\nsingolo endpoint]
  LS -->|avvia o instrada verso| U1[Server Upstream A\nllama-server]
  LS -->|avvia o instrada verso| U2[Server Upstream B\nServer OpenAI vLLM]
  LS --> M[Endpoints di gestione\nesecuzione, scaricamento, eventi, metriche]

Questo spiega anche perché un proxy switcher di modelli è diverso dal “semplice esecuzione di un modello”: è orchestrazione e instradamento su uno o più server di inferenza.

llama-swap vs Ollama vs LM Studio vs server llama.cpp

Tutte e quattro le opzioni possono darti una “API LLM locale”, ma ottimizzano per flussi di lavoro diversi. Il modo più veloce per scegliere è decidere se vuoi un runtime (download modello + esecuzione) o un router/proxy (cambio e orchestrazione tra runtime).

llama-swap
llama-swap si concentra sull’essere un proxy trasparente che supporta endpoint compatibili con OpenAI (inclusi /v1/chat/completions, /v1/completions, /v1/embeddings e /v1/models) e instrada le richieste verso l’upstream corretto in base al modello richiesto. Fornisce anche endpoint operativi non di inferenza come /running, /logs/stream e un’interfaccia Web a /ui.

Ollama
Ollama espone la propria API HTTP (POST /api/chat, POST /api/generate e il solito default locale sulla porta 11434).
keep_alive controlla quanto tempo un modello rimane caricato, incluso 0 per lo scaricamento immediato.
Si adatta agli utenti che vogliono scaricare un modello e chattare con il minimo cablaggio. llama-swap si adatta a comandi per modello, backend misti e un URL con forma OpenAI per ogni client—orchestrare vLLM accanto a llama-server con flag diversi per modello è fuori dallo scopo di Ollama.

LM Studio
LM Studio è un’app desktop con un server API locale dalla Scheda Sviluppatore (localhost o LAN), inclusi modi compatibili con OpenAI e compatibili con Anthropic, più lms server start dal terminale.
Si adatta a un ciclo prima interfaccia grafica: sfoglia modelli, clicca, testa. llama-swap si adatta a un ruolo stile server: YAML, supervisione dei processi, upstream misti, nessuna sessione desktop.

Server llama.cpp
llama-server espone /v1/completions, /v1/chat/completions, /v1/responses e il pattern abituale è puntare un client OpenAI verso di esso tramite base_url.
llama.cpp include anche una modalità router: esegui llama-server come router, --models-dir, poi POST /models/load e POST /models/unload per gestire modelli GGUF senza un proxy separato. Per una guida completa alla configurazione vedi Modalità router llama-server: cambio dinamico di modelli senza riavvii.
Se ogni modello risiede sotto un router llama.cpp, un proxy aggiuntivo è spesso inutile. Quando llama.cpp deve stare accanto a vLLM o altri server con forma OpenAI, llama-swap fornisce una superficie /v1 unica e molti processi dietro di essa.

Per soluzioni di hosting simili compatibili con OpenAI, vedi LocalAI QuickStart: Esegui LLM Compatibili con OpenAI Localmente o SGLang QuickStart: Installa, Configura e Servi LLM tramite API OpenAI

Installa llama-swap model switcher con Docker, Homebrew, WinGet o binari

Linux, macOS e Windows sono tutti di prima classe: Docker, Homebrew, WinGet, binari GitHub o compilazione dal sorgente. Scelte comuni: Docker su server senza interfaccia grafica, Homebrew o WinGet su workstation, binari standalone quando l’impronta di installazione deve rimanere minima.

Installazione Docker

Estrai un’immagine che corrisponde al tuo hardware. Le immagini seguono da vicino gli upstream (build notturne) e coprono CUDA, Vulkan, Intel, MUSA e CPU—scegli quella che corrisponde a come acceleri effettivamente, non “latest” per abitudine.

# Esempi di estrazione per piattaforma
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

Preferisci le varianti di immagine non-root quando possibile: meno rimpianti se il confine del container è mai sbagliato.

Installazione Homebrew

Su macOS e Linux, usa il tap e installa:

brew tap mostlygeek/llama-swap
brew install llama-swap
llama-swap --config path/to/config.yaml --listen localhost:8080

Installazione WinGet

Su Windows:

winget install llama-swap
winget upgrade llama-swap

Binari pre-compilati e release

GitHub Releases fornisce binari per Linux, macOS, Windows e FreeBSD se non vuoi un gestore di pacchetti.
I numeri di release si muovono velocemente (ad esempio v198, v197 all’inizio del 2026)—fissa una versione nell’automazione invece di galleggiare su “quello che c’era ieri”.

Configura llama-swap con config.yaml per cambio modelli, TTL e gruppi

Tutto in llama-swap è guidato dalla configurazione. La configurazione minima vitale è semplicemente un dizionario models: e un cmd per ogni modello, spesso che lancia llama-server con ${PORT} sostituito per modello.

Il sistema di configurazione va molto oltre il semplice “avvia un processo” e alcune opzioni vale la pena comprenderle presto perché rispondono direttamente a problemi comuni di stile FAQ (scaricamento automatico, sicurezza e client che si affidano a /v1/models).

Impostazioni globali che userai davvero

healthCheckTimeout è quanto tempo llama-swap attende che un modello diventi sano dopo l’avvio (default 120s, minimo 15s). Per carichi multi-GB su dischi lenti, aumenta questo prima di incolpare il proxy.
globalTTL sono i secondi di inattività prima dello scaricamento automatico; default 0 significa “mai scaricare” a meno che tu non lo imposti—scegli esplicitamente i TTL per qualsiasi cosa oltre a una configurazione giocosa per evitare che la VRAM si riempia di modelli dimenticati.
startPort semina la macro ${PORT} (default 5800); l’assegnazione è deterministica per ID modello alfabetico, una caratteristica quando debugghi “chi ha preso quale porta” e una trappola se rinomini modelli con disattenzione.
includeAliasesInList decide se gli alias appaiono come righe separate in /v1/models; attivalo se la tua interfaccia offre solo modelli elencati.
apiKeys protegge tutto ciò che è raggiungibile fuori da localhost: Basic, Bearer o x-api-key. llama-swap rimuove quegli header prima di inoltrare in modo che i log upstream siano meno probabili a conservare segreti del client.

Impostazioni a livello di modello che sbloccano l’ergonomia di produzione

Per modello, cmd è l’unico campo richiesto.
proxy default è http://localhost:${PORT}—quello è il target di inoltro per l’upstream di quel modello.
checkEndpoint default è /health; imposta "none" quando il backend non ha una rotta di salute o l’avvio a freddo supera ciò che sei disposto ad aspettare—non lasciare un /health rotto e chiederti perché nulla raggiunge ready.
ttl: -1 eredita globalTTL, 0 non scarica mai, N > 0 scarica dopo N secondi di inattività—usa TTL per modello quando un modello dovrebbe rimanere e un altro dovrebbe scomparire rapidamente.
aliases e useModelName mantengono nomi stabili per il client mentre soddisfano gli upstream che richiedono un identificatore specifico.
cmdStop è non opzionale per i container: mappalo a docker stop (o equivalente); senza di esso ottieni POSIX SIGTERM / Windows taskkill contro il PID che llama-swap ha avviato—ok per un binario nudo, sbagliato per un nome di container.
concurrencyLimit limita le richieste parallele per modello con HTTP 429 quando superato—impostalo quando preferisci scartare il carico piuttosto che fare la coda all’infinito.

groups coprono la coesistenza (swap, exclusive) e i modelli sempre attivi (persistent). Gli hook possono pre-caricare all’avvio; se pre-carichi più modelli contemporaneamente senza un gruppo, aspettati che lottino—definisci prima un gruppo in modo che il pre-caricamento corrisponda a come vuoi che i modelli condividano la GPU.

Esempio minimo di config.yaml per llama.cpp e vLLM

Questo esempio mira a essere “sufficiente” per illustrare le manopole delle best practice: un TTL predefinito, controllo salute esplicito, alias stabili e un gruppo che mantiene un piccolo modello “sempre attivo” in esecuzione mentre i modelli di chat più grandi fanno il cambio.

# config.yaml
healthCheckTimeout: 180
globalTTL: 900            # 15 minuti di inattività poi scaricamento
includeAliasesInList: true
startPort: 5800

# Opzionale ma raccomandato per tutto ciò che va oltre lo sviluppo locale
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 i default:
    # proxy: http://localhost:${PORT}
    # checkEndpoint: /health
    # ttl: -1 (eredita globalTTL)

  qwen-coder:
    cmd: |
      llama-server --port ${PORT} --model /models/qwen-coder.gguf
      --ctx-size 8192      
    aliases:
      - "qwen-coder-latest"

  vllm-coder:
    # Pattern illustrativo: gestire un server OpenAI compatibile containerizzato
    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                 # mai scaricamento automatico (es. mantieni sulla GPU)

groups:
  chat-models:
    swap: true
    exclusive: true
    members: ["llama-chat", "qwen-coder"]

  always-on:
    persistent: true
    swap: false
    exclusive: false
    members: ["vllm-coder"]

Nessuna di queste cose è decorativa: cmd guida il processo, proxy/checkEndpoint/ttl controllano instradamento e ciclo di vita, cmdStop è ciò che fa fermare effettivamente gli upstream basati su Docker, e groups è ciò che separa “un modello grande alla volta” da “questi due modelli di chat possono coesistere mentre il server di embedding resta fissato”.

Esegui e cambia modelli tramite endpoint compatibili con OpenAI

Una volta che llama-swap è in esecuzione, interagisci con esso come con qualsiasi altro endpoint compatibile con OpenAI. La superficie API include endpoint core come /v1/chat/completions, /v1/completions, /v1/embeddings e /v1/models, e llama-swap usa il model richiesto per decidere quale upstream eseguire e instradare.

Un flusso pratico di avvio rapido:

# 1) Avvia llama-swap
llama-swap --config ./config.yaml --listen localhost:8080
# 2) Scopri i modelli disponibili
curl http://localhost:8080/v1/models

L’elenco dei modelli è una caratteristica di gestione di primo livello e include comportamenti come ordinamento per ID, esclusione di modelli unlisted e opzionalmente inclusione di alias.

# 3) Esegui una richiesta di completamento chat per un modello specifico
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":"Scrivi una funzione TypeScript che ritenta fetch con backoff."}]
  }'

Se ora ripeti la chiamata con "model": "llama-chat", llama-swap cambierà i processi upstream (a meno che la tua configurazione di gruppo non permetta la coesistenza) perché estrae il modello richiesto dalla richiesta e carica la configurazione del server appropriata.

Se stai usando un SDK, punta il client a http://localhost:8080/v1—stesso trucco di puntare la libreria Python OpenAI a llama-server, tranne che l’URL stabile è ora llama-swap e il campo model sceglie l’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": "Spiega la differenza tra mutex e semafori."}],
)
print(resp.choices[0].message.content)

Per riscaldare un modello prima della prima richiesta reale (nascondere la latenza dell’avvio a freddo), usa /upstream/<model>—carica automaticamente se necessario e inoltra direttamente a quell’upstream. Modo semplice per assicurarsi che i pesi siano residenti prima di un benchmark o test scriptato.

Controlla e monitora llama-swap tramite endpoint API di gestione e eventi SSE

llama-swap non è solo “un proxy”; espone anche endpoint di controllo operativo che ti permettono di costruire strumenti attorno al ciclo di vita dei modelli e all’osservabilità.

Controlla cosa è in esecuzione
GET /running restituisce lo stato runtime per i modelli caricati, inclusi valori di stato come ready, starting, stopping, stopped e shutdown.

curl http://localhost:8080/running

Scarica modelli per liberare VRAM
Per scaricare tutto immediatamente, usa l’endpoint versionato API POST /api/models/unload. Per scaricare un singolo modello (per ID o alias), usa POST /api/models/unload/<model>. Esiste un legacy GET /unload per compatibilità retroattiva.

# scarica tutto
curl -X POST http://localhost:8080/api/models/unload

# scarica un modello
curl -X POST http://localhost:8080/api/models/unload/qwen-coder

Usa questi endpoint quando la VRAM è necessaria ora invece di aspettare il TTL—benchmark, cambi rapidi di modello o dopo aver caricato un checkpoint molto più grande del previsto.

Trasmetti eventi in tempo reale via SSE
GET /api/events stabilisce uno stream Server-Sent Events ed è progettato per aggiornamenti in tempo reale che includono cambiamenti di stato del modello, log, metriche e conteggi di richieste in volo.

curl -N http://localhost:8080/api/events

SSE e streaming token si interrompono se qualsiasi box intermedio fa buffer—disabilita il buffering su nginx (o il tuo equivalente) per /api/events e /v1/chat/completions. llama-swap imposta X-Accel-Buffering: no su SSE; disabilita anche il buffering nel proxy—gli header non sono un sostituto per una configurazione proxy corretta.

Metriche e catture delle richieste
GET /api/metrics restituisce metriche di utilizzo token, con ritenzione in memoria controllata da metricsMaxInMemory (default 1000).
GET /api/captures/<id> può recuperare catture complete di richiesta/risposta, ma solo se captureBuffer > 0 è configurato.

Log e Interfaccia Web

llama-swap espone /ui per un’interfaccia web e endpoint di log operativi come /logs e /logs/stream per il monitoraggio in tempo reale.

llama-swap web UI for switching models

Se abiliti apiKeys, assumi difesa in profondità: /health e pezzi di /ui restano raggiungibili senza chiave—ok per confini di fiducia locali, non ok se l’host è su una rete condivisa. Metti llama-swap dietro qualcosa che applica la tua politica reale; l’autenticazione integrata è per mantenere onesti i client casuali, non per un’API multi-tenant pubblica.

Risoluzione dei problemi del cambio modelli llama-swap in produzione

La maggior parte dei problemi di llama-swap rientra in un piccolo set di categorie operative: streaming attraverso un proxy inverso, controlli di salute durante gli avvii a freddo, porti e ciclo di vita dei processi, e autenticazione.

Lo streaming si interrompe dietro nginx o un altro proxy inverso
nginx farà volentieri buffer via i tuoi SSE e completamenti streammati. Disabilita proxy_buffering (e proxy_cache) per /api/events e /v1/chat/completions. llama-swap emette X-Accel-Buffering: no su SSE, che aiuta—risolvi comunque il proxy.

Un modello non diventa mai pronto
Di default, checkEndpoint per modello è /health e deve restituire HTTP 200 perché il processo sia considerato pronto. Puoi impostare checkEndpoint su un altro percorso o su "none" per disabilitare completamente i controlli di salute.
Se i modelli grandi impiegano più tempo a caricarsi, aumenta healthCheckTimeout (default 120s), o usa controlli di salute su misura per il tuo specifico upstream.

Cambiare modelli lascia un vecchio container in esecuzione
Se l’upstream è Docker o Podman, imposta cmdStop—altrimenti llama-swap ferma il processo wrapper mentre il container continua a consumare VRAM in background.

Ricevo risposte 401 dopo aver abilitato la sicurezza
Quando apiKeys è configurato, llama-swap richiede una chiave valida e accetta tre metodi (autenticazione Basic, token Bearer, x-api-key). Rimuove anche gli header di autenticazione prima di inoltrare upstream.

Ricevo 429 Too Many Requests
concurrencyLimit restituisce 429 quando superato—per progettazione. Alza il limite se l’hai sottodimensionato, o abbassa il limite se non intendevi limitare.

Conflitti di porta o problemi di instradamento strani
Evita porte hardcoded in cmd; usa ${PORT} e muovi startPort se 5800+ collide con qualcos’altro. Ricorda che le porte sono assegnate in ordine alfabetico per ID modello—rinomina un modello e la mappatura delle porte cambia.

Checklist di debug operativo
/running per la verità, /logs/stream quando l’avvio è opaco, POST /api/models/unload quando la VRAM è necessaria ora. Quella terna copre la maggior parte delle sessioni “perché la GPU è piena”.

Iscriviti

Ricevi nuovi articoli su sistemi, infrastruttura e ingegneria AI.