Início rápido com Docker
Rode o SDK sem instalar Python ou PyTorch no seu host. Para o início rápido em CPU, reserve 8 GB de RAM e 10 GB de disco livre, com Docker Engine ou Docker Desktop e Compose v2 ou mais novo.
A partir da raiz do repositório:
docker compose run --build --rm laya
Isso compila o checkout, roda a solicitação de exemplo
em CPU e imprime JSON cobrindo choice, score e noul. A primeira solicitação baixa o checkpoint
público selecionado do Hugging Face; nenhuma conta é necessária. Reserve vários minutos para o
primeiro download. Os pesos ficam em um volume nomeado. As execuções seguintes usam
docker compose run --rm laya.
Predições e confiança ainda precisam de avaliação na sua carga de trabalho. Veja os limites de benchmark.
Para hosts ARM64, DGX Spark e Apple Silicon, veja Contêineres ARM64 e DGX Spark.
NVIDIA GPU / CUDA
Instale um driver NVIDIA compatível e configure o Docker com o NVIDIA Container Toolkit. A imagem de GPU usa wheels do PyTorch para CUDA 12.8. Verifique a capacidade de computação e o driver da sua GPU contra as compilações suportadas pelo PyTorch; placas mais antigas podem exigir uma compilação diferente. Reserve espaço em disco adicional para as camadas CUDA. A necessidade de VRAM depende do checkpoint, do tamanho do lote e do comprimento da entrada.
docker compose -f compose.yaml -f compose.cuda.yaml run --build --rm laya
O override seleciona a GPU 0 e usa LAYA_DEVICE=cuda por padrão. Defina LAYA_GPU_ID para outro
índice de host ou UUID. Essa GPU aparece como dispositivo 0 dentro do contêiner. Verifique o acesso
sem baixar pesos:
docker compose -f compose.yaml -f compose.cuda.yaml run --rm laya python -c \
'import torch; assert torch.cuda.is_available(); print(torch.cuda.get_device_name(0)); print(torch.ones(1, device="cuda").cpu())'
O exemplo rejeita uma CUDA indisponível antes de carregar um checkpoint. O Laya ainda pode voltar para CPU depois de um erro de memória ou de inferência, então inspecione seus avisos. Recompile ao alternar entre as configurações de CPU e CUDA.
A imagem define TORCH_DISABLE_NATIVE_JIT=1. Caso contrário, o PyTorch 2.14 substitui algumas ops
CUDA em modo eager por kernels Triton que ele compila na primeira inferência, o que exige um
compilador C que a imagem enxuta não traz: o contêiner se reporta saudável e depois falha toda
solicitação (#365). Os kernels padrão dão as mesmas respostas na mesma latência. Defina a mesma
variável em uma instalação bare-metal se predict falhar com Failed to find C compiler.
Isso usa as reservas de GPU do Compose. O Windows exige a configuração de GPU com WSL2 suportada pelo Docker Desktop. Contêineres com MPS da Apple, AMD/ROCm e GPU Intel estão fora deste início rápido; use CPU, a menos que você configure e valide outro backend.
Configuração
Defina as variáveis do Compose no seu shell, em um arquivo .env local, ou no bloco environment do
serviço. Não faça commit de segredos no .env. As variáveis de runtime também funcionam com
docker run -e; as configurações exclusivas do Compose são identificadas abaixo.
| Variável | Padrão | Propósito |
|---|---|---|
LAYA_DEVICE |
cpu / cuda |
Dispositivo selecionado pela configuração base / de GPU |
LAYA_CUDA_AMP |
não definido (amp_dtype do checkpoint) |
fp16/float16 ou bf16/bfloat16 para o forward em CUDA; qualquer outro valor é ignorado. Não é cosmético: a seção de limiar do README mede o bf16 virando 3 de 864 argmaxes no conjunto de paridade, onde o fp16 não vira nenhum |
LAYA_CPU_AMP |
não definido | bf16 ou bfloat16 coloca o forward em CPU em bf16; qualquer outro valor o deixa em fp32. Nenhuma grafia de fp16 o ativa também: o autocast de CPU não tem um caminho rápido de fp16 que supere o fp32, então bf16 é a única precisão reduzida que o core oferece neste dispositivo |
LAYA_MODEL |
auto |
Alias do Router: auto, english, multilingual, typed-decisions |
LAYA_MODEL_PATH |
não definido | Caminho de checkpoint compatível dentro do contêiner |
LAYA_REVISION |
não definido | Commit, branch ou tag do Hub usado em todo download de checkpoint, ou reviewed para os SHAs revisados em laya/revisions.py; um argumento revision= ainda vence |
LAYA_REQUEST_FILE |
solicitação incluída | Caminho da solicitação JSON dentro do contêiner |
OMP_NUM_THREADS |
4 |
Threads de CPU; mantenha dentro dos núcleos disponíveis |
HF_TOKEN / HF_TOKEN_FILE |
não definido | Credencial opcional do Hugging Face |
LAYA_API_KEY / LAYA_API_KEY_FILE |
não definido | Somente laya-serve: exige Authorization: Bearer <key> |
LAYA_PORT |
8000 |
Somente laya-serve: porta do contêiner, e a porta do host publicada para ela |
HF_HUB_OFFLINE |
0 |
1 usa apenas checkpoints em cache |
HF_HOME |
/home/laya/.cache/huggingface |
Caminho do cache; veja o requisito de montagem abaixo |
LAYA_CACHE_VOLUME |
cache de modelo do projeto | Somente Compose: volume de cache nomeado |
LAYA_GPU_ID |
0 |
Somente Compose: índice ou UUID do dispositivo NVIDIA |
LAYA_TORCH_INDEX |
cpu / cu128 / cu130 |
Build do Compose: índice de wheels do PyTorch |
LAYA_TORCH_VERSION |
2.14.0 |
Build do Compose: versão do PyTorch fixada |
O Compose repassa as variáveis de runtime, exceto HF_HOME, que fica alinhada com sua montagem de
cache fixa, e exceto LAYA_MPS_AMP_MIN_ROWS, o gate de linhas do MPS, que nenhuma imagem aqui
consegue alcançar porque nenhum contêiner aqui consegue selecionar MPS.
Se você sobrescrever HF_HOME no docker run ou no seu próprio arquivo Compose, forneça uma
montagem correspondente gravável pelo UID 10001. Compilações diretas do Docker selecionam o PyTorch
com --build-arg TORCH_INDEX=cu128; um -e de runtime não consegue mudar a wheel instalada.
LAYA_MODEL=english OMP_NUM_THREADS=2 docker compose run --build --rm laya
docker build -t laya:local .
docker run --rm -e LAYA_MODEL=english -e OMP_NUM_THREADS=2 \
-v laya-model-cache:/home/laya/.cache/huggingface laya:local
Para sua própria solicitação:
docker compose run --rm --volume "$PWD/request.json:/inputs/request.json:ro" \
--env LAYA_REQUEST_FILE=/inputs/request.json laya
Para uma configuração comentada com montagens de solicitação, checkpoint e arquivo de segredo, veja
compose.example.yml:
docker compose -f compose.yaml -f compose.example.yml run --build --rm laya
Adicione -f compose.cuda.yaml antes de run para GPUs NVIDIA. O exemplo é um override de
compose.yaml, então as configurações de cache e de imagem ficam em um único lugar.
Arquivos de segredo
HF_TOKEN_FILE lê um arquivo UTF-8 montado na inicialização, remove espaços em branco ao redor e tem
precedência sobre HF_TOKEN. Arquivos ilegíveis, vazios ou inválidos interrompem a inicialização sem
imprimir seu conteúdo. O arquivo precisa ser legível pelo UID 10001. _FILE se aplica apenas a
segredos suportados, não a toda configuração.
Com HF_TOKEN_PATH apontando para um arquivo de host existente fora do checkout:
docker compose run --rm --volume "$HF_TOKEN_PATH:/run/secrets/hf_token:ro" \
--env HF_TOKEN_FILE=/run/secrets/hf_token laya
Docker secrets ou volumes Secret do Kubernetes podem fornecer o mesmo arquivo. Os valores são carregados no ambiente do processo na inicialização; reinicie depois de mudar um arquivo. Nunca use tokens como argumentos de compilação nem os embuta em imagens. Checkpoints públicos não precisam de token.
Checkpoints ajustados
Esta imagem roda inferência. O ajuste fino acontece fora dela — o notebook de ajuste fino roda todo o ciclo nas GPUs 2xT4 gratuitas do Kaggle e exporta um checkpoint que esta imagem consegue servir. Contexto e questões em aberto sobre a interface de treino ficam nos #4 e #26.
Aponte LAYA_CHECKPOINT_PATH para um diretório absoluto do host contendo
rl_agent_config.json, model.safetensors e arquivos de tokenizer correspondentes:
docker compose run --rm --volume "$LAYA_CHECKPOINT_PATH:/models/custom" \
--env LAYA_MODEL_PATH=/models/custom laya
Use uma cópia de trabalho gravável pelo UID 10001 porque o loader pode atualizar a configuração do
tokenizer. Um adaptador LoRA sozinho não é um checkpoint completo. Deixe LAYA_MODEL=auto ao definir
LAYA_MODEL_PATH; um alias explícito e um caminho local são mutuamente exclusivos. A resposta de
caminho local vem do Agent e não tem metadados routing do Router. Essas configurações também
funcionam com o override de CUDA. Avalie checkpoints ajustados em exemplos reservados antes de
confiar neles.
Modelos do ModelScope
Quando um host não consegue alcançar huggingface.co, o checkpoint pode vir do ModelScope e ser assado na imagem em tempo de build. Um argumento escolhe qual checkpoint, e o padrão é o multilíngue. O override do Compose adiciona os argumentos de prefetch aos dois serviços e mantém o contêiner fora do Hub:
docker compose -f compose.yaml -f compose.http.yaml -f compose.modelscope.yaml up --build laya-serve
Para NVIDIA, adicione -f compose.cuda.yaml antes de up; ele repete os próprios argumentos
para os dois serviços, então a ordem entre os dois overrides não importa. O Docker puro pega os
argumentos diretamente:
docker build --build-arg MODELSCOPE_MODEL=multilingual \
-t laya:local .
docker run --rm -e HF_HUB_OFFLINE=1 -p 127.0.0.1:8000:8000 laya:local laya-serve
Um pré-requisito em um host que já rodou isto antes. Os pesos assados ficam em $HF_HOME/hub
dentro da imagem, sob o diretório de cache em que o compose.yaml monta o volume model-cache
(/home/laya/.cache/huggingface), e o Docker semeia um volume nomeado a partir da imagem
apenas enquanto esse volume está vazio. Um volume deixado pelo início rápido baseado no Hub
contém o snapshot antigo do Hub, nunca é semeado de novo, e os pesos assados ficam invisíveis
atrás dele: o loader resolve refs/main para o commit antigo do Hub e o contêiner responde com
os pesos que já tinham sido baixados, como se a reconstrução não tivesse mudado nada. Aponte a
implantação para um volume de cache vazio — docker compose down --volumes com os mesmos
arquivos Compose e o mesmo LAYA_CACHE_VOLUME, ou LAYA_CACHE_VOLUME=<name> para um novo. Com
HF_HUB_OFFLINE=1, um ref ausente ou divergente é uma falha de carregamento sem rede para onde
recorrer, mas o pré-requisito é o mesmo.
docker/prefetch_modelscope.py
lista o repositório em modelscope.cn, baixa os arquivos próprios do checkpoint — o mesmo
conjunto que o laya/agent.py pede ao Hub, então nenhum checkpoint irmão é puxado — e os
escreve no cache hub da imagem do jeito que o snapshot_download dispõe um snapshot. Nada mais
muda: Agent, o Router que o laya-serve constrói, laya.cli e as integrações mantêm seus
ids de repositório e os resolvem para o snapshot assado, então um contêiner construído assim
não precisa de rede alguma. O tamanho de cada arquivo é conferido contra o que o repositório
reporta antes de o snapshot ser publicado, e seu SHA-256 também quando o repositório publica um.
Uma divergência de tamanho ou digest faz o build falhar. Um repositório que não publica nenhum
digest deixa a checagem só no tamanho, que não consegue detectar uma substituição do mesmo
tamanho.
| Variável | Padrão | Propósito |
|---|---|---|
MODELSCOPE_MODEL |
multilingual (Compose); vazio no Dockerfile |
Checkpoint a assar: multilingual, english, typed-decisions ou all. Vazio significa sem prefetch e a imagem inalterada |
MODELSCOPE_REVISION |
master |
Branch, tag ou commit do ModelScope a assar |
HF_HUB_OFFLINE |
1 no override do Compose |
1 nunca contata o Hub, então a cópia assada é servida |
Um tipo se expande para o caminho desse checkpoint dentro do repositório empacotado, que é o
que o Router e o início rápido de uma vez carregam por padrão, então um build que nomeia um
tipo o serve sem mais mudanças:
MODELSCOPE_MODEL=english docker compose -f compose.yaml -f compose.http.yaml -f compose.modelscope.yaml up --build laya-serve
MODELSCOPE_MODEL=all docker compose -f compose.yaml -f compose.http.yaml -f compose.modelscope.yaml up --build laya-serve
all é a família inteira, cerca de 2,4 GB de pesos. O override também define
LAYA_MODELS=multilingual, porque LAYA_PRELOAD=1 com a lista padrão tentaria construir todo
checkpoint e falharia no primeiro que não foi assado; defina LAYA_MODELS com a lista que você
assou quando assar mais, e MODELSCOPE_MODEL=all quando uma implantação realmente serve a
família.
Vários tipos podem ser nomeados de uma vez — MODELSCOPE_MODEL="english multilingual" assa os
dois, cerca de 1,5 GB — que é o que uma imagem de serviço geralmente quer: o Router escolhe
entre o checkpoint inglês e o multilíngue por conta própria, e um que não recebeu responde
500 inference failed com does not contain 'rl_agent_config.json' no log. Checkpoints que
compartilham um repositório sempre são assados em um único snapshot, porque uma revisão em
cache se resolve em um único diretório; o checkpoint raiz e cada subpasta estão ambos nele.
Além dos tipos, o argumento também aceita especificações repo[:subfolder], separadas por
vírgula ou espaço, que é como os repositórios autônomos do espelho
(laya,
laya-multilingual,
laya-typed-decisions) ou
um checkpoint ajustado são assados. Um repositório autônomo é o que o
Agent("convaiinnovations/laya-multilingual") carrega diretamente; o padrão do Router é o
caminho empacotado, então um tipo é normalmente o que uma imagem de serviço quer.
Dois detalhes sobre pins e proveniência. O build imprime o commit com que o snapshot é
chaveado, que é a ponta da revisão assada — passe esse SHA como revision= ou LAYA_REVISION
para fixar um carregamento exatamente no que foi assado. Um repositório espelho pode conter
arquivos de vários uploads, então essa ponta é a única chave no nível do repositório que
existe. Pins do lado do Hub não descrevem um snapshot espelho: reviewed nomeia commits do
Hugging Face, e o mapa de digests SHA-256 é chaveado a hashes de artefatos do Hub, então nenhum
se aplica aqui, e também não existe pin de digest para um snapshot espelho. O build já recusa
um download que não bate com o tamanho reportado pelo espelho — e com seu digest, quando o
espelho publica um — mas isso confere consistência com os metadados do espelho, não um digest
fixado de forma independente. Os pesos vêm da conta de espelho que o argumento nomeia, o que é
uma decisão de cadeia de suprimentos própria que a implantação deve tomar.
Desenvolvimento e limpeza
Abra um prompt Python com docker compose run --rm laya python. Para rodar os checks de
roteamento/critérios e os testes de arquivo de segredo existentes contra seu checkout sem baixar
pesos:
docker compose run --rm --volume "$PWD:/workspace:ro" --workdir /workspace laya \
sh -ec 'python tests/test_router.py; python tests/test_criteria.py; python tests/test_docker_entrypoint.py'
Recompile com --build depois de mudar o código-fonte ou o exemplo incluído. A imagem roda como
UID/GID 10001. Volumes nomeados novos herdam a propriedade do diretório de cache da imagem;
diretórios do host precisam ser graváveis por esse UID. Mantenha os caches de modelo graváveis para
atualizações de compatibilidade do tokenizer.
--rm remove contêineres concluídos. docker compose down mantém o cache.
Para excluir os pesos baixados, rode docker compose down --volumes usando os mesmos arquivos
Compose e a mesma configuração de LAYA_CACHE_VOLUME. A próxima solicitação os baixa de novo; não
remova um cache compartilhado com outro projeto.
Serviço HTTP
A imagem traz laya-serve, então a mesma compilação que roda o início rápido de uma vez pode servir
a API compatível com o Jev. O compose.http.yaml o adiciona como um segundo serviço e deixa o
laya intacto:
docker compose -f compose.yaml -f compose.http.yaml up --build laya-serve
curl -s localhost:8000/health
curl -s localhost:8000/v1/systemone -H 'content-type: application/json' \
--data @examples/docker/request.json
Para NVIDIA, adicione o override de CUDA. Ele repete os argumentos de compilação e a reserva de
dispositivo para o laya-serve, porque laya-serve é um serviço separado e overrides para o laya
nunca chegam até ele:
docker compose -f compose.yaml -f compose.http.yaml -f compose.cuda.yaml up --build laya-serve
up mantém o serviço rodando em primeiro plano; -d o desanexa. Os pesos vão para o mesmo volume
nomeado model-cache do início rápido, então servir depois de uma execução do início rápido começa
com os checkpoints já em disco. Pare com docker compose ... down, usando os mesmos arquivos
Compose.
A porta é publicada apenas em 127.0.0.1. A API não tem autenticação até LAYA_API_KEY ser
definido, então defina uma chave antes de expô-la com LAYA_BIND_ADDRESS=0.0.0.0, e coloque um proxy
reverso com TLS na frente para clientes remotos. O /health não exige autenticação em nenhum dos
casos, então o healthcheck abaixo continua funcionando; com uma chave definida, ele responde a um
chamador não autenticado {"status": "ok"} e retém os campos checkpoint, revision e device, que
precisam do bearer.
O serviço tem um healthcheck em /health. O servidor pré-carrega antes de começar a escutar, então
com LAYA_PRELOAD=1 um contêiner saudável tem seus checkpoints carregados.
docker compose ... up -d --wait laya-serve retorna quando ele está saudável.
O /health reporta device como o dispositivo em que um checkpoint residente de fato computa, que
nem sempre é o que LAYA_DEVICE pediu: um checkpoint que quer uma GPU que não consegue fica em CPU
silenciosamente e ainda responde corretamente. checkpoint_devices nomeia cada checkpoint carregado,
e device_is_preference é true apenas enquanto nada está residente, então uma implantação que
perdeu sua GPU em silêncio diz isso em vez de repetir de volta sua própria configuração.
Configuração do servidor
Estas se aplicam apenas ao serviço laya-serve.
| variável | padrão | efeito |
|---|---|---|
LAYA_HOST |
0.0.0.0 |
endereço de bind dentro do contêiner |
LAYA_PORT |
8000 |
porta do contêiner, e a porta do host publicada para ela |
LAYA_BIND_ADDRESS |
127.0.0.1 |
endereço do host onde a porta é publicada |
LAYA_PRELOAD |
0 |
1 constrói todo checkpoint na inicialização em vez de na primeira solicitação |
LAYA_MODELS |
(todos) | lista separada por vírgulas a pré-carregar: english,multilingual,typed-decisions |
LAYA_THREADS |
OMP_NUM_THREADS |
limita threads intra-op do torch; mantenha em ou abaixo dos núcleos físicos |
LAYA_AUTO_TASK |
0 |
1 deixa o router alcançar typed-decisions automaticamente |
LAYA_DEFAULT_MODEL |
english |
Checkpoint para o qual recorre um estado sem evidência de idioma (sem letras, ou texto latino curto demais para identificar). Defina multilingual para tráfego majoritariamente não inglês; um nome que não pode ser resolvido para o contêiner na inicialização em vez de servir uma configuração que ninguém pediu |
LAYA_MAX_LOADED |
2 |
Checkpoints mantidos residentes; LAYA_AUTO_TASK torna um terceiro alcançável sob demanda, e um teto abaixo do que o roteamento escolhe reconstrói um por troca |
LAYA_MAX_CONCURRENT |
16 |
solicitações admitidas de uma vez; as posteriores recebem 503 (um valor que não faz parsing, ou não é positivo, volta para 16) |
LAYA_LOG_LEVEL |
info |
nível de log do uvicorn |
LAYA_API_KEY |
(nenhum) | quando definido, exige Authorization: Bearer <key> |
LAYA_ROOT_PATH |
(vazio) | prefixo de URL público para o FastAPI atrás de um proxy reverso; o proxy deve removê-lo antes de repassar |
LAYA_MAX_TOKEN_BUDGET |
8192 |
teto para os overrides de max_len e head_max_len por solicitação |
LAYA_SHA256_DIGESTS |
(nenhum) | digests JSON verificados antes de um checkpoint ser analisado: {artifact: digest} para todo checkpoint, ou {model: {artifact: digest}} por checkpoint. Veja Segurança |
Por exemplo, defina LAYA_ROOT_PATH=/laya ao publicar a API sob /laya. O proxy deve remover esse
prefixo antes de repassar para o contêiner; essa configuração atualiza as URLs geradas pelo FastAPI
e não muda as rotas internas /health ou /v1/systemone.
LAYA_PRELOAD usa 0 por padrão aqui em vez do padrão 1 do pacote, porque pré-carregar faz o
primeiro boot baixar os três checkpoints. Defina 1 para uma implantação de longa duração, assim a
primeira solicitação não paga pela construção.
LAYA_PORT define tanto a porta publicada no host quanto a porta em que o servidor faz bind, então
as duas não podem divergir. Mude em um único lugar para mover o serviço:
LAYA_PORT=9000 docker compose -f compose.yaml -f compose.http.yaml up --build laya-serve
Bearer token de um arquivo
LAYA_API_KEY_FILE é lido uma vez na inicialização, movido para LAYA_API_KEY, e a variável _FILE
é removida antes de o servidor dar exec. Prefira isto a colocar a chave no ambiente:
docker compose -f compose.yaml -f compose.http.yaml run --rm \
--volume "$PWD/laya_api_key:/run/secrets/laya_api_key:ro" \
-e LAYA_API_KEY_FILE=/run/secrets/laya_api_key \
--service-ports laya-serve