Documentação

Início rápido com Docker

Executa o SDK sem instalar Python nem PyTorch no teu anfitrião. Para o início rápido em CPU, reserva 8 GB de RAM e 10 GB de disco livre, com o Docker Engine ou o Docker Desktop e o Compose v2 ou mais recente.

A partir da raiz do repositório:

docker compose run --build --rm laya

Isto compila o checkout, corre o pedido de exemplo em CPU e imprime JSON que abrange choice, score e noul. O primeiro pedido descarrega o checkpoint público selecionado do Hugging Face; não é precisa conta. Reserva vários minutos para a primeira transferência. Os pesos ficam num volume nomeado. As execuções seguintes usam docker compose run --rm laya.

As predições e a confiança continuam a precisar de avaliação na tua carga de trabalho. Vê os limites do benchmark.

Para anfitriões ARM64, DGX Spark e Apple Silicon, vê Contentores ARM64 e DGX Spark.

NVIDIA GPU / CUDA

Instala um controlador NVIDIA compatível e configura o Docker com o NVIDIA Container Toolkit. A imagem de GPU usa wheels PyTorch CUDA 12.8. Verifica a capacidade de computação e o controlador da tua GPU em compilações suportadas do PyTorch; placas mais antigas podem exigir uma compilação diferente. Reserva espaço em disco adicional para as camadas CUDA. As necessidades de VRAM dependem do checkpoint, do tamanho de 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 assume LAYA_DEVICE=cuda por predefinição. Define LAYA_GPU_ID para outro índice ou UUID do anfitrião. Essa GPU aparece como dispositivo 0 dentro do contentor. Verifica o acesso sem descarregar 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 pode ainda cair para a CPU após um erro de memória ou de inferência, por isso inspeciona os seus avisos. Recompila ao alternar entre configurações de CPU e CUDA.

A imagem define TORCH_DISABLE_NATIVE_JIT=1. Caso contrário, o PyTorch 2.14 substitui algumas operações CUDA eager por kernels Triton que compila na primeira inferência, o que exige um compilador C que a imagem slim não traz: o contentor reporta-se saudável e depois falha todos os pedidos (#365). Os kernels de origem dão as mesmas respostas à mesma latência. Define a mesma variável numa instalação bare-metal se o predict falhar com Failed to find C compiler.

Isto usa reservas de GPU do Compose. O Windows exige a configuração de GPU WSL2 suportada pelo Docker Desktop. Contentores Apple MPS, AMD/ROCm e GPU Intel estão fora deste início rápido; usa CPU a menos que configures e valides outro backend.

Configuração

Define as variáveis do Compose no teu shell, num ficheiro .env local, ou no bloco environment do serviço. Não faças commit de segredos no .env. As variáveis de runtime também funcionam com docker run -e; as definições exclusivas do Compose estão identificadas abaixo.

Variável Predefinição Finalidade
LAYA_DEVICE cpu / cuda Dispositivo selecionado pela configuração base / de GPU
LAYA_CUDA_AMP não definida (amp_dtype do checkpoint) fp16/float16 ou bf16/bfloat16 para a passagem direta em CUDA; qualquer outro valor é ignorado. Não é cosmético: a secção de limiares do README mede que o bf16 troca 3 de 864 argmaxes no conjunto de paridade onde o fp16 não troca nenhum
LAYA_CPU_AMP não definida bf16 ou bfloat16 opta por bf16 na passagem direta de CPU; qualquer outro valor deixa-a em fp32. Nenhuma grafia de fp16 a ativa também: o autocast de CPU não tem um caminho rápido de fp16 que supere o fp32, por isso 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 definida Caminho de checkpoint compatível dentro do contentor
LAYA_REVISION não definida Commit, ramo ou tag do Hub usados em cada download de checkpoint, ou reviewed para os SHAs revistos em laya/revisions.py; um argumento revision= ainda ganha
LAYA_REQUEST_FILE pedido incluído Caminho do pedido JSON dentro do contentor
OMP_NUM_THREADS 4 Threads de CPU; mantém dentro dos núcleos disponíveis
HF_TOKEN / HF_TOKEN_FILE não definida Credencial opcional do Hugging Face
LAYA_API_KEY / LAYA_API_KEY_FILE não definida Apenas laya-serve: exige Authorization: Bearer <key>
LAYA_PORT 8000 Apenas laya-serve: porta do contentor e porta do anfitrião publicada para ela
HF_HUB_OFFLINE 0 1 usa apenas checkpoints em cache
HF_HOME /home/laya/.cache/huggingface Caminho da cache; vê o requisito de montagem abaixo
LAYA_CACHE_VOLUME cache de modelos do projeto Apenas Compose: volume de cache nomeado
LAYA_GPU_ID 0 Apenas Compose: índice ou UUID do dispositivo NVIDIA
LAYA_TORCH_INDEX cpu / cu128 / cu130 Compilação Compose: índice de wheels do PyTorch
LAYA_TORCH_VERSION 2.14.0 Compilação Compose: versão fixa do PyTorch

O Compose encaminha as variáveis de runtime, exceto HF_HOME, que fica alinhada com a sua montagem de cache fixa, e exceto LAYA_MPS_AMP_MIN_ROWS, o gate de linhas para MPS, que nenhuma imagem daqui consegue alcançar porque nenhum contentor daqui consegue selecionar MPS. Se substituíres HF_HOME em docker run ou no teu próprio ficheiro Compose, fornece uma montagem correspondente que possa ser escrita pelo UID 10001. As compilações diretas do Docker selecionam o PyTorch com --build-arg TORCH_INDEX=cu128; o -e de runtime não pode alterar 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 o teu próprio pedido:

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 pedido, checkpoint e ficheiro de segredo, vê compose.example.yml:

docker compose -f compose.yaml -f compose.example.yml run --build --rm laya

Acrescenta -f compose.cuda.yaml antes de run para GPUs NVIDIA. O exemplo é um override de compose.yaml, por isso as definições de cache e de imagem ficam num só sítio.

Ficheiros de segredos

HF_TOKEN_FILE lê um ficheiro UTF-8 montado no arranque, retira o espaço em branco em volta e tem precedência sobre HF_TOKEN. Ficheiros ilegíveis, vazios ou inválidos param o arranque sem imprimir o seu conteúdo. O ficheiro tem de poder ser lido pelo UID 10001. _FILE aplica-se apenas aos segredos suportados, não a todas as definições.

Com HF_TOKEN_PATH a apontar para um ficheiro existente do anfitrião 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

Os Docker secrets ou os volumes Secret do Kubernetes podem fornecer o mesmo ficheiro. Os valores são carregados no ambiente do processo no arranque; reinicia após alterar um ficheiro. Nunca uses tokens como argumentos de compilação nem os incorpores nas imagens. Os checkpoints públicos não precisam de token.

Checkpoints com ajuste fino

Esta imagem corre inferência. O ajuste fino acontece fora dela — o notebook de ajuste fino corre o ciclo completo nas 2xT4 gratuitas do Kaggle e exporta um checkpoint que esta imagem consegue servir. O contexto e as questões em aberto sobre a interface de treino ficam em #4 e #26.

Aponta LAYA_CHECKPOINT_PATH para um diretório absoluto do anfitrião que contenha rl_agent_config.json, model.safetensors e ficheiros de tokenizer correspondentes:

docker compose run --rm --volume "$LAYA_CHECKPOINT_PATH:/models/custom" \
  --env LAYA_MODEL_PATH=/models/custom laya

Usa uma cópia de trabalho que possa ser escrita pelo UID 10001, porque o carregador pode atualizar a configuração do tokenizer. Um adaptador LoRA sozinho não é um checkpoint completo. Deixa 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. Estas definições também funcionam com o override de CUDA. Avalia os checkpoints com ajuste fino em exemplos reservados antes de confiar neles.

Modelos do ModelScope

Quando um anfitrião não consegue alcançar huggingface.co, o checkpoint pode vir do ModelScope e ser embutido na imagem em tempo de compilação. Um argumento escolhe qual checkpoint, e a predefinição é o multilingue. O override do Compose acrescenta os argumentos de prefetch aos dois serviços e mantém o contentor fora do Hub:

docker compose -f compose.yaml -f compose.http.yaml -f compose.modelscope.yaml up --build laya-serve

Para NVIDIA, acrescenta -f compose.cuda.yaml antes de up; repete os próprios argumentos para os dois serviços, por isso a ordem entre os dois overrides não importa. O Docker simples recebe 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 num anfitrião que já correu isto antes. Os pesos embutidos 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 só semeia um volume nomeado a partir da imagem 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 embutidos ficam invisíveis atrás dele: o carregador resolve refs/main para o commit antigo do Hub e o contentor responde com os pesos que já tinham sido transferidos, como se a recompilação não tivesse mudado nada. Aponta a implementação para um volume de cache vazio — docker compose down --volumes com os mesmos ficheiros Compose e a mesma 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 recuar, mas o pré-requisito é o mesmo.

docker/prefetch_modelscope.py lista o repositório em modelscope.cn, descarrega os ficheiros próprios do checkpoint — o mesmo conjunto que o laya/agent.py pede ao Hub, por isso nenhum checkpoint irmão é puxado — e escreve-os na cache hub da imagem tal como 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 os seus ids de repositório e resolvem-nos para o snapshot embutido, por isso um contentor construído assim não precisa de rede nenhuma. O tamanho de cada ficheiro é verificado contra o que o repositório reporta antes de o snapshot ser publicado, e o seu SHA-256 também quando o repositório publica um. Uma divergência de tamanho ou digest faz a compilação falhar. Um repositório que não publica nenhum digest deixa a verificação só no tamanho, que não consegue detetar uma substituição do mesmo tamanho.

Variável Predefinição Finalidade
MODELSCOPE_MODEL multilingual (Compose); vazio no Dockerfile Checkpoint a embutir: multilingual, english, typed-decisions ou all. Vazio significa sem prefetch e a imagem inalterada
MODELSCOPE_REVISION master Ramo, tag ou commit do ModelScope a embutir
HF_HUB_OFFLINE 1 no override do Compose 1 nunca contacta o Hub, por isso a cópia embutida é servida

Um tipo expande-se para o caminho desse checkpoint dentro do repositório empacotado, que é o que o Router e o início rápido único carregam por predefinição, por isso uma compilação que nomeia um tipo serve-o sem mais alterações:

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 predefinida tentaria construir todos os checkpoints e falharia no primeiro que não foi embutido; define LAYA_MODELS com a lista que embutiste quando embutires mais, e MODELSCOPE_MODEL=all quando uma implementação serve mesmo a família.

Vários tipos podem ser nomeados de uma vez — MODELSCOPE_MODEL="english multilingual" embute os dois, cerca de 1,5 GB — que é o que uma imagem de serviço normalmente quer: o Router escolhe entre o checkpoint inglês e o multilingue 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 partilham um repositório são sempre embutidos num único snapshot, porque uma revisão em cache se resolve num ú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 com ajuste fino são embutidos. Um repositório autónomo é o que o Agent("convaiinnovations/laya-multilingual") carrega diretamente; a predefinição do Router é o caminho empacotado, por isso um tipo é normalmente o que uma imagem de serviço quer.

Dois detalhes sobre pins e proveniência. A compilação imprime o commit com que o snapshot é indexado, que é a ponta da revisão embutida — passa esse SHA como revision= ou LAYA_REVISION para fixar um carregamento exatamente no que foi embutido. Um repositório espelho pode conter ficheiros de vários uploads, por isso essa ponta é a única chave ao 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 é indexado a hashes de artefactos do Hub, por isso nenhum se aplica aqui, e também não existe pin de digest para um snapshot espelho. A compilação já recusa uma transferência que não corresponde ao tamanho reportado pelo espelho — e ao seu digest, quando o espelho publica um — mas isto verifica 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 aprovisionamento própria que a implementação deve tomar.

Desenvolvimento e limpeza

Abre uma consola Python com docker compose run --rm laya python. Para correr as verificações existentes de encaminhamento/critérios e os testes de ficheiros de segredos contra o teu checkout sem descarregar 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'

Recompila com --build após alterar o código-fonte ou o exemplo incluído. A imagem corre como UID/GID 10001. Os volumes nomeados novos herdam a propriedade do diretório de cache da imagem; os diretórios do anfitrião têm de poder ser escritos por esse UID. Mantém as caches de modelos graváveis para atualizações de compatibilidade do tokenizer.

--rm remove os contentores concluídos. docker compose down mantém a cache. Para eliminar os pesos descarregados, corre docker compose down --volumes com os mesmos ficheiros Compose e a mesma definição LAYA_CACHE_VOLUME. O próximo pedido volta a descarregá-los; não removas uma cache partilhada com outro projeto.

Serviço HTTP

A imagem inclui o laya-serve, por isso a mesma compilação que corre o início rápido único pode servir a API compatível com o Jev. O compose.http.yaml acrescenta-o como segundo serviço e deixa o laya em paz:

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, acrescenta o override de CUDA. Ele repete os argumentos de compilação e a reserva de dispositivo para o laya-serve, porque o laya-serve é um serviço separado e os overrides do laya nunca chegam a ele:

docker compose -f compose.yaml -f compose.http.yaml -f compose.cuda.yaml up --build laya-serve

up mantém o serviço a correr em primeiro plano; -d destaca. Os pesos vão para o mesmo volume nomeado model-cache do início rápido, por isso servir após uma execução do início rápido começa com os checkpoints já em disco. Para com docker compose ... down, usando os mesmos ficheiros Compose.

A porta é publicada apenas em 127.0.0.1. A API não tem autenticação até LAYA_API_KEY estar definida, por isso define uma chave antes de a expor com LAYA_BIND_ADDRESS=0.0.0.0, e coloca um reverse proxy TLS à frente para clientes remotos. O /health não exige autenticação em qualquer dos casos, por isso o healthcheck abaixo continua a funcionar; com uma chave definida, 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, por isso com LAYA_PRELOAD=1 um contentor saudável tem os checkpoints carregados. docker compose ... up -d --wait laya-serve regressa assim que estiver saudável.

O /health reporta device como o dispositivo em que um checkpoint residente calcula de facto, que nem sempre é o que LAYA_DEVICE pediu: um checkpoint que quer uma GPU que não consegue obter cai silenciosamente para a CPU e continua a responder corretamente. checkpoint_devices nomeia cada checkpoint carregado, e device_is_preference é true apenas enquanto nada estiver residente, por isso uma implementação que perdeu a sua GPU discretamente diz-o, em vez de repetir a sua própria configuração.

Configuração do servidor

Estas aplicam-se apenas ao serviço laya-serve.

variável predefinição efeito
LAYA_HOST 0.0.0.0 endereço de bind dentro do contentor
LAYA_PORT 8000 porta do contentor e porta do anfitrião publicada para ela
LAYA_BIND_ADDRESS 127.0.0.1 endereço do anfitrião em que a porta é publicada
LAYA_PRELOAD 0 1 constrói todos os checkpoints no arranque em vez de no primeiro pedido
LAYA_MODELS (todos) lista separada por vírgulas a pré-carregar: english,multilingual,typed-decisions
LAYA_THREADS OMP_NUM_THREADS limita as threads intra-op da torch; mantém 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 recua um estado sem evidência de idioma (sem letras, ou texto latino demasiado curto para identificar). Define multilingual para tráfego maioritariamente não inglês; um nome que não pode ser resolvido para o contentor no arranque 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 a pedido, e um limite abaixo do que o encaminhamento escolhe reconstrói um por cada troca
LAYA_MAX_CONCURRENT 16 pedidos admitidos ao mesmo tempo; os seguintes recebem 503 (um valor que não faz parse, ou não positivo, cai para 16)
LAYA_LOG_LEVEL info nível de log do uvicorn
LAYA_API_KEY (nenhuma) quando definida, exige Authorization: Bearer <key>
LAYA_ROOT_PATH (vazio) prefixo de URL público para o FastAPI quando atrás de um reverse proxy; o proxy deve removê-lo antes de encaminhar
LAYA_MAX_TOKEN_BUDGET 8192 limite sobre as substituições por pedido de max_len e head_max_len
LAYA_SHA256_DIGESTS (nenhum) digests JSON verificados antes de um checkpoint ser analisado: {artifact: digest} para cada checkpoint, ou {model: {artifact: digest}} por checkpoint. Vê Segurança

Por exemplo, define LAYA_ROOT_PATH=/laya ao publicar a API em /laya. O proxy tem de remover esse prefixo antes de encaminhar para o contentor; esta definição atualiza os URLs gerados pelo FastAPI e não altera as rotas internas /health ou /v1/systemone.

Aqui, LAYA_PRELOAD assume 0 por predefinição, em vez do 1 predefinido do pacote, porque o pré-carregamento faz com que o primeiro arranque descarregue os três checkpoints. Define-a como 1 para uma implementação de longa duração, para que o primeiro pedido não pague a construção.

LAYA_PORT define tanto a porta publicada do anfitrião como a porta que o servidor liga, por isso as duas não podem divergir. Altera um só sítio para mover o serviço:

LAYA_PORT=9000 docker compose -f compose.yaml -f compose.http.yaml up --build laya-serve

Token Bearer a partir de um ficheiro

LAYA_API_KEY_FILE é lido uma vez no arranque, movido para LAYA_API_KEY, e a variável _FILE é removida antes de o servidor fazer exec. Prefere 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