平台架构 · v4.5 · 2026-11-13

多节点 AI Agent 计算与调度平台

PCS 控制面管理主机、部署与 Agent / API 档案,密钥只保存 Secret Store 引用; 主机侧 host-runtime 执行签名命令;调度机按递归树派发任务,结点调度机逐级汇总能力; 主机可以并入另一台主机组成联邦,跨调度机的任务只下推、不复制。 局域网设备可以拿侧载令牌走同一条任务链路,每个任务都能通过附件与产物通道收发文件。

控制面 PCS 根调度机 结点调度机 叶构建机 Agent / API 档案 Secret Store MCP builders 侧载令牌 附件 / 产物 工作能力值 W 任务难度 D 能力汇总 ΣW 主机并入 跨调度机中继
图 1 · 控制面与主机 PCS 只写期望态;容器生命周期由主机上的 host-runtime 执行
管理应用(浏览器) AI Agent 工作室 · 构建机 · 任务 对话 · 终端 · 按主机折叠 单页应用 · 无登录角色 HTTPS 局域网设备 · 侧载 curl · sdl_ 令牌 · 权限 附件 ↔ 产物 HTTPS · sdl_ PCS 控制面 主机接入 · 部署与签名命令 · Agent / API 档案 · 审计 主机名册 本地 / SSH 远程 parent_host_id 联邦树 部署计划 镜像 digest 白名单 CPU · 内存 · 磁盘 Agent 档案 role_agent_bindings 模型 · CLI / HTTP API 档案 role_api_bindings llm · secret:// 引用 Secret Store 密钥值不在平台库 文件 0600 · 实例 JWT 审计与事件 谁改了哪台主机 全部操作可回溯 出站长轮询 · 签名命令幂等 本地主机 A · 运行管理页面 / PCS 本机执行探测与引导,不需要 SSH host-runtime 拉取期望态 · 执行签名命令 写容器端口 / 卷 / 网络 docker 只在主机侧调用 scheduler 根调度机 :8443 任务 · 租约 · 控制台任务 文件收发 · MCP builders builder × N 构建 Agent + sshd root shell SSH 远程主机 B 私钥 AES-256-GCM 加密保存,接口只回指纹 host-runtime 一次性引导后主动连 PCS 长期不再需要 SSH 会话 bundle 与命令公钥写在主机侧 builder × N 构建 Agent + sshd root shell scheduler B 的根(可并入 A) 任务 · 租约 · 调度 Agent MCP builders → 构建机 PCS 不直接调用 Docker;私钥只用于探测与一次性引导。容器 sshd 只接受部署时注入的主机登录公钥(root,密钥登录)。 侧载不是 Agent:设备只连 PCS,由 PCS 解析主机根调度机;令牌看不到调度机地址与实例凭据。
图 2 · 逻辑视图 递归调度树、能力汇总与主机并入
主机 A · 根域 根调度机所在主机 · 可运行多个容器 根调度机 主机 A · 容器 · ROOT 任务队列 · 派发 · 租约 · 记账 看到的是整个联邦的总能力 ΣW 168 ↓ 下发任务 · ↑ 上报能力 叶构建机 W 24 Ubuntu 24.04 8 核 · 3.2 GHz 32G 内存 · 500G 磁盘 模型 / API 能力已折算 叶构建机 W 16 Ubuntu 22.04 4 核 · 2.8 GHz 16G 内存 · 200G 磁盘 模型 / API 能力已折算 结点调度机 S1 ΣW 68 下挂 2 叶构建机 + 1 结点 先在子树内按 ΣW 路由 再按 W 选择目标构建机 叶构建机 W 20 Ubuntu 22.04 16G / 200G 叶构建机 W 12 Ubuntu 24.04 8G / 120G 结点调度机 ΣW 36 S2 · 可继续 挂子节点 ⋯ 主机内可运行多个容器(构建机 / 调度机);主机本身直接充当角色时,只能二选一。 每台主机最多一个根调度机,它是该主机对内、对外的唯一入口。 主机 B · 并入 A SSH 远程主机 · 内部仍是独立根域 主机 B 的根调度机 ΣW 60 对内:仍是 B 的根调度机 对外:A 的结点调度机 内部派发链完全不变 叶构建机 W 32 Ubuntu 24.04 24G / 400G 叶构建机 W 28 Ubuntu 22.04 16G / 300G B 的 ΣW 通过「对外身份」上报给 A 的根。 并入 A · 对外降为结点调度机 工作能力值 W W = w1·核心数 + w2·主频 + w3·内存 + w4·存储 + w5·模型能力 + w6·API 能力 创建构建机时计算上报,权重归一化后得到可比较分值。 派发:任务难度 D ≤ 构建机 W,取余量最小者。 汇总:ΣW = Σ叶构建机 W + Σ子调度机 ΣW(递归)。 根调度机看到的 168,就是整个联邦的可用能力。 父 → 子:下发任务;子 → 父:上报能力 主机并入(联邦关系)
图 3 · 主机并入 同一棵子树,换个视角看:对外降级,对内不变
并入前 并入后 主机 A · 根域 根调度机 A ROOT 构建机 W 24 构建机 W 16 主机 B · 根域 根调度机 B ROOT 构建机 W 32 构建机 W 28 并入 主机 A · 根域 + B 子树 根调度机 A ROOT B 的根调度机 对外 = 结点 · ΣW 60 对内仍是 B 的根 构建机 W 32 构建机 W 28 B 的调度链不需要改动;只是把「根」这个身份对 A 降了一级。
图 4 · 跨调度机中继 只下推、不复制:状态与输出逐级镜像回父任务
根调度机 · 主机 A 任务第一次进入联邦 任务 T · QUEUED target: b-1(在并入主机 B 下) 本地没有目标实例 父任务留在本库,不复制 task_relays · ACTIVE 领取候选排除父任务 两边不会同时执行 周期拉取子任务:状态 / 摘要 / 输出镜像回父任务 取消父任务 → 向子任务转发取消 工作流子任务不中继,状态机留在同一个库 POST /v1/tasks · relay parent_task_id · depth+1 结点调度机 · 主机 B 对外是 A 的结点,对内仍是 B 的根 子任务 T' · 去重建单 relay_parent_task_id = T 重复投递不会建出第二条 本机没有就继续往下推 叶构建机 b-1 W ≥ D · 领取并执行 stdout / stderr → 子任务结果 子任务状态、摘要、输出回传给父任务 父任务最终拿到执行方的 stdout / stderr 最大深度 8;接不住就留在原调度机排队 中继语义 1. 带目标实例:本机有该实例就留本机;否则在直接子结点名册里找,逐跳下推。 2. 不带目标实例:本机有在线且 W ≥ D 的构建机就留本机;否则按容量挑子结点。 D > 0:优先 max_builder_score 刚好够用的(升序)。 D = 0:优先更闲的子结点(idle_builder_count 降序)。 3. 只下推、不复制:父任务保持 QUEUED,领取候选排除。 4. 去重:子任务用 relay_parent_task_id 唯一约束,重复投递不会建第二条。 5. 镜像:周期拉取子任务状态与输出;多级中继取嵌套的 child_result。 6. 取消:父任务取消 → 子任务 POST /v1/tasks/:id/cancel,再往下转发。 7. 深度上限 8;子树整体接不住时,任务留在原调度机排队。 8. 子结点不可达只累计 sync_failures,不重复执行。 结点上报同时带容量指标,根据此决定往哪个子结点下推。

1控制面

PCS 只写期望态与签名命令,不直接调用 Docker;容器生命周期由主机上的 host-runtime 执行。私钥只用于探测与一次性引导。

2递归

根调度机下可以挂叶构建机,也可以挂结点调度机;结点调度机再挂构建机和调度机,如此递归,层级不设上限。每台调度机各自一套库。

3工作能力值 W

W = round(1000 × Σ(权重 × min(值, 上限) / 上限)):CPU 30%(8 核)、频率 15%(4 GHz)、内存 20%(32 GB)、存储 10%(256 GB)、模型 15%(10)、API 10%(10)。调度机不参与 W,固定 0。

4按难度派发

任务带难度 D(0–1000,0 = 不限)。调度机只把任务交给 W ≥ D 的构建机,并优先选余量最小的,避免大机器被小任务占住。

5逐级汇总

结点调度机把名下构建机的 W 与子调度机的 ΣW 相加后上报,直到根调度机。根看到的 ΣW 就是整个联邦的总能力。

6主机并入

pcs_hosts.parent_host_id 一行引用即完成并入;不能并入自己或自己的下级,双方都必须已有根调度机。合并与脱离只改运行时上级,不重启容器。

7跨调度机中继

只下推、不复制:父任务留在原库保持 QUEUED,子任务用 relay_parent_task_id 唯一约束去重;状态与输出镜像回来,取消向下转发,深度上限 8。

8角色规则

主机角色取 containers / builder / scheduler;同一台主机不能同时是构建机和调度机。容器模式下每台主机有且仅有一台根调度机,可再加任意多台结点调度机。

9管理视图

构建机、调度机、对话、终端都按主机子树取数:本机与并入主机分组折叠,组头显示主机名与数量,折叠状态记在本机;只有一台主机时不折叠。

10Agent / API 档案

Agent Profile 与 API Profile 由控制面维护:角色到 Agent 的绑定在 role_agent_bindings,到 API 的绑定在 role_api_bindings,都按主机生效。调度机与构建机部署时只拿到引用,调度机不解析档案内容,也不接触密钥。

11Secret Store

API 密钥不落平台库:档案里只存 secret://<path> 引用,值写入独立的 Secret Store(文件 0600),PCS 不回显、不记日志;容器实例用 Secret Store 实例 JWT 解析引用。

12调度 Agent 与 MCP

派发仍由确定性调度循环完成;调度 Agent 只解释队列、租约与「为什么这条在等」。它通过调度机本地 MCP 服务 builders 调用 list_builders、builder_exec、builder_ask、task_status 查看或操作构建机,不进入任务派发路径。

13侧载令牌

侧载是绑定到单台主机的 curl 令牌,不是 Agent:设备 → PCS → 主机根调度机,复用同一套任务、租约与 fencing 路径。权限是封闭集合(tasks:read、tasks:write、builders:read、queue:read、console:run);平台只存 SHA-256 哈希与末四位。

14文件收发

附件经 POST /attachments 上传(单个 24 MiB),命令执行前落到 <workspace>/attachments/。任务用 requirements.console.collect 收集工作区(32 个路径 / 128 个文件,单文件 64 MiB、合计 256 MiB),逐字节进入产物通道并重算 SHA-256;下载同样是原始字节。

15信任边界

明文令牌只展示一次;删除或到期在下一次请求即生效。在线状态最多 30 秒写一次,界面 120 秒内算在线。侧载能看到的构建机就是主机根调度机的子树,也正是任务实际能跑的范围。