No description
  • Go 42.6%
  • TypeScript 27.8%
  • Python 19%
  • JavaScript 5.3%
  • CSS 4.9%
  • Other 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-07 14:52:18 +00:00
Controller feat(controller): add audio extractor UI 2026-08-25 15:52:36 +08:00
docs/guides docs: standardize Worker and Controller development 2026-08-24 14:35:36 +08:00
EManager docs: expand project guide and standardize Go 1.26.8 2026-10-07 14:50:44 +00:00
EWorker docs: expand project guide and standardize Go 1.26.8 2026-10-07 14:50:44 +00:00
Platform docs: expand project guide and standardize Go 1.26.8 2026-10-07 14:50:44 +00:00
.gitignore feat(controller): add CrispASR transcription UI 2026-08-22 16:44:20 +08:00
go.work docs: expand project guide and standardize Go 1.26.8 2026-10-07 14:50:44 +00:00
README.md docs: clarify main tracking for single-branch clones 2026-10-07 14:52:18 +00:00

Layla_TAB_V2

Layla_TAB_V2 是业务无关的任务执行与管理平台:Platform 管理身份、注册信息、任务和文件元数据,EManager 协调一台执行机器,EWorker 运行具体业务,Controller 提供独立打包的操作界面。Worker 与 Controller 通过不可变的 Spec 共享输入、输出与版本契约。

  • 仓库:Cloverdo/Layla-TAB-V2
  • 开发分支:dev;主分支:main。
  • Go 基准版本:1.26.8。开发、测试、发布构建和 Docker Go 构建阶段统一使用此版本。
  • 当前测试主机:10.10.10.102;项目工作目录:/opt/agents/Layla_TAB_V2。

本文的命令以 Linux Bash 为例。测试主机上的源码、构建产物、临时文件和原生运行目录均放在上述项目目录内。需要到其他路径开展开发、测试或部署工作时,先向项目负责人汇报;Docker 部署例外。子目录文档中的 /opt/Emanager 是历史部署示例,不能直接作为本测试环境的目标路径。账号、令牌、数据库密码和 Manager Key 通过未跟踪的配置或运行环境提供。

目录

  1. 主要功能
  2. 架构与执行流程
  3. 仓库结构
  4. 开发环境与 Go 版本
  5. 启动 Platform
  6. 配置 EManager
  7. 安装 Worker 与 Controller
  8. 构建与测试
  9. 协议与扩展开发
  10. 运维与排错
  11. 分支与发布流程
  12. 相关文档

主要功能

Platform 提供本地账号登录、可配置的 OIDC 登录、Manager 注册、Worker 管理、Spec 注册与版本校验、Controller ZIP 安装与启用、任务状态及历史查询、文件预览与下载、S3 配置和运行遥测。管理界面支持中英文显示。

已包含以下独立业务扩展;源码存在不代表运行环境、模型和工具已经安装。

扩展 Spec 输入与输出 运行依赖
MarkItDown MarkItDown 1.0 文档转换为 Markdown Python、MarkItDown 及所选文档格式依赖
CrispASR CrispASR 1.0 上传音频或公共 URL 转录为 Markdown CUDA 版 CrispASR、Qwen3-ASR 模型、独立媒体工具
IndexTTS2 IndexTTS2 1.0 文本与授权的参考音频生成 WAV NVIDIA CUDA、IndexTTS2 运行时和模型
ComfyUI ComfyUI 2.0 文本生成一个或多个 PNG 图像 NVIDIA CUDA、ComfyUI、FLUX.2 模型及匹配的文本编码器
AudioExtractor AudioExtractor 1.0 上传视频或 Bilibili/YouTube URL 提取音频片段 CPU、Worker 私有的 ffmpeg、ffprobe、yt-dlp

AudioExtractor 默认上传上限为 100 MiB,输出 24 kHz、单声道、16 位 PCM WAV。时间范围要求 0 <= start_seconds < end_seconds <= 86400;结束时间超出媒体长度时截断,开始时间达到或超出媒体长度时失败。CrispASR 与 IndexTTS2 的任务推理使用子进程,在任务结束或取消后释放推理进程的资源;GPU 扩展不能用 CPU 假装完成 GPU 验收。

架构与执行流程

flowchart LR
    Browser[浏览器 / 管理界面] --> Platform[Platform / Go API]
    Controller[Controller / 沙箱 iframe] --> SDK[Controller Host SDK]
    SDK --> Platform
    Platform --> PostgreSQL[(PostgreSQL / 核心数据)]
    Platform --> S3[(S3 / 上传与产物)]
    Manager[EManager / 原生进程] -->|主动心跳、领取任务、回报状态| Platform
    Manager -->|本机 Runtime Protocol| Worker[EWorker / 独立进程]
    Manager --> Workspace[任务工作区]
    Worker --> Workspace

组件职责

组件 职责 数据与连接边界
Platform 登录、注册、Spec 校验、调度、任务历史、Artifact 与素材库元数据 PostgreSQL;持有 S3 凭据;不执行业务任务、不主动连接 Manager
EManager Worker 同步、任务领取、工作区管理、文件搬运、状态与遥测上报 本地 SQLite;持有 Manager Key;主动连接 Platform
EWorker 解释 Spec 的业务输入、运行适配器、产生声明的输出 只连接本机 Manager;不持有 Manager Key、Platform 登录或 S3 凭据
Controller 业务表单、上传、提交任务、进度展示、预览与下载 沙箱 iframe;只使用公共 Host SDK
Spec 约定业务输入、输出、Artifact 角色与版本 同名同版本不可变,使用规范化 JSON 的 SHA-256 标识

一次任务如何执行

  1. Platform 管理员注册 Manager 并发放 Key,创建 Spec 家族与 Worker 分配。
  2. EManager 主动连接 Platform;Worker 通过本机 Runtime Protocol 报告运行版本和支持的 Spec。
  3. Platform 校验 Worker/Controller 的 Spec 定义;双方的活动版本和规范化摘要必须一致。
  4. Controller 经 Host SDK 上传输入并创建面向具体 Worker 的任务,任务冻结 Spec 名称、版本和摘要。
  5. EManager 领取任务,把输入 Artifact 下载到该任务的工作区,然后交给 Worker。
  6. Worker 回报进度,将正式输出写到工作区的 output/,返回相对路径和结果元数据。
  7. EManager 上传输出并回报终态,Platform 保存历史,Controller 经平台接口预览或下载产物。

主要任务状态为 pending、claimed、running、succeeded、failed、cancelled、interrupted。当前调度对同一 Manager 的 claimed/running 任务进行串行约束;多个 Worker 注册在同一 Manager 下不意味着它们会同时执行任务。业务失败不会自动重试;再次提交形成新的任务。

存储边界

  • PostgreSQL 是 Platform 的必需依赖,保存账号、配置、Spec、Manager、Worker、Controller、任务与 Artifact 元数据。缺少 LAYLA_DATABASE_URL 或数据库不可达时,Platform 启动失败,不回退到 SQLite。
  • SQLite 只用于 EManager 本地状态,不能替代 Platform 的数据库。
  • S3 保存用户上传、素材文件和 Worker 输出。没有配置 S3 时,平台仍可管理注册信息与核心配置,依赖文件传输的业务需要可用的存储。
  • Controller 的安装包与静态资源还需要 Platform 的本地数据目录;容器运行时应持久化该目录。
  • 清理或更换 S3 不会删除数据库中的历史,但可能导致历史文件不可访问。备份必须分别覆盖数据库、Platform 数据目录与对象存储。

仓库结构

Layla-TAB-V2/
├── README.md
├── go.work                         # 三个 Go 模块的开发工作区
├── Platform/
│   ├── cmd/layla-platform/          # Platform 入口
│   ├── internal/platform/          # API、核心逻辑、数据库、Controller、存储
│   ├── pkg/platformprotocol/v1/    # Spec 解析与规范化摘要
│   ├── protocol/                   # Platform / Spec 的机器可读契约
│   ├── web/                        # React + TypeScript 管理界面
│   ├── tests/                      # 契约测试及浏览器验收
│   ├── docs/
│   └── Dockerfile
├── EManager/
│   ├── cmd/layla-manager/
│   ├── internal/manager/           # 调度、Runtime、SQLite、工作区、遥测
│   ├── sdk/go/platformclient/      # 公共 Platform Protocol 客户端
│   ├── Release/                    # 已跟踪的历史原生发行产物
│   ├── systemd/                    # 原生服务模板
│   ├── .env.example
│   └── Dockerfile.test             # 测试辅助镜像,非原生部署替代品
├── EWorker/
│   ├── protocol/                   # Manager / Worker Runtime Protocol
│   ├── sdk/go/worker/
│   ├── sdk/python/
│   ├── MarkItDown/
│   ├── CrispASR/
│   ├── IndexTTS2/
│   ├── ComfyUI/
│   └── AudioExtractor/
├── Controller/
│   ├── sdk/typescript/             # Controller Host SDK
│   ├── protocol/controller/v1/
│   └── <功能名称>/                 # manifest、Spec、UI、打包脚本
└── docs/guides/
    └── NEW_FUNCTION_WORKER_CONTROLLER_STANDARD.md

每个可部署 Go 组件拥有自己的 go.mod。node_modules/、dist/、.venv/、本地数据库、.env 和 .acceptance/ 等开发文件不提交。仓库内已有部分 Controller ZIP 和 EManager 二进制;升级工具链后,应重新构建需要发布的产物,不能假定历史二进制已由 Go 1.26.8 编译。

开发环境与 Go 版本

工具 项目要求
Go 1.26.8;go.work、三个 go.mod 与 Go Docker 构建镜像统一对齐
Node.js Docker 前端使用 Node 22;测试机已验证 Node 24.21.0,依赖安装以锁文件为准
npm / pnpm package-lock.json 使用 npm;pnpm-lock.yaml 使用 pnpm
Python SDK/多数适配器要求 Python >= 3.10;IndexTTS2 要求 >= 3.10 且 < 3.12,统一适配层测试可选择 Python 3.11
PostgreSQL Platform 必需;以下示例和基础测试使用 PostgreSQL 17
Docker Compose 支持 docker compose 与示例中的依赖健康/完成条件
NVIDIA CUDA CrispASR、IndexTTS2、ComfyUI 的真实推理需要

在测试机进入项目目录并确认工具链:

cd /opt/agents/Layla_TAB_V2
go version
# 预期:go version go1.26.8 linux/amd64
export GOTOOLCHAIN=local
test "$(go env GOVERSION)" = go1.26.8

# 将编译缓存、模块缓存和临时文件限制在项目内。
mkdir -p .acceptance/cache/go-build .acceptance/cache/go-mod \
  .acceptance/cache/go-path .acceptance/tmp
export GOCACHE="$PWD/.acceptance/cache/go-build"
export GOMODCACHE="$PWD/.acceptance/cache/go-mod"
export GOPATH="$PWD/.acceptance/cache/go-path"
export TMPDIR="$PWD/.acceptance/tmp"
export npm_config_cache="$PWD/.acceptance/cache/npm"
export PIP_CACHE_DIR="$PWD/.acceptance/cache/pip"

go 1.26.8 声明了模块最低工具链要求,不能阻止手动使用更新版本;上面的版本检查和 Docker 的 golang:1.26.8 标签用于保持实际构建基准一致。版本变更应同时更新工作区、三个模块和全部 Go 构建镜像。

启动 Platform

Docker Compose 最小环境

以下是可保存为项目根目录 compose.local.yml 的示例,仓库不预置该文件。示例针对 Linux 测试主机,镜像构建阶段使用宿主网络以绕过当前容器构建网络的 DNS 问题;应用运行仍使用 Compose 网络。它提供 PostgreSQL、Platform 数据卷初始化和 Platform;不包含 S3、Manager、Worker 或模型。

services:
  postgres:
    image: postgres:17-alpine
    environment:
      POSTGRES_DB: layla
      POSTGRES_USER: layla
      POSTGRES_PASSWORD: ${LAYLA_DB_PASSWORD:?set LAYLA_DB_PASSWORD}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U layla -d layla"]
      interval: 5s
      timeout: 3s
      retries: 20
    restart: unless-stopped

  platform-data-init:
    image: postgres:17-alpine
    command: ["chown", "65532:65532", "/data"]
    volumes:
      - platform-data:/data
    restart: "no"

  platform:
    image: cloverdo/layla-tab:dev
    build:
      context: ./Platform
      dockerfile: Dockerfile
      network: host
    environment:
      LAYLA_DATABASE_URL: postgres://layla:${LAYLA_DB_PASSWORD:?set LAYLA_DB_PASSWORD}@postgres:5432/layla?sslmode=disable
      LAYLA_ADMIN_USERNAME: ${LAYLA_ADMIN_USERNAME:-admin}
      LAYLA_ADMIN_PASSWORD: ${LAYLA_ADMIN_PASSWORD:?set LAYLA_ADMIN_PASSWORD}
      LAYLA_LISTEN_ADDRESS: :8080
      LAYLA_DATA_DIR: /tmp/layla-data
      LAYLA_SECURE_COOKIES: "false"
    ports:
      - "${LAYLA_HTTP_PORT:-8080}:8080"
    volumes:
      - platform-data:/tmp/layla-data
    depends_on:
      postgres:
        condition: service_healthy
      platform-data-init:
        condition: service_completed_successfully
    restart: unless-stopped

volumes:
  postgres-data:
  platform-data:

Platform 镜像以 UID/GID 65532 运行,初始化服务为新数据卷设置写权限。以下 .env 是占位示例;数据库密码使用随机字母数字串,若包含 URI 保留字符,需要对连接串中的密码进行 URL 编码。

LAYLA_DB_PASSWORD=replace-with-random-alphanumeric-value
LAYLA_ADMIN_USERNAME=admin
LAYLA_ADMIN_PASSWORD=replace-with-a-strong-password
LAYLA_HTTP_PORT=8080
cd /opt/agents/Layla_TAB_V2
chmod 600 .env
docker compose -p layla-tab-v2 -f compose.local.yml config --quiet
docker compose -p layla-tab-v2 -f compose.local.yml up -d --build
curl -fsS http://127.0.0.1:8080/healthz
curl -fsS http://127.0.0.1:8080/readyz

然后访问 http://10.10.10.102:8080 并使用自己配置的管理员账号。示例端口需要空闲;更改 LAYLA_HTTP_PORT 时同时更改访问和探测地址。示例 sslmode=disable 与非 Secure Cookie 面向隔离测试环境,公网部署应使用 HTTPS 并按实际数据库连接配置 TLS。数据卷由 Compose 管理,down 与 down -v 的数据保留效果不同。

原生源码运行与前端开发

原生启动适用于源码调试;正式 Platform 部署使用 Docker。先准备独立 PostgreSQL 和连接串,再运行:

cd /opt/agents/Layla_TAB_V2/Platform/web
npm ci --no-audit --no-fund
npm run build

cd /opt/agents/Layla_TAB_V2/Platform
export LAYLA_DATABASE_URL='postgres://USER:URL_ENCODED_PASSWORD@HOST:5432/DATABASE?sslmode=disable'
export LAYLA_ADMIN_USERNAME='admin'
export LAYLA_ADMIN_PASSWORD='replace-with-a-strong-password'
export LAYLA_DATA_DIR='/opt/agents/Layla_TAB_V2/.acceptance/runtime/platform-data'
go run ./cmd/layla-platform

Platform 本身不会自动读取 .env;通过 shell、Compose 或进程管理器注入环境变量。前端开发可在另一终端执行 npm run dev -- --host 127.0.0.1;Vite 仅为 /api 和 /healthz 配置了到 127.0.0.1:8080 的代理。完整 Controller iframe 和静态资源链路应通过 Platform 提供的生产构建验证,不能仅凭 Vite 页面加载成功判定端到端可用。

Platform 环境变量

变量 默认值 / 要求 用途
LAYLA_DATABASE_URL 必填 PostgreSQL 连接 URI,启动时执行建表/迁移
LAYLA_LISTEN_ADDRESS :8080 HTTP 监听地址
LAYLA_ADMIN_USERNAME admin 初始化本地管理员
LAYLA_ADMIN_PASSWORD change-me 初始化密码;部署时必须显式替换
LAYLA_DATA_DIR 原生 data;Docker /tmp/layla-data Controller 包和静态资源等本地数据
LAYLA_WEB_DIR 原生 web/dist;Docker /app/web 管理界面构建产物
LAYLA_PROTOCOL_DIR 原生 protocol/platform/v1;Docker /app/protocol/platform/v1 协议文档目录
LAYLA_SECURE_COOKIES false HTTPS 部署设置为 true
LAYLA_PRESIGN_TTL_SECONDS 86400 预签名操作有效期,秒
LAYLA_S3_ENDPOINT 空,禁用文件存储 S3 兼容服务地址
LAYLA_S3_REGION us-east-1 S3 Region
LAYLA_S3_BUCKET 配置 S3 时提供 Bucket 名称
LAYLA_S3_ACCESS_KEY / LAYLA_S3_SECRET_KEY 配置 S3 时提供 仅由 Platform 持有
LAYLA_S3_PATH_STYLE true S3 路径形式
LAYLA_S3_OBJECT_PREFIX layla 对象键前缀

已有本地账号不会因为重启时更改初始化变量而被重置,密码变更通过账号功能完成。S3 也可在管理界面配置;数据库已保存的存储配置优先于启动环境中的 S3 配置。OIDC 配置通过平台认证设置保存,不存在本文未列出的 OIDC 启动环境变量约定。

配置 EManager

一个执行机器运行原生 EManager,其 Worker 是独立进程。测试机示例目录:

/opt/agents/Layla_TAB_V2/.acceptance/runtime/executor/
├── layla-emanager
├── .env
├── data/manager.db
├── workspaces/<task-id>/
├── run/
└── workers/<worker-name>/

编译与启动

cd /opt/agents/Layla_TAB_V2
EXECUTOR_ROOT="$PWD/.acceptance/runtime/executor"
mkdir -p "$EXECUTOR_ROOT"/{data,workspaces,run,workers}
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
  -trimpath -ldflags='-s -w' \
  -o "$EXECUTOR_ROOT/layla-emanager" ./EManager/cmd/layla-manager
cp EManager/.env.example "$EXECUTOR_ROOT/.env"
chmod 600 "$EXECUTOR_ROOT/.env"

先在 Platform 注册 Manager,取得其发放的 Key。编辑示例 .env,将所有数据路径改为本项目目录:

LAYLA_PLATFORM_URL=http://127.0.0.1:8080
LAYLA_MANAGER_KEY=replace-with-issued-manager-key
LAYLA_MANAGER_DATA_DIR=/opt/agents/Layla_TAB_V2/.acceptance/runtime/executor/data
LAYLA_MANAGER_SQLITE_PATH=/opt/agents/Layla_TAB_V2/.acceptance/runtime/executor/data/manager.db
LAYLA_MANAGER_WORKSPACE_DIR=/opt/agents/Layla_TAB_V2/.acceptance/runtime/executor/workspaces
LAYLA_WORKER_LISTEN_ADDRESS=127.0.0.1:9090
LAYLA_MANAGER_HEALTH_ADDRESS=127.0.0.1:9091
LAYLA_HEARTBEAT_INTERVAL_SECONDS=15
LAYLA_WORKER_SYNC_INTERVAL_SECONDS=15
LAYLA_TASK_POLL_INTERVAL_SECONDS=2
LAYLA_PLATFORM_REQUEST_TIMEOUT_SECONDS=30
cd /opt/agents/Layla_TAB_V2/.acceptance/runtime/executor
./layla-emanager
# 另开终端检查:
curl -fsS http://127.0.0.1:9091/healthz
curl -fsS http://127.0.0.1:9091/readyz

Manager 自动读取当前工作目录或可执行文件所在目录的 .env;显式指定 LAYLA_MANAGER_ENV_FILE 可选择其他配置文件。已注入的环境变量优先于文件值。LAYLA_PLATFORM_URL 与 LAYLA_MANAGER_KEY 必填,Worker Runtime 必须监听 loopback 地址。

/healthz 表示进程存活;Platform 不可达或 Key 不被接受时,Manager 仍可启动,但 /readyz 返回 503,直到成功完成心跳。Platform 拒绝未知 Key 时返回 401 INVALID_MANAGER_KEY,不会因此创建 Manager 注册记录。

长期运行可参考 EManager/systemd/ 模板,调整工作目录、环境文件、执行路径和 ReadWritePaths。模板中的旧路径与运行账号需要按当前环境修改;安装到项目外的 systemd 目录前先汇报。

安装 Worker 与 Controller

注册顺序

  1. 在 Platform 创建 Manager,启动已配置的 EManager。
  2. 创建对应 Spec 家族,并在 Manager 下创建 Worker 分配,取得 Worker ID。
  3. 安装该 Worker 的独立运行环境、工具/模型,配置 Worker ID 与本机 Manager 地址。
  4. 启动 Worker,检查在线状态、运行版本和 Spec 接受状态。
  5. 构建对应 Controller ZIP,在平台安装、检查校验结果并启用匹配的 Spec 版本。
  6. 从 Functions 进入 Controller,提交真实输入,验证进度、取消、输出预览与下载。

Worker 默认业务并发为一;当前同 Manager 调度还受机器级串行约束。Worker/Controller 活动 Spec 不匹配、Worker 离线、Spec 被禁用或文件存储不可用时,应先解决对应状态,再提交业务任务。

MarkItDown 原生安装示例

下面只安装 SDK 和 MarkItDown;其他扩展还需依照其专属 README 准备第三方运行时与模型。

cd /opt/agents/Layla_TAB_V2
WORKER_ROOT="$PWD/.acceptance/runtime/executor/workers/markitdown"
mkdir -p "$WORKER_ROOT"
python3 -m venv "$WORKER_ROOT/venv"
"$WORKER_ROOT/venv/bin/python" -m pip install \
  ./EWorker/sdk/python ./EWorker/MarkItDown
cp EWorker/MarkItDown/.env.example "$WORKER_ROOT/.env"
chmod 600 "$WORKER_ROOT/.env"
# 编辑 .env,替换 Worker ID。Worker 不自动读取该文件,启动时显式加载:
cd "$WORKER_ROOT"
set -a
. ./.env
set +a
./venv/bin/layla-markitdown-worker

AudioExtractor 必须在自己的 AUDIO_EXTRACTOR_ROOT/tools/ 下拥有可执行的 ffmpeg、ffprobe、yt-dlp,不能复用另一 Worker 的工具目录。CrispASR、IndexTTS2 和 ComfyUI 的源代码适配层不包含完整上游项目和模型;资源布局、模型校验和 GPU 条件见各组件文档。

Controller 构建与 ZIP

Controller 安装命令(进入对应目录后) ZIP
MarkItDown npm ci markitdown-controller-1.0.0.zip
CrispASR npm ci crispasr-controller-1.0.0.zip
IndexTTS2 pnpm install --frozen-lockfile indextts2-controller-1.0.0.zip
ComfyUI pnpm install --frozen-lockfile comfyui-controller-2.0.0.zip
AudioExtractor pnpm install --frozen-lockfile audio-extractor-controller-1.0.0.zip

统一构建与打包方式:

cd /opt/agents/Layla_TAB_V2/Controller/MarkItDown
npm ci --no-audit --no-fund
npm run build
python3 scripts/package.py

使用 pnpm 锁文件的组件改用 pnpm run build。AudioExtractor 还应运行 pnpm test。显式执行 python3 scripts/package.py 可避免其 npm run package 使用 python 时,在仅提供 python3 的 Linux 上找不到解释器。ZIP 包包含 controller.json、声明的 Spec 与 dist/;构建输出需要先生成。包内不包含服务器代码、Manager/S3 凭据或外部业务调用能力。

构建与测试

Go 测试与二进制

Platform 数据库测试依赖 LAYLA_TEST_DATABASE_URL,不会在缺少数据库时自动通过或改用 SQLite。使用独立测试数据库,不复用业务库;测试创建隔离 schema,并在正常清理时删除 schema。

cd /opt/agents/Layla_TAB_V2
export GOTOOLCHAIN=local
test "$(go env GOVERSION)" = go1.26.8
export LAYLA_TEST_DATABASE_URL='postgres://TEST_USER:URL_ENCODED_PASSWORD@127.0.0.1:5432/layla_test?sslmode=disable'
go test ./Platform/... ./EManager/... ./EWorker/...

mkdir -p .acceptance/build
CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' \
  -o .acceptance/build/layla-platform ./Platform/cmd/layla-platform
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags='-s -w' \
  -o .acceptance/build/layla-emanager-linux-amd64 ./EManager/cmd/layla-manager
go version -m .acceptance/build/layla-emanager-linux-amd64

Windows 开发环境可用 PowerShell 设置相同环境变量;原生发布产物的 GOOS/GOARCH 必须与目标执行机匹配。生产发布前重新生成目标二进制及校验和。EManager/Release/ 的历史产物不随 go.mod 自动更新。

Platform 前端与 Docker

cd /opt/agents/Layla_TAB_V2/Platform/web
npm ci --no-audit --no-fund
npm test
npm run build

cd /opt/agents/Layla_TAB_V2
docker build --network=host -t cloverdo/layla-tab:dev ./Platform
# 仅用于 Manager 测试辅助镜像:
docker build --network=host -f EManager/Dockerfile.test -t layla-emanager:test .

Platform 的 Docker 构建上下文是 Platform/;Manager 测试镜像的上下文是仓库根目录。前者包含前端构建与 Go 1.26.8 后端构建,后者不能作为生产原生 Manager 部署方式。

Python SDK 与适配器测试

在项目内准备独立测试 venv,安装 SDK 和需要验证的适配器。以下完整安装组合使用 Python 3.11,以满足 IndexTTS2 的 <3.12 约束;如主机没有该解释器,先确认安装方案,不直接修改项目外系统环境。MarkItDown 的转换测试依赖真实 MarkItDown 包,CrispASR/IndexTTS2 的导入依赖也需按其项目声明安装。

cd /opt/agents/Layla_TAB_V2
python3.11 -m venv .acceptance/test-venv
.acceptance/test-venv/bin/python -m pip install \
  ./EWorker/sdk/python ./EWorker/MarkItDown ./EWorker/CrispASR \
  ./EWorker/IndexTTS2 ./EWorker/ComfyUI ./EWorker/AudioExtractor

for suite in sdk/python MarkItDown CrispASR IndexTTS2 ComfyUI AudioExtractor; do
  .acceptance/test-venv/bin/python -m unittest discover \
    -s "EWorker/$suite/tests" -v || exit 1
done

各目录内的测试模块存在同名文件,独立进程运行每个 suite 可避免 unittest 导入冲突。适配层使用假引擎的单元测试通过,不代表上游模型或真实 GPU 推理已经验证。

文件存储、媒体与浏览器集成

测试 需要的环境
S3 预签名往返 LAYLA_TEST_S3_ENDPOINT、LAYLA_TEST_S3_BUCKET、LAYLA_TEST_S3_ACCESS_KEY、LAYLA_TEST_S3_SECRET_KEY
AudioExtractor 本地媒体 AUDIO_EXTRACTOR_TEST_TOOLS 指向含 ffmpeg、ffprobe、yt-dlp 的独立目录
AudioExtractor 公共 URL 另配置 AUDIO_EXTRACTOR_TEST_URL
浏览器路由与业务链路 已运行的 Platform、测试账号、Playwright 浏览器;业务测试还需 Worker 和 S3

未配置 S3 或真实媒体条件时,相应集成测试会跳过。浏览器脚本可能修改平台配置,应使用隔离的测试部署并阅读脚本要求:

cd /opt/agents/Layla_TAB_V2/Platform/tests/acceptance/e2e
npm ci --no-audit --no-fund
export PLAYWRIGHT_BROWSERS_PATH='/opt/agents/Layla_TAB_V2/.acceptance/playwright-browsers'
npx playwright install chromium
export LAYLA_PLATFORM_URL='http://127.0.0.1:8080'
export LAYLA_PLATFORM_USERNAME='your-test-user'
export LAYLA_PLATFORM_PASSWORD='your-test-password'
npm run platform:routes

已知测试限制

2026-10-07 在 Go 1.26.8 上的既有基线中,TestHealthLoginAndManagerContract 使用固定 collected_at=2026-08-24T12:00:00Z,而遥测接收接口会清理超过 30 天的非任务样本。因此当前日期执行该测试会在遥测查询断言处失败。此 README 与工具链变更不修改该业务测试;修复时应使测试时间与保留策略一致,不能把失败报告为已通过。

协议与扩展开发

契约 源码 / 文档
Platform Protocol v1 Platform/protocol/platform/v1/openapi.yaml
Spec Protocol v1 Platform/protocol/spec/v1/spec-protocol.schema.json
Manager / Worker Runtime v1 EWorker/protocol/schema/v1/message.schema.json 与 EWorker/protocol/go/v1/
Controller Host SDK v1 Controller/protocol/controller/v1/ 与 Controller/sdk/typescript/
Go Manager 客户端 EManager/sdk/go/platformclient/
Worker SDK EWorker/sdk/go/worker/ 与 EWorker/sdk/python/

新增功能应先阅读统一开发标准,然后依照 Worker 开发合约和 Controller 开发合约开展工作。

  1. 明确功能输入、输出、Artifact 角色、运行依赖和验收要求。
  2. 先定义 Spec;同名同版本的规范化摘要不可变化,破坏兼容性的修改发布新版本。
  3. 实现独立 Worker,并通过 SDK 报告运行版本、支持的 Spec、任务进度与终态。
  4. 实现独立 Controller,通过 Host SDK 访问上下文、上传、素材库、任务与产物。
  5. 校验两端 Spec,测试异常输入、路径边界、取消、重连、版本不匹配及真实业务链路。
  6. 打包、注册并启用扩展,确认对既有功能没有回归。

Platform/EManager 不增加功能名称专用分支。业务需要核心特判才能运行时,应先确认公共协议或 SDK 的缺口。Worker 只读任务声明的输入,在任务 output/ 下生成正式输出;第三方源码、模型和大型依赖不作为 Layla 自有源码提交。Controller 运行在沙箱内,不绕过 Host SDK 直连 Manager、Worker 或 S3。

运维与排错

现象 优先检查
Platform 启动失败 LAYLA_DATABASE_URL、数据库连通性、建表权限、本地数据目录写权限
Platform /readyz 返回 storage_ready:false S3 配置、Bucket/权限和可达性;这与数据库就绪是独立状态
Manager /healthz 正常、/readyz 为 503 Platform URL、网络、已发放且未删除的 Manager Key
INVALID_MANAGER_KEY 使用平台发放的 Key,不把 Worker ID 或登录密码当成 Key
Worker 离线或被隔离 Worker ID、loopback Runtime 地址、Spec 上报结果、独立依赖与进程日志
任务保持 pending Worker/Spec 启用状态、Worker 在线和摘要匹配、同 Manager 是否已有任务
Controller 不显示或无法提交 ZIP 校验、活动 Spec、兼容 Worker、SDK 握手及浏览器日志
预览/下载失败 Artifact 状态、对象是否仍存在、S3 连接、代理路径及支持的内容类型
GPU 扩展启动失败 驱动、CUDA、指定模型与路径,按真实 GPU 条件验收
Docker 构建下载依赖时报 DNS / network unreachable Linux 测试机使用 docker build --network=host 或 Compose build.network: host;仅改变构建网络,不修改系统 DNS
Python venv 创建失败 是否安装了匹配解释器的 venv/ensurepip 支持;需修改项目外系统软件时先汇报

Platform 输出 JSON 日志,可通过 Compose 查看:

cd /opt/agents/Layla_TAB_V2
docker compose -p layla-tab-v2 -f compose.local.yml logs --tail=100 platform

Manager/Worker 的日志查看方式取决于实际进程管理器。对失败请求记录 X-Request-ID、任务 ID、Worker ID 和错误码,便于关联日志;避免把令牌、完整签名 URL 或用户文件内容写入公开问题报告。

非任务遥测当前保留 30 天;任务相关样本随任务历史保留,不受这条非任务样本清理规则影响。文件与历史清理应分别评估数据库、对象存储和工作区,不能用删除 S3 来重置平台核心注册与任务历史。

分支与发布流程

  • dev 用于日常开发与集成;main 接收确认要合入的 dev 状态。
  • 提交前检查差异、Go 版本和与改动对应的构建/测试,清楚记录未通过或跳过的验证。
  • 合并 dev 到 main 会包含 dev 尚未进入 main 的全部提交,应检查提交范围。
  • 分支推送不等于应用部署。构建镜像、推送镜像、更新容器及原生发行产物是独立发布步骤。
  • 不通过强制推送覆盖未知的远程改动;使用正常合并或快进,并核对远程分支最终提交。
  • 不提交 .env、Forgejo Token、Manager Key、S3 密钥、测试数据库或本地验收凭据。
cd /opt/agents/Layla_TAB_V2
git fetch origin
git switch dev
git status --short
git log --oneline origin/main..dev
# 完成必要验证并提交后:
git push origin dev
git switch main
git merge --ff-only dev       # 仅适用于 main 是 dev 祖先的情况
git push origin main
git switch dev

单分支克隆可能没有 origin/main,需要先为 main 配置远程跟踪映射(该配置只添加一次),再获取分支:

git config --add remote.origin.fetch '+refs/heads/main:refs/remotes/origin/main'
git fetch origin refs/heads/main:refs/remotes/origin/main
# 如本地尚无 main:
git branch --track main origin/main

相关文档

阶段验收报告记录的是当时的工具链、部署目录和环境结果;当前工作以此 README、实际源码和项目负责人最新指示为准。