Документация

Быстрый старт с Docker

Запустите SDK, не устанавливая Python или PyTorch на хост. Для быстрого старта на CPU выделите 8 ГБ ОЗУ и 10 ГБ свободного места на диске, а также Docker Engine или Docker Desktop и Compose v2 или новее.

Из корня репозитория:

docker compose run --build --rm laya

Эта команда собирает checkout, выполняет пример запроса на CPU и печатает JSON с choice, score и noul. Первый запрос скачивает выбранный публичный чекпойнт Hugging Face; учётная запись не нужна. Заложите несколько минут на его первую загрузку. Веса остаются в именованном томе. Последующие запуски используют docker compose run --rm laya.

Прогнозы и уверенность по-прежнему требуют оценки на вашей рабочей нагрузке. См. ограничения бенчмарков.

Для хостов ARM64, DGX Spark и Apple Silicon см. контейнеры ARM64 и DGX Spark.

GPU NVIDIA / CUDA

Установите совместимый драйвер NVIDIA и настройте Docker с помощью NVIDIA Container Toolkit. Образ для GPU использует колёса PyTorch CUDA 12.8. Сверьте вычислительную способность вашего GPU и драйвер с поддерживаемыми сборками PyTorch; для старых карт может потребоваться другая сборка. Заложите дополнительное место на диске для слоёв CUDA. Потребность в VRAM зависит от чекпойнта, размера батча и длины входа.

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

Оверрайд выбирает 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())'

Пример отклоняет недоступную CUDA до загрузки чекпойнта. Laya всё же может откатиться на CPU после ошибки памяти или инференса, поэтому проверяйте её предупреждения. Пересобирайте образ при переключении между конфигурациями CPU и CUDA.

Образ задаёт TORCH_DISABLE_NATIVE_JIT=1. Иначе PyTorch 2.14 заменяет некоторые eager-операции CUDA на ядра Triton, которые компилирует при первом инференсе, а для этого нужен компилятор C, которого нет в slim-образе: контейнер сообщает о работоспособности, а затем падает на каждом запросе (#365). Штатные ядра дают те же ответы с той же задержкой. Задайте ту же переменную при установке на голом железе, если predict падает с Failed to find C compiler.

Здесь используются резервирования GPU в Compose. Windows требует поддерживаемой Docker Desktop настройки GPU в WSL2. Контейнеры Apple MPS, AMD/ROCm и Intel GPU вне этого быстрого старта; используйте CPU, если только не настроите и не проверите другой бэкенд.

Конфигурация

Задавайте переменные Compose в оболочке, локальном файле .env или блоке environment сервиса. Не коммитьте секреты в .env. Переменные среды выполнения также работают с docker run -e; настройки, доступные только в Compose, отмечены ниже.

Переменная По умолчанию Назначение
LAYA_DEVICE cpu / cuda Устройство, выбранное базовой / GPU-конфигурацией
LAYA_CUDA_AMP не задано (amp_dtype чекпойнта) fp16/float16 или bf16/bfloat16 для прямого прохода на CUDA; любое другое значение игнорируется. Это не косметика: в разделе о порогах в README измерено, что bf16 меняет 3 из 864 argmax на наборе чётности, где fp16 не меняет ни одного
LAYA_CPU_AMP не задано bf16 или bfloat16 включает bf16 для прямого прохода на CPU; любое другое значение оставляет fp32. Ни одно написание fp16 его тоже не включает: у autocast на CPU нет быстрого пути fp16, который обгонял бы fp32, поэтому bf16 — единственная пониженная точность, которую core предлагает на этом устройстве
LAYA_MODEL auto Псевдоним Router: auto, english, multilingual, typed-decisions
LAYA_MODEL_PATH не задано Путь к совместимому чекпойнту внутри контейнера
LAYA_REVISION не задано Коммит, ветка или тег Hub, используемые для каждой загрузки чекпойнта, либо reviewed для проверенных SHA из laya/revisions.py; аргумент 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 использует только кэшированные чекпойнты
HF_HOME /home/laya/.cache/huggingface Путь кэша; см. требование к монтированию ниже
LAYA_CACHE_VOLUME кэш моделей проекта только Compose: именованный том кэша
LAYA_GPU_ID 0 только Compose: индекс или UUID устройства NVIDIA
LAYA_TORCH_INDEX cpu / cu128 / cu130 сборка Compose: индекс колёс PyTorch
LAYA_TORCH_VERSION 2.14.0 сборка Compose: зафиксированная версия PyTorch

Compose прокидывает переменные среды выполнения, кроме HF_HOME, который остаётся согласован с фиксированным монтированием кэша, и кроме LAYA_MPS_AMP_MIN_ROWS — порогового условия по строкам для MPS, которого не может достичь ни один здешний образ, поскольку ни один здешний контейнер не может выбрать MPS. Если вы переопределяете HF_HOME в docker run или в собственном файле Compose, предоставьте соответствующее монтирование, доступное для записи UID 10001. Прямые сборки Docker выбирают PyTorch с помощью --build-arg TORCH_INDEX=cu128; -e во время выполнения не может сменить установленное колесо.

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

Прокомментированный пример конфигурации с монтированием запроса, чекпойнта и файла секретов см. в compose.example.yml:

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

Добавьте -f compose.cuda.yaml перед run для GPU NVIDIA. Пример — это оверрайд compose.yaml, поэтому настройки кэша и образа остаются в одном месте.

Файлы секретов

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 или тома Secret Kubernetes. Значения загружаются в среду процесса при запуске; перезапустите после изменения файла. Никогда не используйте токены как аргументы сборки и не вшивайте их в образы. Публичные чекпойнты не требуют токена.

Дообученные чекпойнты

Этот образ выполняет инференс. Дообучение происходит вне него — ноутбук для дообучения прогоняет весь цикл на бесплатных GPU 2xT4 в Kaggle и экспортирует чекпойнт, который этот образ может обслуживать. Контекст и открытые вопросы об интерфейсе обучения остаются в #4 и #26.

Укажите LAYA_CHECKPOINT_PATH на абсолютный каталог хоста, содержащий rl_agent_config.json, model.safetensors и соответствующие файлы токенизатора:

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

Используйте рабочую копию, доступную для записи UID 10001, потому что загрузчик может обновлять конфигурацию токенизатора. Одного адаптера LoRA недостаточно для полного чекпойнта. Оставьте LAYA_MODEL=auto при задании LAYA_MODEL_PATH; явный псевдоним и локальный путь взаимоисключающие. Ответ для локального пути приходит от Agent и не имеет метаданных routing Router. Эти настройки также работают с оверрайдом CUDA. Оценивайте дообученные чекпойнты на отложенных примерах, прежде чем полагаться на них.

Модели из ModelScope

Когда хост не может достучаться до huggingface.co, чекпойнт может прийти из ModelScope и быть запечён в образ на этапе сборки. Один аргумент выбирает, какой чекпойнт, и по умолчанию это многоязычный. Оверрайд Compose добавляет аргументы предварительной загрузки обоим сервисам и не даёт контейнеру обращаться к Hub:

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

Для NVIDIA добавьте -f compose.cuda.yaml перед up; он повторяет свои аргументы для обоих сервисов, поэтому порядок двух оверрайдов не имеет значения. Чистый 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, и контейнер отвечает весами, которые уже были скачаны, как будто пересборка ничего не изменила. Направьте развёртывание на пустой том кэша — docker compose down --volumes с теми же файлами Compose и тем же LAYA_CACHE_VOLUME, или LAYA_CACHE_VOLUME=<name> для нового. При HF_HUB_OFFLINE=1 отсутствующий или разошедшийся ref — это ошибка загрузки без сети, куда можно откатиться, но предварительное условие то же.

docker/prefetch_modelscope.py перечисляет репозиторий на modelscope.cn, скачивает собственные файлы чекпойнта — тот же набор, который laya/agent.py запрашивает у Hub, так что соседний чекпойнт не тянется — и записывает их в hub-кэш образа так, как snapshot_download раскладывает снимок. Больше ничего не меняется: Agent, Router, который строит laya-serve, laya.cli и интеграции сохраняют свои repo id и разрешают их в запечённый снимок, поэтому контейнеру, собранному таким образом, сеть не нужна вовсе. Размер каждого файла сверяется с тем, что сообщает репозиторий, прежде чем снимок будет опубликован, а также его SHA-256, когда репозиторий его публикует. Несовпадение размера или дайджеста приводит к сбою сборки. Репозиторий, который не публикует дайджест, оставляет проверку только по размеру, а это не может обнаружить подмену того же размера.

Переменная По умолчанию Назначение
MODELSCOPE_MODEL multilingual (Compose); пусто в Dockerfile Чекпойнт для запекания: multilingual, english, typed-decisions или all. Пусто означает отсутствие предварительной загрузки и неизменённый образ
MODELSCOPE_REVISION master Ветка, тег или коммит ModelScope для запекания
HF_HUB_OFFLINE 1 в оверрайде Compose 1 никогда не обращается к Hub, поэтому подаётся запечённая копия

Тип разворачивается в путь этого чекпойнта внутри встроенного репозитория, который 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 ГБ весов. Оверрайд также задаёт LAYA_MODELS=multilingual, потому что LAYA_PRELOAD=1 со списком по умолчанию попытался бы собрать каждый чекпойнт и упал бы на первом незапечённом; задайте LAYA_MODELS со списком, который вы запекали, когда запечёте больше, и MODELSCOPE_MODEL=all, когда развёртывание действительно обслуживает всё семейство.

Несколько типов можно назвать сразу — MODELSCOPE_MODEL="english multilingual" запекает оба, около 1,5 ГБ — что обычно и нужно обслуживающему образу: Router сам выбирает между английским и многоязычным чекпойнтом, а тот, который ему не дали, отвечает 500 inference failed с does not contain 'rl_agent_config.json' в логе. Чекпойнты, разделяющие один репозиторий, всегда запекаются в один снимок, потому что кэшированная ревизия разрешается в один каталог; корневой чекпойнт и каждая подпапка оба в нём.

Помимо типов аргумент также принимает спецификации repo[:subfolder], разделённые запятыми или пробелами, — так запекаются отдельные репозитории зеркала (laya, laya-multilingual, laya-typed-decisions) или дообученный чекпойнт. Отдельный репозиторий — это то, что Agent("convaiinnovations/laya-multilingual") загружает напрямую; значение по умолчанию у Router — встроенный путь, поэтому обслуживающему образу обычно нужен тип.

Два замечания о фиксациях и происхождении. Сборка печатает коммит, к которому привязан снимок, то есть вершину запечённой ревизии, — передайте этот SHA как revision= или LAYA_REVISION, чтобы привязать загрузку точно к запечённому. Репозиторий зеркала может хранить файлы из нескольких загрузок, поэтому эта вершина — единственный существующий общесистемный ключ. Фиксации на стороне Hub не описывают снимок зеркала: reviewed называет коммиты Hugging Face, а карта дайджестов SHA-256 привязана к хешам артефактов Hub, так что ни та, ни другая здесь не применима, и для снимка зеркала тоже нет фиксации дайджеста. Сборка уже отвергает загрузку, не совпадающую с размером, который сообщает зеркало, — и с его дайджестом, когда зеркало его публикует, — но это проверяет согласованность с метаданными зеркала, а не независимо зафиксированный дайджест. Веса приходят из той учётной записи зеркала, которую называет аргумент, а это уже собственное решение о цепочке поставок, которое должно принять развёртывание.

Разработка и очистка

Откройте приглашение Python командой docker compose run --rm laya python. Чтобы выполнить существующие проверки маршрутизации/criteria и тесты файлов секретов на вашем 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. Держите кэши моделей доступными для записи ради обновлений совместимости токенизатора.

--rm удаляет завершённые контейнеры. docker compose down сохраняет кэш. Чтобы удалить скачанные веса, выполните docker compose down --volumes, используя те же файлы Compose и настройку LAYA_CACHE_VOLUME. Следующий запрос скачает их снова; не удаляйте кэш, общий с другим проектом.

Обслуживание по HTTP

Образ включает laya-serve, поэтому та же сборка, что запускает одноразовый быстрый старт, может обслуживать API, совместимый с Jev. 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. Он повторяет аргументы сборки и резервирование устройства для laya-serve, потому что laya-serve — отдельный сервис, и оверрайды для laya до него не доходят:

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

up держит сервис работающим на переднем плане; -d отсоединяет. Веса идут в тот же именованный том model-cache, что и быстрый старт, поэтому обслуживание после запуска быстрого старта начинается с уже скачанными чекпойнтами на диске. Остановите командой docker compose ... down, используя те же файлы Compose.

Порт публикуется только на 127.0.0.1. У API нет аутентификации, пока не задан LAYA_API_KEY, поэтому задайте ключ, прежде чем открывать его наружу через LAYA_BIND_ADDRESS=0.0.0.0, и поставьте перед ним обратный прокси с TLS для удалённых клиентов. /health не требует аутентификации в любом случае, поэтому проверка работоспособности ниже продолжает работать; с заданным ключом он отвечает неаутентифицированному вызывающему {"status": "ok"} и скрывает поля checkpoint, revision и device, для которых нужен bearer.

У сервиса есть проверка работоспособности по /health. Сервер предзагружается, прежде чем начать слушать, поэтому при LAYA_PRELOAD=1 работоспособный контейнер имеет загруженные чекпойнты. docker compose ... up -d --wait laya-serve возвращает управление, как только сервис работоспособен.

/health сообщает device как устройство, на котором фактически считает резидентный чекпойнт, а это не всегда то, что запросил LAYA_DEVICE: чекпойнт, которому нужен GPU, которого он не может получить, молча откатывается на CPU и всё равно отвечает правильно. checkpoint_devices называет каждый загруженный чекпойнт, а device_is_preference равно true только пока ничего не резидентно, поэтому развёртывание, которое тихо потеряло свой GPU, сообщает об этом, а не повторяет собственную конфигурацию обратно.

Конфигурация сервера

Применяются только к сервису laya-serve.

переменная по умолчанию эффект
LAYA_HOST 0.0.0.0 адрес привязки внутри контейнера
LAYA_PORT 8000 порт контейнера и публикуемый для него порт хоста
LAYA_BIND_ADDRESS 127.0.0.1 адрес хоста, на котором публикуется порт
LAYA_PRELOAD 0 1 собирает каждый чекпойнт при запуске, а не при первом запросе
LAYA_MODELS (все) список через запятую для предзагрузки: english,multilingual,typed-decisions
LAYA_THREADS OMP_NUM_THREADS ограничивает число intra-op потоков torch; держите на уровне физических ядер или ниже
LAYA_AUTO_TASK 0 1 позволяет роутеру самостоятельно доходить до typed-decisions
LAYA_DEFAULT_MODEL english Чекпойнт, к которому откатывается состояние без языковых свидетельств (нет букв или латинский текст слишком короткий для определения). Задайте multilingual для преимущественно неанглоязычного трафика; неразрешимое имя останавливает контейнер при запуске вместо того, чтобы подавать конфигурацию, которую никто не просил
LAYA_MAX_LOADED 2 Чекпойнты, удерживаемые резидентно; LAYA_AUTO_TASK делает третий достижимым по требованию, а ограничение ниже того, что выбирает маршрутизация, пересобирает один на каждое переключение
LAYA_MAX_CONCURRENT 16 запросов, принимаемых одновременно; последующие получают 503 (значение, которое не парсится или не положительно, откатывается к 16)
LAYA_LOG_LEVEL info уровень логирования uvicorn
LAYA_API_KEY (нет) когда задан, требует Authorization: Bearer <key>
LAYA_ROOT_PATH (пусто) публичный префикс URL для FastAPI за обратным прокси; прокси должен срезать его перед перенаправлением
LAYA_MAX_TOKEN_BUDGET 8192 ограничение на переопределения max_len и head_max_len для каждого запроса
LAYA_SHA256_DIGESTS (нет) JSON-дайджесты, проверяемые до разбора чекпойнта: {artifact: digest} для каждого чекпойнта или {model: {artifact: digest}} по чекпойнтам. См. безопасность

Например, задайте LAYA_ROOT_PATH=/laya при публикации API под /laya. Прокси должен срезать этот префикс перед перенаправлением в контейнер; эта настройка обновляет сгенерированные FastAPI URL и не меняет внутренние маршруты /health и /v1/systemone.

LAYA_PRELOAD по умолчанию здесь равен 0, а не 1 из пакета, потому что предзагрузка заставляет первую загрузку скачивать все три чекпойнта. Установите 1 для долго работающего развёртывания, чтобы первый запрос не платил за сборку.

LAYA_PORT задаёт и публикуемый порт хоста, и порт, к которому привязывается сервер, поэтому они не могут разойтись. Измените в одном месте, чтобы переместить сервис:

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

Bearer-токен из файла

LAYA_API_KEY_FILE читается один раз при запуске, переносится в LAYA_API_KEY, а переменная _FILE удаляется до того, как сервер выполнит exec. Предпочитайте это помещению ключа в среду:

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