V2 独立版愿景

系统设置

HeteroFlow 是本站的异构算力与大模型调度产品。系统设置。系统设置 系统设置页( )是 HeteroFlow 平台管理员的运维控制台:负载调度阈值、任务默认内存、告警外发渠道三类全局配置在此集中管理,配套一个随时可跑的系统自检面板把"平台现在健康吗"变成六项可核对的检查结果。页面上每一项配置都遵循同一条纪律—— 改完即生效、落盘可持久、…

系统设置

系统设置页(/settings)是 HeteroFlow 平台管理员的运维控制台:负载调度阈值、任务默认内存、告警外发渠道三类全局配置在此集中管理,配套一个随时可跑的系统自检面板把"平台现在健康吗"变成六项可核对的检查结果。页面上每一项配置都遵循同一条纪律——改完即生效、落盘可持久、部分更新不误伤未提及的键:负载阈值保存后立刻同步进运行中的调度器并写回 config.yaml,任务默认内存与告警渠道存入数据库配置表,告警渠道更是保存后下一次告警推送就走新配置,全程不需要重启服务。

整个页面挂在前端 AdminRoute 守卫之后(非平台 admin 角色访问即重定向回首页),后端每条读写接口再各自校验权限,形成页面级与接口级的双层收口。本页讲的是平台侧全局设置;节点环境与镜像检测请见《环境检测》篇。

功能总览

能力一句话说明状态
负载调度阈值GPU 显存/算力/温度、CPU、内存五项准入阈值,超阈值的节点不再接收新任务已实现
阈值即时生效与持久化保存即同步运行中的调度器并落盘 config.yaml,重启不丢已实现
任务默认内存推理/训练/Docker 三类任务创建未填内存时的全局兜底值,按类型独立配置已实现
告警外发渠道企业微信/钉钉/飞书群机器人 webhook 配置,推送级别两档可选已实现
凭据脱敏回显webhook 与密钥从不明文回显,留空保存即保持原值已实现
渠道测试发送每渠道一键真实发送测试告警,配置对不对当场验证已实现
告警配置热更新渠道配置保存后下一次告警推送即走新配置,无需重启已实现
系统自检后端服务/插件/节点/GPU/分片/任务队列六项检查 + 总体状态聚合已实现
一键修复插件系统重初始化、残留分片清理、僵死任务裁决三项修复动作,二次确认后执行已实现
权限双层收口前端 AdminRoute 页面守卫 + 后端逐接口读写权限校验已实现

负载调度阈值:逐项说明

这是页面的第一个区块,由五个滑块组成。当节点资源使用率超过阈值时,调度器不再向该节点分配新任务——这是集群过载保护的第一道闸门,判定发生在每次调度绑定前。

配置项配置键默认值滑块范围作用范围
GPU 显存使用率gpu_memory_percent90%50–99%节点单卡真实显存用量达到该百分比后,该卡不再接收新任务
GPU 计算利用率gpu_utilization_percent90%50–99%单卡算力利用率超阈值后不再接收新任务
GPU 温度阈值gpu_temperature_threshold85°C40–95°C单卡温度超阈值后不再接收新任务;节点不支持温度采集(上报温度为 0)时自动跳过该项检查
CPU 利用率cpu_percent85%50–99%节点级 CPU 使用率超阈值后不再接收新任务
系统内存使用率memory_percent85%50–99%节点级内存使用率超阈值后不再接收新任务

几个关键行为细节:

  • 判定是逐卡的三合一检查:GPU 三项阈值在调度器里是一个整体判定(core/pkg/scheduler/scheduler_core.go 的 nodeHasAvailableGPU)——一张卡必须显存、算力、温度三项同时达标才算可用,任何一项越界这张卡就出局;三项阈值任一大于 0 该检查才启用。CPU 与内存则是节点级判定,同样以大于 0 为启用条件。
  • 保存语义是严格的部分更新:前端保存时刻意只提交 thresholds 一个对象,不带页面加载时顺带读到的 GPU 保留配置——依赖后端"请求里没出现的字段保持原值"的指针字段语义。这样即使另一个管理员刚在别处改过别的配置项,这次保存也不会用过期快照把它悄悄回滚。该语义由 API 层性质测试钉住(未传字段不许被改、改动必须真的落盘)。
  • 0 = 关闭检查是接口级语义:直接调 API 可以把某项阈值显式设为 0(关闭该项检查)、百分比上限 100、温度上限 120°C;前端滑块不提供这个入口,界面操作范围内始终为启用状态。
  • 改完的去向:保存 → 后端先改运行中调度器的内存态(下一轮调度立即生效)→ 再写回 config.yaml(重启后由启动流程回填,配置不丢)。落盘失败会如实返回 500 并注明"内存已生效,重启会丢",绝不假装成功。
  • 与推理显存预算是两回事:这里的 GPU 显存阈值是调度准入判断(卡快满了就别再塞),与推理引擎的 KV Cache 显存预算(gpu_memory_utilization)语义无关、方向相反,2026-08-29 起已拆分为两个独立字段,互不牵连。

页面顶部的"刷新"按钮重新拉取当前生效配置;保存成功后出现"配置已保存"提示,3 秒自动消失。

任务默认内存:创建任务的兜底值

第二个区块回答一个问题:创建任务时没填内存(memory_mb)怎么办? 答案是按任务类型读这里配的全局默认值。三个键互相独立、逐项可配:

配置项配置键未配置时回落说明
推理服务默认内存default_memory_mb_inference512 MB创建推理服务未指定内存时使用。推理创建表单本身没有内存输入项,实际全部走这个兜底值
训练任务默认内存default_memory_mb_training512 MB创建训练任务未指定内存时使用。训练表单同样没有内存输入项
Docker 任务默认内存default_memory_mb_docker512 MB创建普通 Docker 任务未指定内存时使用。前端表单自带 4096 MB 预填值,此键主要覆盖直接调 API 不传 memory_mb 的场景

校验与生效规则:

  • 下限 64 MB:前端在输入框就地拦截(空值、非整数、低于 64 MB 都无法点保存),后端 PUT 同样拒绝低于 64 MB 的值——过小的默认值会让默认创建的容器直接 OOM。即使有人绕过 API 手改数据库塞进非法值,读取侧也会忽略它回落 512 MB。
  • 作用于创建时,不追溯存量:这三个键只在任务创建请求缺省 memory_mb 时参与解析,已创建任务的内存值在创建瞬间已经落库定型,之后改这里不会影响它们。
  • 任务类型判定吃权威结果:inference / training 之外的一切类型(含未标注的普通任务)一律走 docker 键,不另立一套分类。
  • 部分更新语义与整区块保存:PUT 接口没携带的键不动(全指针字段);本区块的三个键都归这个表单所有,保存时整表提交,响应体返回当前生效值供界面回显。

告警外发渠道:把告警推进群里

第三个区块配置告警的多渠道外发,支持三家有官方 webhook 的群机器人。每渠道一组配置 + 一个真实的测试发送按钮;保存后即时生效——下一次告警推送就走新配置,无需重启服务。渠道列表:

渠道加签密钥获取方式(页面内附图文指引)
企业微信群机器人无需密钥群设置 → 添加群机器人 → 复制 Webhook 地址
钉钉群机器人需要(SEC 开头的加签密钥)群设置 → 智能群助手 → 自定义机器人,安全设置勾选"加签"
飞书群机器人可选(开启签名校验才需要)群设置 → 群机器人 → 自定义机器人,复制 Webhook 地址

逐字段说明:

字段控件行为
推送级别单选(全部告警 / 仅 ERROR 及以上)全局过滤:选"仅 ERROR 及以上"时低级别告警不外发,只在平台内落库
启用开关每渠道一个复选框关闭后该渠道不外发,配置保留
Webhook 地址文本框已配置时 placeholder 显示脱敏串(如 https://qyapi.weixin.qq.com/.../send?key=abcd****)并注明"留空保持不变";启用中的渠道保存时必须已配置且以 http(s) 开头,否则 400 拒绝
加签密钥密码框(钉钉/飞书)同样脱敏回显、留空保持原值;要改就整段重新粘贴
发送测试每渠道一个按钮真实走网络发一条测试告警到目标群;输入框里有新值就用新值测(可测尚未保存的配置),留空则用已保存值。发送失败按"用户配置/网络问题"如实返回失败原因,不算服务器错误
保存渠道配置按钮提交后回读脱敏配置刷新界面,Toast 提示"即时生效,无需重启"

凭据安全约定(与后端一致):GET 从不明文回显 webhook URL 与密钥——webhook URL 里的 key/access_token 查询参数本身就是凭据,明文回显等于泄密;后端只返回脱敏展示串(token 保留前 4 位便于识别)加"是否已配置"标志。前端因此拿不到原值,"留空 = 保持原值"是唯一安全的修改语义。此外页面还提供可展开的"如何获取 Webhook"分步指引,照着点就能配好。

渠道配置以单个 JSON 键存进数据库配置表,告警推送时按需热读取;后端为非 PostgreSQL 存储时该区块显示"未启用"提示(告警仅落库不外发)。告警的类型体系、生命周期与推送触发机制见《告警管理》篇,本篇只讲配置面。

系统自检:六项检查与一键修复

第四个区块是运维巡检面板,进入页面自动跑一轮,之后可随时点"重新检测"。

逐检查项与判据(后端 core/pkg/api/system.go):

检查项正常警告异常可修复
后端服务能响应本接口即正常——否
插件系统已加载 ≥1 个插件(文案报数量)—没有加载任何插件是
节点状态有节点且至少一个在线没有注册任何节点所有节点离线否(节点离线只能由 Agent 上线或人工注册解决,服务端没有对应修复动作,契约如实标不可修复)
GPU 资源"n/m 个 GPU 可用"(可用/总数)无 GPU;或存在判定丢失的卡(仍计入总数、不计可用,文案点明张数并指引到节点页)—否
GPU 分片报当前已分配分片数——是(清理残留)
任务队列待处理任务 ≤10积压超 10 个 pending(全平台口径,显式跨全租户统计,不受请求者所在租户收窄)—是

总体状态按最差项聚合:任一项异常 → 总体异常;否则任一项警告 → 总体警告;全正常 → 正常。界面形态为顶部总体状态灯 + 逐项列表(状态点、名称、状态标签、判据文案)+ 底部检测时间戳。

一键修复(可修复项异常时出现"修复..."按钮):

修复项实际动作
插件系统以插件管理器现有配置打底、config.yaml 配置覆盖,重新初始化插件系统,并同步重建调度器实际生效的插件列表
GPU 分片释放并删除所有处于 releasing 状态的残留分片记录,同时对已释放分片下发 MIG 分区销毁指令,避免"账上删了、卡上还在"
任务队列将排队超过 1 小时仍未调度的待处理任务标记为失败(终态,不可逆)

修复的交互刻意做了两道防护:点击"修复..."先展开内联确认面板,明示"将执行"的具体操作再二次确认;修复请求本身做了去取消化——批量清理中途断连不会只清一半就停,保证内存与数据库一致。修复完成后自动重跑一轮自检,让结果当场刷新。某项是否显示修复按钮由后端返回的 auto_fixable 契约字段决定,前端不做白名单绕过,契约与实际修复能力一一对应。

配置持久化:双轨与单一持久源原则

本页管理的配置按性质分两条持久化轨道,各自纪律明确:

轨道持久层覆盖配置生效方式
运行时键值配置PostgreSQL system_config 表(key 主键 / value 文本 / 更新时间,UPSERT 写入)任务默认内存三键、告警渠道 JSON、推理全局配置等保存即落库,消费方按需读取(告警渠道为每次推送热读取)
调度行为配置config.yaml 的 scheduler 段五项负载阈值、GPU 保留配置保存时先改运行中调度器内存态(下一轮调度生效),再落盘;启动时从 yaml 回填进调度器

第二条轨道遵循单一持久源原则:同一字段绝不允许两个持久化来源并存。这不是纸面洁癖——GPU 温度阈值曾经就是双源形态:一个接口写数据库、另一个接口写 yaml,而启动流程只读 yaml,于是库里的值每次重启必被覆盖,界面上"保存成功"、重启后配置原地消失,且无从排查。2026-08-29 起收敛为只写 yaml 一个来源,保存新值时顺带清理历史遗留的库键(清理刻意安排在 yaml 落盘成功之后,落盘失败时旧值至少还留在一处)。

写入路径的并发安全也有交代:修改内存中的配置对象与整份序列化落盘之间用同一把锁互斥,避免并发保存与配置导出互相踩踏;落盘失败按"内存已生效、重启会丢"如实报 500,绝不提示假成功。

页面功能介绍

/settings 系统设置页(平台 admin 专属)

页面加载时并行拉取调度器配置、任务默认内存、告警渠道配置并自动跑一轮系统自检;四个区块各自独立保存、互不牵连。

区块操作 / 控件行为背后 API
页头刷新按钮重新拉取负载阈值当前生效值GET /api/v1/scheduler/config
负载调度阈值五个滑块(百分比 50–99 / 温度 40–95,步进 1,右侧实时显示当前值与单位)拖动即时预览;保存时只提交 thresholds 对象PUT /api/v1/scheduler/config
负载调度阈值保存配置按钮同步调度器内存态 + 落盘 config.yaml;成功提示 3 秒自动消失同上
任务默认内存三个数字输入框(MB,最小 64)非法值就地标红并禁用保存按钮,不发请求GET / PUT /api/v1/system/task-defaults
任务默认内存保存配置按钮整表提交三键,响应回显生效值同上
告警外发渠道推送级别单选、三渠道启用开关、Webhook/密钥输入框、获取指引折叠面板留空字段保持原值;启用渠道必须有合法 webhookGET / PUT /api/v1/alerts/notify-config
告警外发渠道发送测试按钮(每渠道)真实发送测试告警;新值优先、留空用已存值POST /api/v1/alerts/test-notify
告警外发渠道保存渠道配置按钮保存后回读脱敏配置刷新,即时生效同 PUT
系统自检重新检测按钮重跑六项检查GET /api/v1/system/check
系统自检修复...→ 确认执行 / 取消内联二次确认后触发修复,完成自动复检POST /api/v1/system/fix

后端逻辑概念表

概念定义代码出处
THRESHOLD_CONFIGS前端五项阈值的单一真相源:键、文案、默认值一处派生,改默认值即全局生效web/src/pages/SettingsPage.tsx:17
阈值部分更新语义PUT 请求全指针字段:nil = 本次不改,显式 0 = 关闭该项检查,杜绝"没传"与"传 0"混淆core/pkg/api/plugin.go:348
nodeHasAvailableGPU调度器逐卡准入判定:显存、算力、温度三项同时达标才算可用;温度为 0 视为不支持采集跳过core/pkg/scheduler/scheduler_core.go:718
NewScheduler 默认阈值五项默认 90/90/85/85/85,调度器未注入时 GET 接口回落同款默认core/pkg/scheduler/types.go:256
resolveDefaultMemoryMB创建请求缺省 memory_mb 时按任务类型读全局默认键,非法/未配置一律回落 512core/pkg/api/task_default_memory.go:60
MinDefaultTaskMemoryMB默认内存下限 64 MB:PUT 校验拒收,读取侧对绕过 API 的非法库值同样忽略core/pkg/api/task_default_memory.go:41
system_config 表全局配置键值表(key 主键 / value TEXT / updated_at),任务默认内存、告警渠道等运行时配置的持久层core/pkg/storage/postgres/schema.go:766
ConfigStoresystem_config 的读写访问器,UPSERT 语义写入core/pkg/storage/postgres/config.go:18
alert_notify_channels三渠道配置在 system_config 的单一 JSON 键,推送时热读取实现免重启生效pkg/plugin/plugins/group_bot_notifier.go:44
maskToken / maskWebhookURL密钥与 webhook URL 中 token 参数的脱敏:保留前 4 位与 host+path,凭据绝不明文回显core/pkg/api/alert.go:1671
mergeChannel渠道配置合并规则:留空的 webhook/密钥保持原值——脱敏回显下唯一安全的"不修改"信号core/pkg/api/alert.go:1765
handleSystemCheck六项检查的判定与总体状态聚合;任务队列项显式全租户口径core/pkg/api/system.go:31
systemGPUCheckGPU 资源项判定:丢失卡(lost_at)单独计数、计入总数不计可用core/pkg/api/system.go:695
handleSystemFix三项修复分支;detachedWriteContext 去取消化保证批量清理不半途而废core/pkg/api/system.go:154
auto_fixable 契约检查项可否修复由后端据实上报(节点状态曾谎报可修复已纠正),前端直接信任该字段core/pkg/api/system.go:27
requireAdminAuth登录 + 权限校验之外强制平台管理员角色;system/check 与 system/fix 挂此门禁core/pkg/api/middleware.go:348
AdminRoute前端页面守卫:未登录跳登录页,非平台 admin 重定向首页web/src/auth/PrivateRoute.tsx:27

API 参考

接口说明
GET /api/v1/scheduler/config读调度器配置:五项负载阈值 + GPU 保留配置。挂 settings:read(普通用户也持有——分片页轮询共用此接口,刻意保持读开放)
PUT /api/v1/scheduler/config部分更新:nil 字段不动、显式 0 关闭对应检查(百分比 0–100、温度 0–120);先同步运行中调度器再落盘 config.yaml。路由级 settings:read + 处理器内二次校验 settings:write(仅 admin 持有)
GET /api/v1/system/task-defaults三类任务默认内存当前生效值(未配置键回落 512)
PUT /api/v1/system/task-defaults部分更新三键;值域 ≥64 MB,未知字段 400;system:write
GET /api/v1/alerts/notify-config告警渠道配置(脱敏视图 + 已配置标志 + 推送级别);非 PG 后端 503
PUT /api/v1/alerts/notify-config保存渠道配置:留空字段保持原值,启用渠道强制校验 webhook;保存后热生效;system:write
POST /api/v1/alerts/test-notify渠道真实测试发送;channel 仅认 wecom/dingtalk/feishu;发送失败回 success:false 而非 5xx
GET /api/v1/system/check系统自检:六项检查 + overall_status + 时间戳;requireAdminAuth(平台管理员专属)
POST /api/v1/system/fix按检查项名修复(插件系统/GPU分片/任务队列);未知项名返回 fixed:false 并点名认识的键;requireAdminAuth

已知边界

1. GPU 保留配置不在本页管理:GET /api/v1/scheduler/config 返回的 gpu_reserve_fixed_mb / gpu_reserve_percent 由分片页的配置表单负责编辑,本页保存时刻意只提交阈值对象,避免用过期快照覆盖他处刚改的保留值。

2. 推理全局配置另有入口:推理休眠超时、KV Cache 显存预算、单节点推理服务数上限等键走独立的 PUT /api/v1/system/inference-config(见《推理服务》篇),不在本页面。

3. 告警外发渠道依赖 PostgreSQL 后端:非 PG 部署下通知器不装配,本区块显示"未启用",告警仅平台内落库。

4. 推送级别非法值静默回落:min_level 传非 all/error 的值时不报错,回落"全部告警"。

5. 前端滑块不含"关闭检查"入口:阈值设 0(关闭该项过载检查)是 API 级语义,需要直接调 PUT 接口;界面滑块始终落在启用区间。

6. 任务队列积压阈值固定:自检的"pending > 10 判积压"与修复的"排队超 1 小时判僵死"是代码常量,不可配置。

7. "后端服务"检查项恒为正常:该检查的判据就是"能响应本接口",不做更深的依赖健康判定(数据库、连接池等另由服务器监控覆盖,见《服务器监控》篇)。

8. 任务队列修复不可逆:将排队超 1 小时的 pending 任务标记为 failed 是终态写入,确认面板已明示该操作会修改系统状态,执行前请确认积压原因(例如节点全部离线时应先恢复节点而非清理队列)。

9. Email / Slack 渠道未实现:多渠道外发当前只覆盖企业微信/钉钉/飞书三家群机器人(另有环境变量形态的 legacy 通用 webhook 兜底),其他渠道形态不在当前承诺内。

<!-- 状态标注说明: 已实现=代码+测试钉住并在开发环境长期运行;本篇各能力均无"真机 GPU 验证"范畴的独立验证记录,故统一标"已实现" -->