AI 应用
首先,我们先理解下下面几个概念:
lzc-cli是懒猫微服中用来开发微服应用的脚手架,通过lzc-cli可以快速打包应用、安装应用、调试应用、发布应用等。- 通过
lzc-cli打包后产生的包为lpk格式,这是微服中的应用格式。 - 懒猫 AI 浏览器中可以安装插件,支持
PC和Android平台。
AI 应用 是指在微服应用的基础上,导入 AIApp resource 的应用。这一类应用的下载和安装都和正常的微服应用一样,区别在于:
- 支持添加 AI 服务: 应用安装后,会自动将匹配设备型号的服务部署到算力舱上。
- 支持添加 AI 浏览器插件: 应用安装后,AI 浏览器会自动加载对应插件。
- 支持定义 AI 浏览器快捷方式和依赖关系: 快捷方式、上游服务、存储别名等配置由 resource 中的
config/aipod.yml描述。
Resource 导入声明
微服应用通过 lzc-manifest.yml 的 import_resources 声明导入 AIApp resource:
import_resources:
- kind: aipod平台安装应用后,会把 AIApp resource 展开到下面的运行目录:
/lzcapp/run/resources/aipod/<package-id>/其中 <package-id> 为应用包 ID。平台从该目录读取 AI Pod 配置、服务 compose、浏览器插件和兜底 metadata。
Resource 目录结构
推荐的 AIApp resource 结构如下:
aipod/
├── package.yml
├── lzc-manifest.yml
├── icon.png
├── config/
│ └── aipod.yml
├── agxorin/
│ └── docker-compose.yml
├── thor/
│ └── docker-compose.yml
└── extensions/
├── desktop.zip
└── android.crx字段说明:
config/aipod.yml: AI Pod 配置文件,不需要外层aipod:。agxorin/docker-compose.yml: AGX Orin 及默认 Jetson 设备使用的服务定义。thor/docker-compose.yml: Thor 设备使用的服务定义。extensions/*.zip|*.crx: AI 浏览器插件文件,可放置一个或多个。package.yml、lzc-manifest.yml、icon.png: metadata 和图标兜底来源。
兼容旧包时,平台仍会识别以下 legacy 路径:
ai-pod-service/docker-compose.yml: legacy 服务定义。仅当缺少设备型号目录下的 compose 时作为 fallback。browser-extensions/extension.zip: legacy 浏览器插件。仅当缺少extensions/下插件时作为 fallback。
config/aipod.yml
config/aipod.yml 只写 AI Pod 配置本身,不带外层 aipod:。例如:
shortcut:
disable: false
title: ComfyUI
url: /_lzc/aipod_backend/startup/gate/cloud.lazycat.aipod.comfyui?redirect=https%3A%2F%2Fcomfyui-ai
favicon: /icon.png
locales:
en:
shortcut:
title: ComfyUI
depends_on_others:
- ollama-ai
depends_on_hosts:
- comfyui-ai
storage_alias:
models: /ssd/modelsshortcut
安装到微服中的 AI 应用默认会显示在 AI 浏览器快捷方式上。可以通过 shortcut.disable 禁用,也可以覆盖标题、入口地址和图标:
shortcut.disable: 是否隐藏快捷方式,默认为false。shortcut.title: 快捷方式标题。shortcut.url: 快捷方式打开地址。长初始化服务推荐使用平台 startup gate。shortcut.favicon: 快捷方式图标地址。
locales
locales 用于配置多语言 metadata。平台会按浏览器语言选择对应标题、描述或快捷方式字段,缺失时回退到默认配置。
depends_on_others
depends_on_others 声明当前 AI 应用依赖的其他 AI host。平台会在入口和启动检查中考虑这些依赖的可用性。
depends_on_hosts
depends_on_hosts 声明当前 AI 应用自身需要检查的 AI host。通常填写 compose 中通过 Traefik 暴露的 Host(...) 值。
storage_alias
storage_alias 声明服务中使用的存储别名,便于平台将模型、缓存或用户数据挂载到稳定路径。
添加 AI 服务
AI 服务通过 resource 中的 docker-compose.yml 描述。平台根据设备型号选择服务目录:
- Thor 设备优先使用
thor/docker-compose.yml。 - 其他设备默认使用
agxorin/docker-compose.yml。 - 如果型号目录缺失,再 fallback 到 legacy
ai-pod-service/docker-compose.yml。
agxorin、thor 和 legacy 服务如果同时存在,暴露给 AI 浏览器的 AI host 必须一致,避免同一个应用在不同设备上生成不同访问地址。
服务访问规则
算力舱中的服务使用 traefik 结合 Host 规则转发。可被平台识别和部署的 compose 必须包含可解析的 Traefik Host(...) label,并且 host 值必须以 -ai 结尾。
services:
comfyui:
image: registry.lazycat.cloud/demo/comfyui:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.${LZC_SERVICE_ID}-comfyui.rule=Host(`comfyui-ai`)"
networks:
default:
external: true
name: traefik-shared-network规则说明:
Host(...)中的值是微服和 AI 浏览器访问该服务的 AI host。- 只有加入
traefik-shared-network的服务才能被 Traefik 接管。 - 多个设备目录中的 compose 必须暴露相同的 AI host。
- 长初始化服务必须配置
healthcheck,通过容器健康状态控制 ready 状态。平台的安装进度和 startup loading 会复用该状态。
关于 traefik 的更多使用方法可以查看 Host Rule。
附加说明
算力舱中的 docker 默认使用 nvidia-runtime,容器中能直接使用 gpus,不需要显式指定 gpus 相关配置。更详细的说明,点击连接
服务环境变量
服务运行时,算力舱中会提供以下环境变量:
数据持久化路径
- 定义:
/ssd/lzc-ai-agent/data/<service_id> - 环境变量:
LZC_AGENT_DATA_DIR - 示例:
/ssd/lzc-ai-agent/data/cloud.lazycat.aipod.ai
ymlservices: ollama: volumes: - ${LZC_AGENT_DATA_DIR}/data:/root/.ollama- 定义:
数据缓存路径
- 定义:
/ssd/lzc-ai-agent/cache/<service_id> - 环境变量:
LZC_AGENT_CACHE_DIR - 示例:
/ssd/lzc-ai-agent/cache/cloud.lazycat.aipod.ai
ymlservices: ollama: volumes: - ${LZC_AGENT_CACHE_DIR}/cache:/root/.cache- 定义:
服务 ID
- 定义:
<appId>去掉.后的值 - 环境变量:
LZC_SERVICE_ID - 示例:
cloudlazycataipodfishspeech
ymlservices: ollama: labels: - "traefik.http.routers.${LZC_SERVICE_ID}-ollama.rule=Host(`ollama-ai`)"- 定义:
添加 AI 浏览器插件
AI 浏览器插件放在 resource 的 extensions/ 目录中,支持 zip 和 crx:
extensions/
├── desktop.zip
└── android.crxzip 为浏览器兼容的插件格式。如果插件是 wxt 开发的,可以直接打包为 zip;也可以手动把插件目录打包成 zip。
兼容旧包时,平台仍会读取 browser-extensions/extension.zip 作为 legacy fallback。
Metadata 和图标兜底
平台优先读取 resource 中的 config/aipod.yml。当其中缺少标题、描述、图标等 metadata 时,会按下面顺序兜底:
package.ymllzc-manifest.ymlicon.png
如果 metadata 同时存在于微服应用 manifest 和 AIApp resource 中,AI 浏览器相关展示以 resource 配置为准。
启动入口和 loading
长初始化 AI 服务不再推荐每个 AI 应用内置前置 caddy 做健康判断。推荐复用平台提供的 startup gate:
/_lzc/aipod_backend/startup/gate/:appid?redirect=<url>快捷方式直接进入 gate
如果应用入口就是一个 AI host,可以在快捷方式里直接进入 gate:
shortcut:
title: ComfyUI
url: /_lzc/aipod_backend/startup/gate/cloud.lazycat.aipod.comfyui?redirect=https%3A%2F%2Fcomfyui-ai规则说明:
:appid为 AI 应用包 ID。redirect为服务 ready 后跳转的目标地址,需要 URL encode,通常是 compose 暴露的 AI host 或微服页面地址。- 静态前端可以直接走微服平台路由。
- API 或模型服务访问走 Traefik upstream。
- loading、健康检查、失败提示复用平台能力,不需要每个应用重复实现。
静态前端接入 startup gate
如果 AI 应用本身有微服静态前端,更推荐参考 cloud.lazycat.aipod.imgtrans 的做法,在 lzc-manifest.yml 中使用 application.injects 拦截页面请求。这样用户访问任意前端页面时,都会先进入平台 startup loading;服务 ready 后再回到原始页面,并且可以保留深链接和 query。
application:
subdomain: imgtrans
injects:
- id: aipod-startup-gate
'on': request
auth_required: false
when:
- /*
unless:
- /api/*
- /debug/backend/*
- /assets/*
- /favicon.ico
- /icon.png
- /robots.txt
- /manifest.json
- /_lzc/*
do:
- src: >
const appid = "cloud.lazycat.aipod.imgtrans";
const cookieName = "aipod_startup_ready_" +
appid.replace(/[^A-Za-z0-9]/g, "_");
const cookies = String(ctx.headers.get("Cookie") || "");
if (cookies.split(";").map((item) => item.trim()).some((item) =>
item === cookieName + "=1")) {
return;
}
const boxDomain = String(ctx.request.host || "").replace(/^[^.]+\./,
"");
const query = ctx.request.raw_query ? "?" + ctx.request.raw_query :
"";
const redirect = "https://" + ctx.request.host + ctx.request.path +
query;
const location = "https://" + boxDomain +
"/_lzc/aipod_backend/startup/gate/" + encodeURIComponent(appid) +
"?redirect=" + encodeURIComponent(redirect);
ctx.response.send(307, "", { location });
routes:
- /=file:///lzcapp/pkg/content/dist
upstreams:
- location: /api/
backend: http://backend:3000
disable_trim_location: true
public_path:
- /debug/backend/
- /api/这个例子的关键点:
when: /*拦截所有页面入口,unless放行 API、调试接口、静态资源、图标和/_lzc/*平台内部路径,避免资源请求和 gate 自身被重复重定向。appid必须填写当前 AI 应用包 ID,startup gate 会用它查询安装和服务 ready 状态。- gate ready 后会写入
aipod_startup_ready_<appid>cookie,inject 先检查这个 cookie,已 ready 的请求直接放行,避免每次打开页面都进入 loading。 boxDomain通过当前 host 去掉第一段 subdomain 得到,例如从imgtrans.13gxg.heiyu.space得到13gxg.heiyu.space。redirect保留用户原始访问地址和 query,并用encodeURIComponent传给 gate。服务 ready 后,平台会跳回这个地址。- 前端静态文件继续使用
routes暴露,应用自己的 API 使用upstreams转发。startup gate 只负责 ready/loading,不替代业务路由。
对应的 AIApp resource 中可以声明依赖,平台会把这些依赖纳入 ready 判断:
shortcut:
disable: false
depends_on_others:
- trans
- ocr指定某一个算力舱上的服务
在具有多个算力舱的情况下,可以通过 f-{算力舱的序列号}-{服务名称}-ai.{微服名称}.heiyu.space 来访问。例如:
https://f-1420225016421-dozzle-ai.catdog.heiyu.space