Documentação

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