Быстрый старт с 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