文件導航

Docker 快速開始

不必在主機上安裝 Python 或 PyTorch 就能執行 SDK。CPU 快速開始請預留 8 GB 記憶體和 10 GB 空閒 磁碟,並裝好 Docker Engine 或 Docker Desktop 以及 Compose v2 或更新版本。

在倉庫根目錄執行:

docker compose run --build --rm laya

這會構建當前 checkout,在 CPU 上執行示例請求 並列印覆蓋 choice、score 和 noul 的 JSON。第一次請求會下載選定的公開 Hugging Face checkpoint;不需要賬號。首次下載請留出幾分鐘。 權重留在具名卷裡。之後的執行用 docker compose run --rm laya。

預測結果和置信度仍需在你自己的工作負載上評估。見 基準限制。

ARM64 主機、DGX Spark 和 Apple Silicon 見 ARM64 與 DGX Spark 容器。

NVIDIA GPU / CUDA

裝好相容的 NVIDIA 驅動,並用 NVIDIA Container Toolkit 配置 Docker。GPU 映象使用 PyTorch CUDA 12.8 wheel。對照 PyTorch 支援的構建檢查你 GPU 的計算能力和驅動; 較老的卡可能需要另一種構建。為 CUDA 層預留額外的磁碟空間。視訊記憶體需求取決於 checkpoint、批大小 和輸入長度。

docker compose -f compose.yaml -f compose.cuda.yaml run --build --rm laya

這個 override 選擇 GPU 0,並把 LAYA_DEVICE=cuda 設為預設。把 LAYA_GPU_ID 設為另一個 主機索引或 UUID。那塊 GPU 在容器內顯示為裝置 0。不下權重也能檢查訪問是否正常:

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())'

示例在載入 checkpoint 之前會先拒絕不可用的 CUDA。遇到記憶體或推理錯誤後,Laya 仍可能回退到 CPU,所以要留意它的警告。在 CPU 和 CUDA 配置之間切換時要重新構建。

映象設定了 TORCH_DISABLE_NATIVE_JIT=1。否則 PyTorch 2.14 會把一些 eager CUDA 運算元替換成 Triton 核心,並在第一次推理時編譯它們,而這需要一個 slim 映象裡沒有的 C 編譯器:容器報告健康, 然後每個請求都失敗(#365)。原裝核心給出同樣的答案、同樣的延遲。裸機安裝如果 predict 報 Failed to find C compiler,也請設定同一個變數。

這裡用的是 Compose GPU 預留。Windows 需要 Docker Desktop 支援的 WSL2 GPU 設定。Apple MPS、AMD/ROCm 和 Intel GPU 容器不在這個快速 開始範圍內;除非你另外配置並驗證了後端,否則請用 CPU。

配置

在 shell、本地 .env 檔案或服務的 environment 塊裡設定 Compose 變數。不要把金鑰提交進 .env。執行時變數也可以通過 docker run -e 使用;僅限 Compose 的設定下面會標出。

變數 預設值 用途
LAYA_DEVICE cpu / cuda 由基礎 / GPU 配置選擇的裝置
LAYA_CUDA_AMP 未設定(checkpoint 的 amp_dtype) CUDA 前向用 fp16/float16 或 bf16/bfloat16;其他任何值都被忽略。不是裝飾性的:README 的閾值一節測出,在 fp16 一次 argmax 都不翻轉的對等集上,bf16 翻轉了 864 箇中的 3 個
LAYA_CPU_AMP 未設定 bf16 或 bfloat16 讓 CPU 前向使用 bf16;其他任何值都保持 fp32。任何 fp16 寫法也打不開它:CPU autocast 沒有比 fp32 更快的 fp16 快速路徑,所以 bf16 是 core 在這個裝置上提供的唯一降精度選項
LAYA_MODEL auto Router 別名:auto、english、multilingual、typed-decisions
LAYA_MODEL_PATH 未設定 容器內相容的 checkpoint 路徑
LAYA_REVISION 未設定 每次 checkpoint 下載所使用的 Hub commit、分支或 tag,或 reviewed 表示用 laya/revisions.py 裡經過複核的 SHA;revision= 參數仍然優先
LAYA_REQUEST_FILE 內建請求 容器內的 JSON 請求路徑
OMP_NUM_THREADS 4 CPU 執行緒數;不要超過可用核心
HF_TOKEN / HF_TOKEN_FILE 未設定 可選的 Hugging Face 憑據
LAYA_API_KEY / LAYA_API_KEY_FILE 未設定 僅 laya-serve: 要求 Authorization: Bearer <key>
LAYA_PORT 8000 僅 laya-serve: 容器埠,以及為它釋出的宿主機埠
HF_HUB_OFFLINE 0 1 表示只用快取的 checkpoint
HF_HOME /home/laya/.cache/huggingface 快取路徑;見下面的掛載要求
LAYA_CACHE_VOLUME 專案模型快取 僅 Compose: 具名快取卷
LAYA_GPU_ID 0 僅 Compose: NVIDIA 裝置索引或 UUID
LAYA_TORCH_INDEX cpu / cu128 / cu130 Compose 構建: PyTorch wheel 索引
LAYA_TORCH_VERSION 2.14.0 Compose 構建: 固定的 PyTorch 版本

Compose 會轉發執行時變數,但 HF_HOME 除外 —— 它與固定的快取掛載保持一致;LAYA_MPS_AMP_MIN_ROWS (MPS 行數門限)也除外,因為這裡沒有任何映象能觸及它,這裡也沒有容器能選中 MPS。如果在 docker run 或你自己的 Compose 檔案裡覆蓋 HF_HOME,請提供一個配套的、UID 10001 可寫的 掛載。直接 Docker 構建用 --build-arg TORCH_INDEX=cu128 選擇 PyTorch;執行時的 -e 改不了已 安裝的 wheel。

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

用你自己的請求:

docker compose run --rm --volume "$PWD/request.json:/inputs/request.json:ro" \
  --env LAYA_REQUEST_FILE=/inputs/request.json laya

要看一份帶註釋、掛載了請求、checkpoint 和金鑰檔案的配置,見 compose.example.yml:

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

NVIDIA GPU 在 run 前加上 -f compose.cuda.yaml。這個示例是 compose.yaml 的 override, 所以快取和映象設定只放在一處。

金鑰檔案

HF_TOKEN_FILE 在啟動時讀取一個掛載的 UTF-8 檔案,去掉首尾空白,優先順序高於 HF_TOKEN。 讀不到、為空或非法的檔案會阻止啟動,且不列印其內容。該檔案必須對 UID 10001 可讀。_FILE 只 適用於受支援的金鑰,不是每項設定都行。

當 HF_TOKEN_PATH 指向 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 或 Kubernetes Secret 卷也能提供同一個檔案。值在啟動時載入程序環境;改檔案後需 重啟。絕不要把 token 用作構建參數或烤進映象裡。公開 checkpoint 不需要 token。

微調後的 checkpoint

這個映象跑推理。微調在它之外進行 —— 微調 notebook 在 Kaggle 免費的 2xT4 GPU 上跑完整個迴圈,匯出一個這個映象能服務的 checkpoint。關於訓練介面的 背景和待決問題留在 #4 和 #26。

把 LAYA_CHECKPOINT_PATH 指向一個絕對宿主機目錄,裡面要有 rl_agent_config.json、 model.safetensors 和匹配的 tokenizer 檔案:

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

請用 UID 10001 可寫的工作副本,因為載入器可能會更新 tokenizer 配置。單有 LoRA 介面卡不算一個 完整的 checkpoint。設定 LAYA_MODEL_PATH 時把 LAYA_MODEL=auto 留著;顯式別名和本地路徑互不 相容。本地路徑的響應來自 Agent,沒有 Router 的 routing 後設資料。這些設定對 CUDA override 也 適用。請在留出樣本上評估微調後的 checkpoint,再決定是否依賴它。

從 ModelScope 獲取模型

當主機無法訪問 huggingface.co 時,checkpoint 可以來自 ModelScope,並在構建時烤進映象。用一個參數選擇哪個 checkpoint, 預設是多語言那個。Compose override 會把預取參數加到兩個服務上,並讓容器不碰 Hub:

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

NVIDIA 的話,在 up 前加上 -f compose.cuda.yaml;它自己會為兩個服務重複參數,所以兩個 override 的先後順序無所謂。直接用 Docker 則直接接受這些參數:

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

對之前跑過它的主機有一個前提。烤進去的權重要落在映象內的 $HF_HOME/hub,也就是 compose.yaml 把 model-cache 卷掛載到的那個快取目錄(/home/laya/.cache/huggingface) 下,而 Docker 只在該具名卷為空時才從映象為它播種。一個從基於 Hub 的快速開始遺留下來的卷 握著舊的 Hub 快照,它永遠不會被重新播種,烤進去的權重就藏在它後面看不見:載入器把 refs/main 解析到舊的 Hub commit,容器用已經下載過的權重作答,就好像這次重建什麼都沒改。 把部署指向一個空的快取卷 —— 用同樣的 Compose 檔案和同樣的 LAYA_CACHE_VOLUME 執行 docker compose down --volumes,或用 LAYA_CACHE_VOLUME=<name> 換一個全新的。設了 HF_HUB_OFFLINE=1 時,缺失或分叉的 ref 就是一次載入失敗,沒有網路可以回退,但這個前提是 一樣的。

docker/prefetch_modelscope.py 列出 modelscope.cn 上的倉庫,下載 checkpoint 自己的檔案 —— 也就是 laya/agent.py 向 Hub 要的同一組,所以不會拉取兄弟 checkpoint —— 並按 snapshot_download 鋪開快照的方式把它們 寫進映象的 hub 快取。其他什麼都不變:Agent、laya-serve 構建的 Router、laya.cli 以及各整合都保留自己的 repo id,並把它們解析到烤進去的快照,所以這樣構建的容器完全不需要 網路。每個檔案的大小會在快照發布之前對照倉庫報告的值檢查,倉庫釋出摘要時連 SHA-256 也一起 查。大小或摘要對不上會讓構建失敗。倉庫不釋出摘要時,檢查就只剩大小,而這檢測不出同樣大小 的替換。

變數 預設值 用途
MODELSCOPE_MODEL multilingual(Compose);Dockerfile 裡為空 要烤哪個 checkpoint:multilingual、english、typed-decisions 或 all。為空表示不預取,映象不變
MODELSCOPE_REVISION master 要烤的 ModelScope 分支、tag 或 commit
HF_HUB_OFFLINE Compose override 裡為 1 1 從不聯絡 Hub,所以提供的是烤進去的那份

一個型別會展開為該 checkpoint 在捆綁倉庫內的路徑,也就是 Router 和一次性快速開始預設 載入的那個,所以一個只指定了某個型別的構建無需進一步改動就能提供它:

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 是整個家族,約 2.4 GB 權重。這個 override 還會設 LAYA_MODELS=multilingual,因為 LAYA_PRELOAD=1 配上預設列表會試圖構建每個 checkpoint,並在第一個沒烤進去的上面失敗;當 你烤了更多時,把 LAYA_MODELS 設成你烤的那個列表,當部署確實要提供整個家族時再設 MODELSCOPE_MODEL=all。

可以一次指定多個型別 —— MODELSCOPE_MODEL="english multilingual" 會兩個都烤,約 1.5 GB —— 這通常正是服務映象想要的:Router 自己在英語和多語言 checkpoint 之間選擇,而它沒拿到 的那個會用日誌裡的 does not contain 'rl_agent_config.json' 回答 500 inference failed。 共享一個倉庫的 checkpoint 總是烤進同一個快照,因為一個快取的 revision 只解析到一個目錄; 根 checkpoint 和每個子目錄都在裡面。

除了型別,這個參數還接受 repo[:subfolder] 形式的規格,逗號或空格分隔,映象的獨立倉庫 (laya、 laya-multilingual、 laya-typed-decisions) 或一個微調後的 checkpoint 就是這樣烤的。獨立倉庫是 Agent("convaiinnovations/laya-multilingual") 直接載入的東西;Router 的預設是捆綁路徑, 所以服務映象通常要的是型別。

關於固定和來源的兩個細節。構建會列印快照以之鍵控的 commit,也就是所烤 revision 的頂端 —— 把那個 SHA 作為 revision= 或 LAYA_REVISION 傳入,就能把載入精確固定到所烤的東西上。一個 映象倉庫可以裝著來自多次上傳的檔案,所以那個頂端是唯一存在的倉庫級鍵。Hub 側的固定不描述 映象快照:reviewed 命名的是 Hugging Face commit,而 SHA-256 摘要對映以 Hub 製品雜湊為鍵, 所以兩者在這裡都不適用,映象快照也不存在摘要固定。構建已經會拒絕與映象自己報告的大小不符的 下載 —— 映象釋出摘要時也拒絕摘要不符的 —— 但這檢查的是與映象後設資料的一致性,不是一個獨立 固定的摘要。權重來自參數所命名的那個映象賬號,那是部署自己要做的供應鏈決定。

開發與清理

用 docker compose run --rm laya python 開啟一個 Python 提示符。想在不下載權重的情況下,對 你的 checkout 跑現有的路由/判定標準檢查和金鑰檔案測試:

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'

改動原始碼或內建示例後,用 --build 重新構建。映象以 UID/GID 10001 執行。新建的具名卷繼承映象 快取目錄的屬主;宿主機目錄必須對該 UID 可寫。模型快取要保持可寫,以便做 tokenizer 相容性更新。

--rm 會刪除已完成的容器。docker compose down 保留快取。要刪除已下載的權重,用同樣的 Compose 檔案和 LAYA_CACHE_VOLUME 設定執行 docker compose down --volumes。下一個請求會重新 下載它們;不要刪掉與其他專案共享的快取。

HTTP 服務

映象自帶 laya-serve,所以跑一次性快速開始的那次構建也能提供相容 Jev 的 API。 compose.http.yaml 把它加為第二個服務,不動 laya:

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

NVIDIA 再疊上 CUDA override。它要為 laya-serve 重複構建參數和裝置預留,因為 laya-serve 是一個單獨的服務,針對 laya 的 override 到不了它:

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

up 讓服務在前臺執行;-d 轉到後臺。權重進到和快速開始同一個具名的 model-cache 卷,所以 快速開始跑過之後再起服務,checkpoint 已經在磁碟上了。用同樣的 Compose 檔案,通過 docker compose ... down 停止。

埠只在 127.0.0.1 上釋出。在設定 LAYA_API_KEY 之前 API 沒有認證,所以用 LAYA_BIND_ADDRESS=0.0.0.0 暴露它之前先設一個 key,併為遠端客戶端在前面放一個 TLS 反向 代理。兩種情況下 /health 都不需要認證,所以下面的健康檢查照常工作;設定 key 後,它對未經 認證的呼叫者回答 {"status": "ok"},並保留需要 bearer 的 checkpoint、revision 和 device 欄位。

服務對 /health 有健康檢查。伺服器在開始監聽前先預載入,所以 LAYA_PRELOAD=1 時,一個健康的 容器其 checkpoint 已經載入好了。docker compose ... up -d --wait laya-serve 會在它健康後 返回。

/health 報告的 device 是常駐 checkpoint 實際計算所用的裝置,它不總是 LAYA_DEVICE 要求的 那個:一個想要 GPU 卻拿不到的 checkpoint 會靜默回退到 CPU,仍然給出正確的答案。 checkpoint_devices 列出每個已載入的 checkpoint,device_is_preference 只在沒有任何常駐 checkpoint 時為 true,於是一個悄悄丟了 GPU 的部署會說出來,而不是把自己配置裡的東西原樣 回聲。

伺服器配置

這些只適用於 laya-serve 服務。

變數 預設值 作用
LAYA_HOST 0.0.0.0 容器內的繫結地址
LAYA_PORT 8000 容器埠,以及為它釋出的宿主機埠
LAYA_BIND_ADDRESS 127.0.0.1 埠釋出所在的宿主機地址
LAYA_PRELOAD 0 1 表示啟動時就構建每個 checkpoint,而不是首次請求時
LAYA_MODELS (全部) 要預載入的逗號列表:english,multilingual,typed-decisions
LAYA_THREADS OMP_NUM_THREADS 限制 torch 程序內執行緒數;保持在物理核心數或以下
LAYA_AUTO_TASK 0 1 讓路由器能自動觸達 typed-decisions
LAYA_DEFAULT_MODEL english 沒有語言證據的 state 回退到哪個 checkpoint(沒有字母,或拉丁文本短到無法識別)。主要是非英語流量時設為 multilingual;無法解析的名字會在啟動時停住容器,而不是提供一個沒人要的配置
LAYA_MAX_LOADED 2 保持常駐的 checkpoint 數;LAYA_AUTO_TASK 讓第三個可按需觸達,而上限低於路由實際選擇時,每次切換都會重建一個
LAYA_MAX_CONCURRENT 16 一次可接納的請求數;更晚的會拿到 503(無法解析或非正數的值會回退到 16)
LAYA_LOG_LEVEL info uvicorn 日誌級別
LAYA_API_KEY (無) 設定後要求 Authorization: Bearer <key>
LAYA_ROOT_PATH (空) 在反向代理之後時,FastAPI 的公開 URL 字首;代理應在轉發前把它剝掉
LAYA_MAX_TOKEN_BUDGET 8192 對每請求 max_len 和 head_max_len 覆蓋的上限
LAYA_SHA256_DIGESTS (無) 在解析 checkpoint 之前校驗的 JSON 摘要:對所有 checkpoint 是 {artifact: digest},對每個 checkpoint 是 {model: {artifact: digest}}。見安全

比如,在 /laya 下發布 API 時,設定 LAYA_ROOT_PATH=/laya。代理必須在轉發到容器之前剝掉這個 字首;這項設定更新 FastAPI 生成的 URL,不改變內部的 /health 或 /v1/systemone 路由。

LAYA_PRELOAD 這裡預設是 0,而不是包預設的 1,因為預載入會讓首次啟動下載全部三個 checkpoint。長時間執行的部署把它設為 1,這樣第一個請求不用為構建買單。

LAYA_PORT 同時設定釋出的宿主機埠和伺服器繫結的埠,所以兩者不會脫節。要挪動服務,只改 一處:

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

從檔案讀 bearer token

LAYA_API_KEY_FILE 在啟動時讀一次,移入 LAYA_API_KEY,然後在伺服器 exec 之前刪掉 _FILE 變數。優先用它,而不是把 key 放進環境:

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