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