KADT WebUI
KADT的可视化部署界面,支持OpenCode、OpenClaw和vLLM-Ascend三种部署方案的Web化管理。
核心特性
可视化部署
- 清晰的步骤流程展示
- 实时日志输出与滚动刷新
单步执行
- 每个步骤可独立执行
- 支持跳过、重试
- 参数表单动态渲染
- 服务器IP/密码配置
进程管理
- 任务中止(SIGTERM → SIGKILL)
- WebUI重启不杀运行中的任务
- 任务状态持久化与恢复
- 进程意外终止检测
配置驱动
- YAML配置定义脚本流程
- 无需修改Python代码即可扩展
- 动态选项(如OS列表)实时获取
- 多参数类型支持
快速启动
使用启动脚本(推荐)
cd kadt/webui
./launcher.sh
默认端口:8080
自定义端口
./launcher.sh 9000
launcher.sh 功能
启动脚本会自动完成以下操作:
- 检查 Python 环境:验证 Python 3 是否可用
- 自动安装依赖:检测并安装 Flask、PyYAML(如未安装)
- 获取本机 IP:自动获取服务器 IP 地址用于远程访问
- 启动服务:启动 Flask 应用
启动后显示访问地址:
访问地址:
本机: http://127.0.0.1:8080
远程: http://10.10.10.10:8080
直接启动(不推荐)
cd kadt/webui
python3 app.py --port 8080
此方式需要手动安装依赖:
pip3 install flask pyyaml
依赖
最小依赖设计,仅需:
- Python 3.6+
- Flask
- PyYAML
使用 launcher.sh 启动时会自动检测并安装缺失的依赖。
手动安装:
pip3 install flask pyyaml
支持的部署方案
| Profile | 名称 | 步骤数 | 说明 |
|---|---|---|---|
| opencode | OpenCode 一体机 | 4步 | AI 编程助手(下载→安装→LLM→应用) |
| openclaw | OpenClaw 一体机 | 4步 | AI Agent助手(下载→安装→LLM→应用) |
| vllm-ascend | vLLM-Ascend | 3步 | 纯推理服务(下载→安装→LLM) |
使用流程
1. 选择部署方案
首页展示3个Profile卡片,点击选择进入工作流页面。
2. 查看部署流程
左侧显示完整步骤列表,右侧显示当前步骤详情。
3. 执行步骤
- 点击「执行」进入参数填写页面
- 填写必要参数(服务器、模型、端口等)
- 点击「开始执行」,查看实时日志
- 等待执行完成,查看结果状态
4. 继续后续步骤
按顺序执行或跳过某些步骤,所有步骤完成后部署成功。
参数类型
WebUI支持多种参数类型,自动渲染对应表单:
| 类型 | 说明 | 示例 |
|---|---|---|
| text | 文本输入 | 模型名称、路径 |
| number | 数字输入 | 端口、实例数量 |
| password | 密码输入 | API Key、SSH密码 |
| select | 下拉选择 | 操作系统、模型 |
| checkbox | 复选框 | 布尔开关 |
| servers | 服务器配置 | IP + 密码输入 |
| software_list | 软件列表 | 添加/删除软件组件 |
特殊参数
servers类型:
- 支持添加多个远程服务器
- IP支持单IP或IP范围(10.10.10.1-10.10.10.9)
- User固定为root,需填写密码
- 自动更新
ascend_deployer/inventory_file
software_list类型:
- 显示已选软件标签,点击×可删除
- 输入框添加新软件名称
- 逗号分隔传递给脚本(如
sys_pkg,npu,docker_compose)
select + bool_flag:
- 当options为
["true", "false"]且bool_flag: true时 - 渲染为开关,true时添加flag参数(如
--dual-node)
目录结构
webui/
├── app.py # Flask应用
├── script_runner.py # 核心执行引擎
├── scripts_config.yaml # YAML配置
├── launcher.sh # 启动脚本(自动安装依赖)
├── templates/ # Jinja2模板
│ ├── base.html # 基础模板
│ ├── index.html # 首页(Profile卡片)
│ ├── workflow.html # 工作流页面
│ ├── step.html # 步骤执行页面
│ ├── logs.html # 日志查看页面
│ ├── tasks.html # 任务列表页面
│ └── error.html # 错误页面
├── static/
│ ├── style.css # CSS
│ └── app.js # 前端交互逻辑
├── logs/ # 任务日志与状态文件
│ ├── task_xxx.log # 执行日志
│ └── task_xxx.status.json # 任务状态
└── README.md # 本文件
技术架构
Flask应用 (app.py)
- 6个页面路由:index, profile, step, logs, tasks, error
- 8个API路由:profiles, workflow, step, execute, logs, task, tasks, kill, health
- datetime模板过滤器
- threaded=True支持并发请求
ScriptRunner (script_runner.py)
核心执行引擎,负责:
- 配置解析:加载YAML,提取profiles/workflow/params
- 命令构建:根据参数类型生成bash命令
- inventory更新:写入服务器列表到inventory_file
- 异步执行:subprocess.Popen + 独立进程组
- 日志管理:实时写入,支持增量读取
- 进程管理:SIGTERM/SIGKILL中止,进程存活检测
- 状态恢复:启动时扫描.status.json,恢复运行中任务
- 清理机制:退出时终止运行中任务,定时清理24小时前的日志
关键设计:
start_new_session=True:创建独立进程组,不受WebUI退出影响stdin.write(b'y\n'):自动确认EULA- 状态持久化到JSON文件,支持跨重启恢复
配置驱动 (scripts_config.yaml)
每个profile定义workflow,每个step定义params:
profiles:
opencode:
display_name: "OpenCode 一体机"
workflow:
- name: download
script: "opencode/opencode_download.sh"
title: "软件下载"
params:
- name: os
type: select
source: dynamic
source_cmd: "python3 -c '...'"
无需修改Python代码,只需修改YAML即可扩展新脚本。
API接口
REST API可用于集成或自动化:
| 路径 | 方法 | 说明 |
|---|---|---|
/api/profiles |
GET | 获取所有profile列表 |
/api/workflow/<profile> |
GET | 获取profile的workflow步骤 |
/api/step/<profile>/<step> |
GET | 获取步骤表单信息(含动态选项) |
/api/execute |
POST | 执行步骤,返回task_id |
/api/logs/<task_id>?pos=N |
GET | 增量读取日志(从pos位置开始) |
/api/task/<task_id> |
GET | 获取任务状态 |
/api/tasks |
GET | 获取所有任务列表 |
/api/kill/<task_id> |
POST | 中止正在运行的任务 |
/api/health |
GET | 健康检查 |
执行API示例
curl -X POST http://localhost:8080/api/execute \
-H "Content-Type: application/json" \
-d '{
"profile": "opencode",
"step": "download",
"params": {
"os": "openeuler22.03",
"model": "Qwen/Qwen3-8B"
}
}'
返回:
{
"task_id": "task_1234567890_1",
"status": "started",
"message": "任务 task_xxx 已启动"
}
进程生命周期
正常流程
- 用户点击「开始执行」
- ScriptRunner创建独立进程组(start_new_session)
- 进程运行,日志实时写入
- 进程结束,更新状态(success/failed)
- WebUI退出时不影响进程运行
任务中止
- 用户点击「中止任务」
- 发送SIGTERM,等待0.3秒
- 进程仍存活则发送SIGKILL
- 更新状态为killed,写入日志
WebUI重启恢复
- 启动时扫描logs/*.status.json
- 状态为running的检查进程是否存活
- 存活则恢复任务,继续监控
- 不存活则更新状态为failed
WebUI退出清理
- 注册atexit和SIGTERM/SIGINT信号
- 扫描所有running状态任务
- 发送SIGTERM终止进程
- 更新状态为killed,写入日志
测试
WebUI包含完整的测试套件(39个测试):
cd ../..
python3 -m pytest test/st/test_webui.py -v
测试覆盖:
- JavaScript语法验证
- Jinja2模板语法验证
- Python导入测试
- Flask路由测试
- ScriptRunner功能测试
- 配置文件解析测试
- CSS语法检查
- HTML渲染测试(新增)
- JSON数据属性引号格式验证
- help_panel元素渲染验证
- dynamic_filter属性完整性验证
- 参数默认值渲染验证
- JSON可解析性验证
扩展新脚本
1. 添加脚本
在kadt/your_profile/下创建脚本:
#!/bin/bash
# your_script.sh
while [[ $# -gt 0 ]]; do
case $1 in
--param-name)
PARAM_VALUE="$2"
shift 2
;;
*)
shift
;;
esac
done
2. 添加配置
修改scripts_config.yaml:
profiles:
your_profile:
display_name: "你的方案"
description: "方案描述"
icon: "server"
workflow:
- name: your_step
script: "your_profile/your_script.sh"
title: "步骤标题"
description: "步骤描述"
standalone: true
skip_allowed: true
params:
- name: param-name
type: text
label: "参数名"
required: true
placeholder: "请输入"
3. 高级参数类型
dynamic_filter - 动态过滤下拉选项
根据其他参数值动态过滤可选项(如根据服务器类型过滤模型):
- name: model
type: select
label: 模型名称
required: true
dynamic_filter: true
filter_depends:
- server-type
- dual-node
filter_rules:
a2_single:
- Qwen3-8B
- Qwen3-14B
a2_multi:
- MiniMax-M2.5
options:
- Qwen3-8B
- Qwen3-14B
- MiniMax-M2.5
重要:filter_depends和filter_rules在HTML中会转为JSON属性,模板必须使用单引号包裹:
data-filter-depends='["server-type", "dual-node"]'
data-filter-rules='{"a2_single": ["Qwen3-8B"]}'
help_panel - 可折叠帮助面板
显示兼容性说明等信息:
- name: model_help
type: help_panel
title: 模型兼容性说明
collapsed: true
content:
a2_single:
title: A2 单机
models:
- Qwen3-8B
- Qwen3-14B
a2_multi:
title: A2 多机
models:
- MiniMax-M2.5
注意:help_panel不需要label字段,只需要title。
frontend_only - 前端专用参数
不传递给后端脚本,仅用于前端交互:
- name: server-type
type: select
label: 服务器类型
frontend_only: true
options:
- a2
- a3
default: a2
frontend_only参数在ScriptRunner.build_command()中会被跳过。
无需修改任何Python代码,重启WebUI即可生效。
注意事项
- 执行权限:所有部署脚本需要root权限执行
- 重启提醒:base_install步骤执行后需要重启服务器(NPU驱动生效)
- 模型权重:下载的模型存储在
model_weights/目录 - 日志清理:任务状态文件和日志默认保留24小时
- 端口占用:默认8080端口,如被占用请指定其他端口
- 浏览器兼容:推荐使用Chrome/Firefox/Safari现代浏览器
- HTML/JS交互:模板中JSON数据属性必须使用单引号包裹
<!-- 正确:单引号包裹JSON --> data-filter-depends='["server-type", "dual-node"]' <!-- 错误:双引号会与JSON内部引号冲突 --> data-filter-depends="[\"server-type\"]"
故障排除
Flask启动失败
pip3 install flask --upgrade
YAML解析错误
pip3 install pyyaml --upgrade
权限问题
chmod +x app.py script_runner.py
chmod +x ../common/*.sh
chmod +x ../opencode/*.sh
chmod +x ../openclaw/*.sh
chmod +x ../vllm-ascend/*.sh
Ansible回调模块错误
参考主仓库AGENTS.md中的解决方案:
cd ascend_deployer/resources/sources/ansible_collections
ansible-galaxy collection install community-general-*.tar.gz
进程无法中止
检查进程状态:
ps aux | grep <task_id中的PID>
kill -9 <PID>
版本历史
v1.0 (2026-05)
- 基础WebUI框架
- 3个部署方案支持
- 单步执行与实时日志
- 任务中止功能
- 服务器配置
- 软件列表编辑
- 任务状态恢复机制
- 模型兼容性过滤
- help_panel帮助面板
- frontend_only参数支持
- 39个自动化测试(含HTML渲染测试)