Guia de Serving do LoRAX: adaptadores LoRA em Kubernetes à escala
Tradução automática Este artigo foi traduzido automaticamente a partir da versão original em inglês.
Um modelo base e muitos adaptadores LoRA criam um problema de serving invulgar. Os pesos base são partilhados, mas cada pedido pode necessitar de um conjunto diferente de pesos de adaptador. Um design convencional, com um deployment por variante, desperdiça memória de GPU quando a maioria das variantes está inactiva.
O LoRAX aborda essa cauda longa. Carrega adaptadores conforme necessário, agrupa em batches pedidos para adaptadores diferentes e move os pesos dos adaptadores entre a memória da GPU e a memória da CPU. A promessa mais apelativa é “milhares de modelos fine-tuned numa só GPU”. A questão de engenharia é mais específica: dado o seu conjunto activo de adaptadores, padrão de chegadas e objectivo de latência, o exchange scheduling traz benefícios suficientes para justificar outro runtime de serving?
Este guia destina-se a engenheiros de inferência e de plataformas que precisam de servir muitas variantes LoRA a partir de um único modelo base. Mostra como testar as APIs documentadas, dimensionar o working set e transformar o Helm chart inicial num plano de produção explícito.
Resumo. Escolha o LoRAX quando muitos adaptadores LoRA compatíveis partilham um modelo base e o tráfego é esparso ou de cauda longa. A capacidade depende do working set activo, não do tamanho do catálogo. Fixe o runtime, autentique e faça allowlist dos IDs dos adaptadores, adicione caching persistente de artefactos e probes, faça routing para aproveitar a localidade da cache e avalie separadamente os percursos cold e warm.
O problema de serving é o working set
O LoRA congela um modelo base e aprende actualizações de baixa dimensão para matrizes de pesos seleccionadas. O adaptador resultante é normalmente muito mais pequeno do que um checkpoint completo, mas o seu tamanho continua a depender do rank, dos target modules, do número de camadas e do dtype. Afirmações fixas como “cada adaptador tem 100 MB” são maus dados de entrada para o dimensionamento.
Para serving, distinga três quantidades:
- Tamanho do catálogo: todos os adaptadores que uma plataforma consegue resolver a partir do armazenamento
- Working set activo: adaptadores que recebem pedidos durante a janela de retenção da cache
- Conjunto concorrente: adaptadores representados em batches no mesmo instante
Um catálogo pode conter milhares de adaptadores sem que seja possível manter milhares na VRAM. O que importa é a frequência com que o conjunto activo muda, o tamanho desses adaptadores e se os pedidos para adaptadores diferentes conseguem partilhar batches úteis.
O LoRAX combina quatro mecanismos:
- O modelo base permanece residente para todos os adaptadores compatíveis.
- Um pedido identifica um adaptador, que pode ser resolvido a partir do Hugging Face, do Predibase ou de um sistema de ficheiros.
- O exchange scheduling de adaptadores faz prefetch e offload dos pesos entre a GPU e a memória da CPU.
- O heterogeneous continuous batching agrupa pedidos destinados a adaptadores diferentes.
O projecto LoRAX reporta que o heterogeneous batching mantém o throughput e a latência quase constantes à medida que cresce o número de adaptadores concorrentes nos seus benchmarks. Trate esse resultado do fornecedor como uma hipótese para a sua carga de trabalho. O comprimento dos prompts, o comprimento das respostas, o rank, os target modules, a ocupação dos batches, o churn da cache e a geração da GPU podem alterar o resultado.
O gráfico restaurado abaixo provém do relatório de lançamento do LoRAX de Novembro de 2023 da Predibase. A Predibase avaliou o Llama 2 7B com pedidos distribuídos por 1 a 128 adaptadores numa NVIDIA A10G. Este gráfico mostra a comparação de custos para 1 a 32 adaptadores no processamento de um milhão de tokens, distribuídos uniformemente pelos adaptadores.

Comparação arquivada do projecto, reproduzida do relatório do LoRAX de 2023 da Predibase. Os custos do LoRAX e dos deployments dedicados usam GPU-hours dessa experiência. Ao nível de detalhe da fonte, a linha do GPT-3.5 Turbo usa o custo por token do modelo fine-tuned.
Leia as barras laranja horizontais como um resultado do desenho desse benchmark, não como uma promessa de preço actual. O teste enviou um total fixo de um milhão de tokens e permitiu que diferentes adaptadores partilhassem um batch. A baseline dedicada assumia compute alojado separado para cada modelo, pelo que o custo aumentava com o número de modelos.
A Predibase não divulgou estes dados de entrada do benchmark:
- mistura de tokens de prompt e de resposta
- comprimentos dos pedidos
- tamanho do batch
- rank do adaptador
- preço por GPU-hour
- modelo exacto de utilização dos deployments dedicados
- preços históricos exactos de input e output do GPT-3.5
Por conseguinte, o relatório não contém informação suficiente para reproduzir de forma independente os valores monetários apresentados no gráfico.
O gráfico também não abrange tráfego esparso, downloads cold, preços actuais da cloud, GPUs mais recentes, outros modelos base ou adaptadores com ranks diferentes. Sustenta a necessidade de replay da carga de trabalho. Não o pode substituir.
Quando o LoRAX é uma opção plausível
O LoRAX merece ser avaliado quando todas estas condições se verificam:
- os adaptadores foram treinados contra o mesmo modelo base suportado e o mesmo contrato de tokenizer
- o tráfego abrange muitos adaptadores, com uma cauda longa relevante
- carregar um adaptador cold conforme necessário é preferível a reservar um deployment para esse adaptador
- o routing por tenant ou tarefa já existe na fronteira da aplicação
- a equipa consegue operar um runtime de inferência especializado e o respectivo comportamento de cache
Casos típicos incluem assistentes específicos de cada tenant, muitas variantes de domínio e experiências online que partilham um checkpoint base.
O LoRAX é menos adequado quando poucos adaptadores concentram a maior parte do tráfego ou quando os modelos não partilham um modelo base. Também é menos adequado quando objectivos de latência rígidos não toleram cold loads ou quando a plataforma não consegue controlar com segurança quais os artefactos que o servidor carrega. Nesses casos, um deployment de vLLM ou TGI com um conjunto fixo de adaptadores pode ser mais simples.
Não use Kubernetes apenas porque o catálogo é grande. Primeiro valide o runtime e a compatibilidade dos adaptadores numa única GPU.
Experimente localmente com um modelo base e um adaptador
O README do LoRAX recomenda o seu container pré-compilado. Num ambiente real, use um image digest imutável. main é apresentado aqui apenas porque é a tag de quick-start documentada pelo repositório. Estes exemplos são ilustrativos e não foram verificados localmente neste checkout. Confirme-os com as versões da imagem e das dependências que irá implementar.
mkdir -p data
docker run --rm --gpus all --shm-size 1g \
-p 8080:80 \
-v "$PWD/data:/data" \
ghcr.io/predibase/lorax:main \
--model-id mistralai/Mistral-7B-Instruct-v0.1
O mínimo documentado é Linux, Docker, uma GPU NVIDIA Ampere ou mais recente e drivers compatíveis com CUDA 11.8. As licenças dos modelos e os repositórios com acesso restrito também podem exigir um token do Hugging Face.
Comece pelo modelo base:
curl http://127.0.0.1:8080/generate \
-H 'Content-Type: application/json' \
-d '{
"inputs": "[INST] Give one reason to measure cold-adapter latency. [/INST]",
"parameters": {"max_new_tokens": 64}
}'
Depois envie um adaptador compatível:
curl http://127.0.0.1:8080/generate \
-H 'Content-Type: application/json' \
-d '{
"inputs": "[INST] Solve: Natalia sold 48 clips in April and half as many in May. What is the total? [/INST]",
"parameters": {
"max_new_tokens": 64,
"adapter_id": "vineetsharma/qlora-adapter-Mistral-7B-Instruct-v0.1-gsm8k"
}
}'
O primeiro pedido pode descarregar e carregar o adaptador. Os pedidos seguintes podem utilizar artefactos em cache e pesos residentes. Registe ambos os percursos. Um único pedido warm diz pouco sobre o comportamento de cauda longa.
Use um cliente compatível com OpenAI
O LoRAX expõe um endpoint de chat compatível com OpenAI. O campo model identifica o adaptador:
from openai import OpenAI
client = OpenAI(
api_key="EMPTY",
base_url="http://127.0.0.1:8080/v1",
)
response = client.chat.completions.create(
model="alignment-handbook/zephyr-7b-dpo-lora",
messages=[
{"role": "user", "content": "Explain cache locality in two sentences."},
],
max_tokens=100,
)
print(response.choices[0].message.content)
Por omissão, o servidor não exige uma API key. Isso é conveniente para localhost, mas inseguro numa configuração exposta à Internet. Coloque autenticação, autorização por tenant, quotas e allowlisting de adaptadores à frente do servidor.
Defina um compatibility gate
Antes de um adaptador entrar no catálogo, verifique pelo menos:
- modelo base e revisão declarados
- compatibilidade do tokenizer e do chat template
- rank LoRA e target modules suportados pelo runtime
- formato do artefacto e formas dos tensores
- licença, proveniência e digest de integridade
- um pequeno conjunto de testes comportamentais e de regressão
Rejeite artefactos incompatíveis durante o registo, em vez de o fazer no primeiro pedido de um utilizador.
Compreenda a residência antes de fazer o deployment
O modelo base consome a maior parcela fixa da memória da GPU. Os pesos dos adaptadores, a KV cache, o workspace dos batches e os kernels do runtime competem pelo espaço restante. A RAM da CPU pode conter adaptadores em offload, enquanto /data armazena os artefactos descarregados.
Estas camadas não são intercambiáveis. Um artefacto num disco ou Hub tem de ser lido e materializado antes de se tornar um adaptador residente na CPU ou na GPU. Meça as transições separadamente:
| Percurso | O que inclui | Métrica a registar |
|---|---|---|
| GPU hit | Adaptador já residente | tempo em fila e time to first token |
| CPU hit | Transferência ou rematerialização para a GPU | atraso de carregamento do adaptador e latência end-to-end |
| Artifact hit | Leitura da cache local /data | atraso de leitura/carregamento e bytes em cache |
| Remote miss | Download, validação e carregamento | tempo de download, falhas e latência cold total |
O capacity planning deve reproduzir a distribuição real de popularidade dos adaptadores. IDs de adaptadores aleatórios uniformes criam um problema de cache diferente do de uma carga de trabalho de tenants com distribuição Zipf.
Implemente o chart do repositório com cuidado
O repositório contém charts/lorax, pelo que o ponto de partida repetível é uma revisão fixa do repositório e um chart local:
git clone https://github.com/predibase/lorax.git
cd lorax
git checkout <reviewed-commit-or-release>
helm dependency update charts/lorax
helm template lorax charts/lorax -f values.production.yaml
helm upgrade --install lorax charts/lorax \
--namespace inference \
--create-namespace \
-f values.production.yaml
Tal como verificado em 15 de Julho de 2026, os values do chart e o template do Deployment apresentam defaults que merecem atenção:
- a tag da imagem é
latest /dataé umemptyDir, pelo que a substituição do pod elimina os artefactos descarregados- os probes de liveness e readiness estão vazios
- o token do Hugging Face é modelado como um valor literal de ambiente
- é solicitada uma GPU por omissão
O chart é um bom ponto de partida. Não é uma política de produção.
Comece pela estrutura efectiva de values do chart
O chart aninha a configuração do runtime sob deployment, e os argumentos do launcher são uma lista de pares nome/valor. Uma sobreposição mínima teria este aspecto:
deployment:
replicas: 1
image:
repository: ghcr.io/predibase/lorax
tag: "<tested-release-tag>"
args:
- name: "--model-id"
value: "mistralai/Mistral-7B-Instruct-v0.1"
- name: "--max-input-length"
value: "2048"
- name: "--max-total-tokens"
value: "3072"
- name: "--max-batch-total-tokens"
value: "8192"
- name: "--max-batch-prefill-tokens"
value: "4096"
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
env:
- name: HUGGING_FACE_HUB_TOKEN
valueFrom:
secretKeyRef:
name: lorax-hub
key: token
readinessProbe:
httpGet:
path: /health
port: http
periodSeconds: 5
failureThreshold: 600
service:
serviceType: ClusterIP
port: 80
Os limites de tokens acima são valores iniciais exemplificativos, não recomendações de dimensionamento. Derive-os a partir de prompts representativos, concorrência esperada, memória da GPU e testes de carga.
Corrija explicitamente as lacunas
O template actual do chart passa deployment.env através de toYaml, pelo que uma sobreposição normal de values pode usar valueFrom.secretKeyRef para as credenciais do Hub, como acima. O template fixa os volumes de emptyDir, não tem um hook de startupProbe e formata sempre a imagem como repository:tag. Por isso, um ficheiro de values, por si só, não consegue fornecer /data persistente, uma startup probe ou pinning por image digest; para essas alterações, use um fork do chart revisto, um patch pós-render ou uma camada de manifests de nível superior. Inclua nessa camada de produção:
- um PersistentVolumeClaim ou uma cache de artefactos local ao nó montada em
/data - uma startup probe antes de uma liveness probe agressiva
- política de interrupção de pods e distribuição por topologia para múltiplas réplicas
- NetworkPolicy, restrições da service account e um gateway autenticado
- pinning por image digest e verificações de integridade dos artefactos
Não coloque um token do Hub directamente num ficheiro de values versionado. Duas réplicas só fornecem alta disponibilidade útil se ambas conseguirem carregar o modelo base. O router também deve evitar enviar cada adaptador cold para ambos os pods.
Faça routing para aproveitar a localidade da cache
O balanceamento round-robin pode transformar cada réplica numa cache cold. Um router útil associa um ID de adaptador permitido a uma réplica através de hash ou de outra regra estável. Deve manter um percurso de failover para os casos em que essa réplica esteja indisponível.
A chave de routing deve provir do estado autenticado da aplicação, não de um parâmetro arbitrário num URL público. Caso contrário, um chamador pode forçar downloads remotos, provocar churn nas caches ou sondar nomes de adaptadores privados.
LoRAX ou vLLM?
A documentação actual do vLLM descreve módulos LoRA declarados no arranque e carregamento dinâmico através de endpoints ou resolver plugins. Avisa que a actualização de adaptadores em runtime envolve riscos de segurança e não deve ser utilizada em produção fora de um ambiente isolado e de confiança.
A comparação útil é operacional, não numérica:
| Questão | LoRAX | vLLM |
|---|---|---|
| Como são descobertos os adaptadores de cauda longa? | O ID do adaptador pode resolver artefactos do Hugging Face, Predibase ou sistema de ficheiros durante o pedido | Módulos estáticos, endpoints de gestão dinâmica ou resolver plugins |
| Como é gerida a residência? | Exchange scheduling explícito de adaptadores entre a GPU e a CPU | Limites configurados de LoRA activo e na CPU, mais o comportamento do resolver |
| Qual é a interface de pedidos? | /generate ao estilo TGI, cliente Python e chat compatível com OpenAI | Serving compatível com OpenAI e APIs Python nativas |
| O que deve decidir? | Latência cold/warm, churn da cache, throughput de batches heterogéneos e adequação operacional | O mesmo replay da carga de trabalho e os mesmos critérios operacionais |
Evite regras como “LoRAX para 1.000 adaptadores, vLLM para dez”. O tamanho do catálogo, por si só, não determina o desempenho. Avalie ambos com o mesmo modelo base, adaptadores, prompts, ranks, trace de chegadas e hardware.
Um teste de aceitação para produção
Antes de expandir o catálogo, execute um replay que inclua:
- Um conjunto hot fixo para estabelecer o throughput e a latência warm.
- Uma distribuição de cauda longa para medir hits da CPU e da cache de artefactos.
- Um burst de adaptadores anteriormente desconhecidos, mas permitidos.
- Substituição de um pod para medir a recuperação do modelo base e dos adaptadores.
- Um adaptador indisponível ou corrompido para verificar isolamento e fallback.
- Tenants concorrentes para verificar autenticação, quotas e labels das métricas.
Acompanhe estas métricas:
- taxa de pedidos
- tempo em fila
- time to first token
- latência entre tokens
- latência total
- tempo de carregamento do adaptador
- classe do cache hit
- memória da GPU
- memória da CPU
- bytes descarregados
- falhas por motivo
Mantenha os IDs dos adaptadores fora de labels de métricas sem limite. Mapeie-os para dimensões controladas ou traces amostrados.
Defina os limiares de aceitação antes do teste. Estabeleça uma taxa máxima de erros no percurso cold e um objectivo de P99 warm. Defina também um objectivo de cache hit para a distribuição de popularidade observada e um objectivo de tempo de recuperação após a perda de um pod.
Conclusão
O LoRAX transforma muitos fine-tunes compatíveis numa questão de placement de adaptadores, em vez de numa frota de cópias do modelo base. Pode ser uma arquitectura forte para cargas de trabalho de cauda longa, mas não torna os custos ou a latência constantes por definição. O working set activo, o percurso de exchange, a composição dos batches e a camada de armazenamento continuam a determinar o resultado.
Valide primeiro esses mecanismos numa única GPU. Depois trate o Kubernetes com o devido rigor: fixe os artefactos, preserve a cache, proteja as credenciais, autorize os adaptadores, faça routing para aproveitar a localidade e meça todos os percursos de residência. Se o LoRAX superar uma configuração actual de vLLM sob o mesmo replay, a decisão de deployment terá evidência concreta.
Referências
- Repositório e README do LoRAX — funcionalidades suportadas, requisitos, APIs e Helm chart
- Relatório de lançamento do LoRAX e benchmark de 2023 — fonte e condições do gráfico de custos restaurado
- Values do chart do LoRAX e template do Deployment — defaults actuais e comportamento dos volumes
- Adaptadores LoRA do vLLM — serving estático e dinâmico de adaptadores
- Artigo sobre LoRA — método de adaptação de baixa dimensão
- Documentação PEFT do Hugging Face — formatos dos adaptadores e integração com treino