Descarregar todos os modelos do roteador llama.cpp sem reiniciar

VRAM gratuito sem comprometer o llama-server.

Conteúdo da página

o modo roteador do llama.cpp é uma das mudanças mais úteis no llama-server em anos. Ele finalmente oferece aos operadores de LLMs locais uma experiência de gerenciamento de modelos próxima do que as pessoas esperam do Ollama, mantendo o desempenho bruto e o controle de baixo nível que tornam o llama.cpp digno de uso em primeiro lugar.

Mas há uma aresta afiada: descarregar tudo não é um único botão mágico na API HTTP.

O roteador pode listar modelos. Pode carregar um modelo. Pode descarregar um modelo. Pode expulsar o modelo menos recentemente usado quando --models-max é atingido. O que ele não documenta atualmente como um endpoint de primeira classe é uma chamada universal de descarregar todos os modelos agora.

laptop and desktop with llms

Isso não é um bloqueador real. O padrão correto é simples, explícito e passível de script:

  1. Pergunte ao roteador quais modelos existem.
  2. Filtre os modelos cujo status é loaded (carregado).
  3. Chame /models/unload uma vez para cada modelo carregado.

Esta é a abordagem que recomendo para fluxos de trabalho de LLM locais sérios. É entediante, visível e fácil de depurar. É exatamente o que você quer quando seu objetivo é liberar VRAM sem reiniciar todo o serviço de inferência.

O que o modo roteador do llama.cpp realmente faz

No uso clássico do llama-server, você inicia um servidor com um modelo:

llama-server \
  --model ./models/qwen3-8b.gguf \
  --port 8080

O modo roteador muda isso. Em vez de vincular o servidor a um único arquivo GGUF, o roteador torna-se um coordenador para múltiplos modelos. Ele pode descobrir modelos de um cache ou de um diretório de modelos, carregá-los sob demanda, rotear solicitações para o modelo correto e descarregar modelos quando necessário.

Uma inicialização típica do modo roteador parece com isto:

llama-server \
  --models-dir ./models \
  --models-max 4 \
  --port 8080

A opção importante aqui é --models-max. Ela controla quantos modelos podem ser carregados ao mesmo tempo. Se o limite for atingido, o llama.cpp pode expulsar o modelo menos recentemente usado. Isso é útil, mas não é um substituto para uma operação de descarregamento deliberada. A expulsão LRU é reativa. Um script de descarregamento é controle operacional.

Minha opinião pessoal: se você executa modelos locais para trabalho real, deve tratar o modo roteador como um gerenciador de processos de inferência, não como um servidor de chat de brinquedo. Operações explícitas de ciclo de vida importam.

Os endpoints de gerenciamento de modelos que você precisa

O endpoint principal para descoberta é:

curl -s http://localhost:8080/models | jq

Esse endpoint retorna os modelos conhecidos pelo roteador e seu status atual de ciclo de vida. A forma exata do JSON pode variar ligeiramente entre versões, então inspecione sua própria resposta antes de escrever automação.

Uma forma comum de resposta parece com isto:

{
  "data": [
    {
      "id": "qwen3-8b",
      "status": "loaded"
    },
    {
      "id": "llama-3.2-3b",
      "status": "unloaded"
    }
  ]
}

Para descarregar um modelo, chame:

curl -s -X POST http://localhost:8080/models/unload \
  -H "Content-Type: application/json" \
  -d '{"model":"qwen3-8b"}' \
  | jq

Esta é a operação primitiva. Tudo o resto neste artigo se baseia nisso.

Não há um endpoint documentado para descarregar tudo

Esta é a parte que confunde as pessoas.

Você poderia esperar algo como isto:

curl -X POST http://localhost:8080/models/unload-all

Não construa sua lógica baseada nessa suposição. A operação documentada é por modelo. Você passa um identificador de modelo para /models/unload, e o llama.cpp descarrega aquele modelo específico.

Isso não é necessariamente um mau design de API. Uma operação por modelo é mais segura. Ela faz com que o chamador decida o que deve ser descarregado. Também evita comportamentos surpreendentes em produção onde uma única solicitação de administrador acidentalmente mata todos os modelos quentes sendo usados por outros clientes.

Para uma estação de trabalho, um atalho para descarregar tudo seria conveniente. Para uma caixa de inferência multi-usuário, loops explícitos são melhores.

Descarregue um modelo primeiro

Antes de automatizar qualquer coisa, teste o identificador de modelo exato que seu roteador espera.

Primeiro, liste os modelos:

curl -s http://localhost:8080/models | jq

Escolha um modelo carregado da saída e, em seguida, descarregue-o:

curl -s -X POST http://localhost:8080/models/unload \
  -H "Content-Type: application/json" \
  -d '{"model":"qwen3-8b"}' \
  | jq

Verifique a lista de modelos novamente:

curl -s http://localhost:8080/models | jq

Se o status do modelo mudar para unloaded (descarregado), seu endpoint, porta e identificador de modelo estão corretos.

Se não funcionar, não chute. Inspecione o JSON. Aliases do roteador, nomes de arquivos GGUF e IDs de modelo frequentemente não são a mesma string.

Descarregue todos os modelos carregados com curl e jq

Uma vez que o descarregamento de um único modelo funcione, o padrão de descarregar tudo é apenas um loop de shell.

Use isto quando sua resposta de /models tiver .data[].id e .data[].status:

curl -s http://localhost:8080/models \
| jq -r '.data[] | select(.status == "loaded") | .id' \
| while IFS= read -r model; do
    echo "Unloading: $model"
    curl -s -X POST http://localhost:8080/models/unload \
      -H "Content-Type: application/json" \
      -d "{\"model\":\"$model\"}" \
      | jq
  done

Este é o truque inteiro. Não é glamouroso, mas é a forma certa para uma operação administrativa:

  • Ele só descarrega modelos que estão realmente carregados.
  • Ele imprime o que está fazendo.
  • Ele falha modelo por modelo em vez de esconder tudo atrás de uma ação opaca.
  • Ele funciona a partir de cron, ganchos do systemd, SSH ou jobs de CI.

Um script reutilizável para uso em produção

Para qualquer coisa que você execute mais de duas vezes, pare de colar linhas únicas. Salve um script.

Crie llama-router-unload-all.sh:

#!/usr/bin/env bash
set -euo pipefail

LLAMA_SERVER_URL="${LLAMA_SERVER_URL:-http://localhost:8080}"

models_json="$(curl -fsS "$LLAMA_SERVER_URL/models")"

loaded_models="$(printf '%s' "$models_json" \
  | jq -r '.data[] | select(.status == "loaded") | .id')"

if [ -z "$loaded_models" ]; then
  echo "No loaded models found."
  exit 0
fi

printf '%s\n' "$loaded_models" | while IFS= read -r model; do
  [ -z "$model" ] && continue

  echo "Unloading: $model"

  curl -fsS -X POST "$LLAMA_SERVER_URL/models/unload" \
    -H "Content-Type: application/json" \
    -d "{\"model\":\"$model\"}" \
    | jq

done

echo "Done. Current model state:"
curl -fsS "$LLAMA_SERVER_URL/models" | jq

Torne-o executável:

chmod +x llama-router-unload-all.sh

Execute-o contra o servidor local padrão:

./llama-router-unload-all.sh

Execute-o contra outro host:

LLAMA_SERVER_URL=http://192.168.1.50:8080 ./llama-router-unload-all.sh

Esta é a versão que eu realmente manteria em um diretório de ferramentas. Ela usa curl -f para que erros HTTP falhem o script, e permite que você sobrescreva a URL do servidor sem editar o arquivo.

Adaptando o script para a forma do seu JSON

Não assuma cegamente que cada build do llama.cpp retornará exatamente os mesmos campos para sempre. O modo roteador ainda está evoluindo, e sua build pode expor uma forma de JSON ligeiramente diferente.

Comece inspecionando a resposta:

curl -s http://localhost:8080/models | jq

O script usa este filtro:

jq -r '.data[] | select(.status == "loaded") | .id'

Se seu identificador de modelo estiver em .name, mude para:

jq -r '.data[] | select(.status == "loaded") | .name'

Se seu campo de status usar outro valor, ajuste o filtro conforme necessário. O princípio é o que importa: selecione modelos carregados, extraia o identificador aceito por /models/unload e, em seguida, chame unload para cada um.

Por que os modelos podem carregar novamente após você os descarregar

Esta é a fonte mais comum de confusão.

O modo roteador suporta carregamento sob demanda. Se um cliente enviar uma solicitação de conclusão de chat para um modelo que está atualmente descarregado, o roteador pode carregá-lo novamente automaticamente.

Isso significa que esta sequência é possível:

  1. Você descarrega todos os modelos.
  2. Open WebUI, um script de teste ou um agente envia uma solicitação.
  3. O llama.cpp carrega o modelo solicitado novamente.
  4. Você acha que o descarregamento falhou, mas não falhou.

A correção é operacional, não técnica. Pare o tráfego de clientes primeiro se seu objetivo é manter a VRAM livre.

Por exemplo:

  • Pare scripts de benchmark.
  • Pause agentes e jobs cron.
  • Feche ou desconecte sessões do Open WebUI.
  • Desative verificações de saúde que acidentalmente realizam solicitações reais de modelos.

Descarregar não é um firewall. Se os clientes continuarem pedindo modelos, o modo roteador está fazendo seu trabalho servindo-os.

Open WebUI e o botão Ejetar

Open WebUI pode integrar com o suporte de descarregamento de modelos do llama.cpp. Quando o provedor é configurado como llama.cpp, o Open WebUI pode mostrar o estado do modelo carregado e expor uma ação Ejetar para administradores.

Nos bastidores, essa ação chama a própria API de descarregamento do Open WebUI, que então chama o endpoint /models/unload do llama.cpp na conexão configurada.

Isso é bom para operação manual, mas eu ainda manteria o script de shell. Um botão de UI é conveniente. Um script é auditável, repetível e utilizável em uma caixa sem interface gráfica às 2 da manhã.

Quando usar descarregar tudo

Descarregar todos os modelos carregados é útil quando você deseja:

  • Liberar memória de GPU antes de iniciar um modelo maior.
  • Resetar uma caixa de desenvolvimento sem reiniciar o llama-server.
  • Preparar-se para uma execução de benchmark com um estado de memória limpo.
  • Drenar cargas de trabalho de inferência local antes da manutenção.
  • Recuperar-se de uma sessão bagunçada onde muitos modelos foram aquecidos.

Não é a ferramenta certa quando usuários ativos dependem de modelos quentes. Nesse caso, ajuste --models-max, use roteamento deliberado e deixe a expulsão LRU fazer parte do trabalho. Se você precisar de descarregamento baseado em tempo limite mais inteligente com controle de ciclo de vida por modelo, llama-swap é um proxy projetado para isso que caminha exatamente isso sobre qualquer configuração llama-server.

Minha regra é simples: use LRU para pressão normal, use descarregamento explícito para intenção do operador.

Solução de problemas

O endpoint de modelos retorna 404

Você pode não estar executando uma build com capacidade de roteador, ou pode estar chamando a porta errada.

Verifique o processo do servidor e as opções disponíveis:

llama-server --help | grep -i models

Em seguida, teste ambos os endpoints:

curl -s http://localhost:8080/models | jq
curl -s http://localhost:8080/v1/models | jq

O endpoint /v1/models é a lista de modelos compatível com OpenAI. O endpoint /models é o endpoint de gerenciamento de modelos do roteador. Eles estão relacionados, mas não são a mesma coisa.

jq não está instalado

Instale-o antes de criar scripts de análise de JSON.

No Ubuntu ou Debian:

sudo apt-get update
sudo apt-get install jq

No macOS com Homebrew:

brew install jq

A chamada de descarregamento retorna um erro

A maioria das falhas vem de passar o identificador de modelo errado. Use o identificador exato retornado por /models, não o nome do arquivo que você acha que deve funcionar.

Verifique também se o nome do seu modelo contém aspas, barras ou espaços. O script acima lida bem com strings normais, mas nomes incomuns podem exigir uma construção de JSON mais cuidadosa.

Para máxima segurança, você pode construir o corpo POST com jq:

jq -n --arg model "$model" '{model: $model}'

Um loop de descarregamento mais defensivo usaria esse corpo em vez de JSON escapado manualmente.

A VRAM não é liberada imediatamente

Primeiro confirme que o status do modelo mudou. Depois verifique se outra solicitação o recarregou. Lembre-se também que as ferramentas de memória de GPU podem atrasar ou relatar comportamento de alocador em vez de intenção de nível de aplicativo instantânea.

O teste prático é simples: pare o tráfego, descarregue os modelos, liste o status do modelo e, em seguida, inspecione a memória da GPU. Para uso medido de VRAM através de tamanhos de modelo e janelas de contexto no llama.cpp, os benchmarks de llama.cpp com 16 GB de VRAM fornecem números concretos para verificar a sanidade.

Uma versão mais segura do corpo JSON

Se seus identificadores de modelo contiverem caracteres incomuns, use jq para gerar o corpo da solicitação JSON:

curl -s http://localhost:8080/models \
| jq -r '.data[] | select(.status == "loaded") | .id' \
| while IFS= read -r model; do
    echo "Unloading: $model"
    body="$(jq -n --arg model "$model" '{model: $model}')"
    curl -s -X POST http://localhost:8080/models/unload \
      -H "Content-Type: application/json" \
      -d "$body" \
      | jq
  done

Esta é a versão a ser usada se seus modelos forem nomeados com identificadores estilo repositório, aliases personalizados ou caminhos.

Conclusão final

O modo roteador do llama.cpp é um grande avanço para operações de LLM locais. Ele oferece carregamento dinâmico, troca de modelos e expulsão consciente de memória sem sacrificar a diretividade do llama-server.

Mas não espere por um endpoint perfeito de descarregar tudo. A solução limpa já existe: liste os modelos carregados e descarregue-os um por um.

Esse padrão é explícito. É passível de script. Funciona via SSH. Brinca bem com o Open WebUI. E, mais importante, libera VRAM sem reiniciar o roteador.

Para infraestrutura de IA local, é exatamente o tipo de superfície de controle entediante que você quer.

Assinar

Receba novos artigos sobre sistemas, infraestrutura e engenharia de IA.