myxce/docs/Scheduler-Agent-设计文档.md
Lei Chen 2e299f4a76 docs: add Unified Scheduler Agent Framework design document
Complete design spec for the natural-language scheduler agent:
- Layered architecture (UI/LLM/Agent core/Adapter/Scheduler)
- Unified Resource Model (URM) types and principles
- SchedulerAdapter interface + per-backend strategy
- Language selection strategy (Go primary)
- MCP protocol tool set (read/write/advanced)
- Security model (write-protected by default, API Key auth)
- Event stream design with current-state research
- Implementation roadmap Phase 0-4
- Testing strategy with golden tests
- Design principles + ADR decision records
- Current progress status and blockers

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-01 12:18:39 +08:00

26 KiB
Raw Blame History

Unified Scheduler Agent Framework — 设计文档

项目代号:scheduler-agent 文档版本:v1.0 最近更新:2026-08-01 文档状态:实施中(Phase 0 完成,待集群验证)


1. 文档目的

本文档定义"自然语言调度器管理 Agent 框架"的完整设计——一套架构同时适配自研调度器、LSF、Slurm、Kubernetes,让用户通过自然语言完成集群管理操作。

本文档是设计权威来源(source of truth),实施进度、架构变更、决策记录均在此维护。


2. 背景与项目定位

2.1 为什么做

HPC 集群(调度器)的使用者——研究员、运维——操作门槛高。bjobs/squeue/bsub 等命令行语法复杂,跨系统(LSF/Slurm/K8s)命令不互通。AI Agent 可以将这些操作抽象为自然语言。

2.2 核心定位

我们是调度器开发者,不是壳。

与 iris-mcp、srunx 等项目的结构性差异:

对比维度 其他项目 本项目
交互方式 CLI 文本解析 内核级嵌入 Agent 原生接口
事件能力 无,只能轮询 实时事件流(自研独有)
授权粒度 粗粒度 细粒度 RBAC
API 能力 受限 高级 API 原生支持

2.3 目标用户

  • 研究员:提交作业、查状态、诊断失败原因,用自然语言
  • 运维:集群监控、资源管理、问题排查,用自然语言

2.4 市场叙事

  • Phase 0-2:自研调度器体验碾压 LSF/Slurm(实时 + 自然语言)
  • Phase 3-4:"Any cluster, natural language"

3. 总体架构

3.1 分层架构图

┌─────────────────────────────────────────────────────────────────┐
│ Layer 0 · 用户界面层                                             │
│   🧑 用户 ──→ 💻 CLI (Claude Code)                               │
│              → 🌐 Web Chat (自建 Chat UI)                        │
│              → 🔌 IDE Plugin (Cursor / VS Code)                  │
└─────────────────────────────────────────────────────────────────┘
                              │ 自然语言
┌─────────────────────────────────────────────────────────────────┐
│ Layer 1 · 推理规划层                                             │
│   🧠 Orchestrator LLM                                           │
│      意图识别 → 规划 → 工具调用 → 纠错                          │
│      (Claude / GPT / 本地模型)                                   │
└─────────────────────────────────────────────────────────────────┘
                              │ Tool Call (JSON-RPC)
┌─────────────────────────────────────────────────────────────────┐
│ Layer 2 · Agent 核心层                                           │
│   🔌 MCP 协议 (stdio/SSH/HTTP)                                   │
│   ⚙️ 核心引擎 (Tool 路由 · Session · 多后端调度)                │
│   📦 统一资源模型 URM (Job/Queue/Node)                           │
│   🔐 鉴权 + 审计 (RBAC · 审计日志)                              │
│   📋 Session 上下文管理                                          │
└─────────────────────────────────────────────────────────────────┘
                              │ Adapter 接口
┌─────────────────────────────────────────────────────────────────┐
│ Layer 3 · 后端适配器层                                           │
│   🏆 Native Adapter (自研调度器) ★ 实时事件流                   │
│   📟 LSF Adapter (CLI/Python SDK)                               │
│   📡 Slurm Adapter (REST API/CLI)                                │
│   ☸️ K8s Adapter (client-go/Watch)                               │
└─────────────────────────────────────────────────────────────────┘
                              │
┌─────────────────────────────────────────────────────────────────┐
│ Layer 4 · 调度器层                                               │
│   🚀 自研调度器 (事件总线 · RBAC · 高级 API)                    │
│   📡 LSF 集群 (9.x/10.x) · 📡 Slurm 集群 (23.x+)                │
│   ☸️ Kubernetes (1.28+)                                         │
└─────────────────────────────────────────────────────────────────┘

3.2 数据流

用户自然语言 → LLM → MCP Tool Call → Agent 核心 → Adapter → 调度器
                                                          ↑
                                       事件流实时回传(自研独有)

4. 核心设计

4.1 统一资源模型(URM)

每个调度器的概念不同。URM 提供通用抽象,同时通过 extensions 暴露后端专有能力。

4.1.1 核心类型

type URMJob struct {
    ID              string            `json:"id"`
    Name            string            `json:"name"`
    Status          JobStatus         `json:"status"`   // pending | running | succeeded | failed | cancelled | suspended | unknown
    RawStatus       string            `json:"raw_status"` // 原始状态(PEND / RUNNING / Suspended)
    Queue           string            `json:"queue"`      // 队列 / partition / namespace
    Nodes           int               `json:"nodes"`
    Cores           int               `json:"cores"`
    GPUs            int               `json:"gpus"`
    MemoryBytes     int64             `json:"memory_bytes"`
    WalltimeSeconds int               `json:"walltime_seconds"`
    Dependencies    []JobRef          `json:"dependencies"`
    SubmissionTime  time.Time         `json:"submission_time"`
    StartTime       *time.Time        `json:"start_time,omitempty"`
    ExitCode        *int              `json:"exit_code,omitempty"`
    Owner           string            `json:"owner"`
    LogsURL         string            `json:"logs_url,omitempty"`
    Extensions      map[string]any    `json:"extensions,omitempty"` // 后端专有能力
}

type URMQueue struct {
    Name                 string        `json:"name"`
    Status               string        `json:"status"` // active | inactive | draining
    NodeCount            int           `json:"node_count"`
    RunningJobs          int           `json:"running_jobs"`
    PendingJobs          int           `json:"pending_jobs"`
    MaxWalltimeSeconds   int           `json:"max_walltime_seconds"`
    DefaultResources     *ResourceSpec `json:"default_resources,omitempty"`
    Extensions           map[string]any `json:"extensions,omitempty"`
}

type URMNode struct {
    Name              string   `json:"name"`
    Status            string   `json:"status"` // idle | busy | down | drain | unknown
    CoresTotal        int      `json:"cores_total"`
    CoresUsed         int      `json:"cores_used"`
    MemoryBytesTotal  int64    `json:"memory_bytes_total"`
    MemoryBytesUsed   int64    `json:"memory_bytes_used"`
    GPUCount          int      `json:"gpu_count"`
    Features          []string `json:"features"`
    Extensions        map[string]any `json:"extensions,omitempty"`
}

4.1.2 设计原则

  • 核心字段 = 所有调度器都有,LLM 使用同一套 prompt 理解
  • 扩展字段 = Extensions map 兜底后端专有能力(fairshare / GRES / tolerations)
  • 能力文档动态注入 = LLM prompt 中动态注入当前后端的能力文档

4.2 后端适配器层

4.2.1 SchedulerAdapter 接口

type SchedulerAdapter interface {
    // ── 读操作 ──
    ListJobs(ctx context.Context, filter JobFilter) ([]*URMJob, error)
    GetJob(ctx context.Context, id string) (*URMJob, error)
    ListQueues(ctx context.Context) ([]*URMQueue, error)
    ListNodes(ctx context.Context) ([]*URMNode, error)
    GetMetrics(ctx context.Context) (*Metrics, error)
    GetJobLogs(ctx context.Context, id string, opts LogOpts) ([]string, error)

    // ── 写操作 ──
    SubmitJob(ctx context.Context, spec *JobSpec) (*URMJob, error)
    CancelJob(ctx context.Context, id string) (*CancelResult, error)
    HoldJob(ctx context.Context, id string) error
    ReleaseJob(ctx context.Context, id string) error
    ModifyJob(ctx context.Context, id string, changes *JobModification) (*URMJob, error)

    // ── 高级(可选实现) ──
    CreateReservation(ctx context.Context, spec *ReservationSpec) (*Reservation, error)
    AnalyzeFailure(ctx context.Context, jobID string) (*FailureAnalysis, error)

    // ── 事件流 ──
    WatchJobs(ctx context.Context, filter EventFilter) (<-chan JobEvent, error)
}

4.2.2 各后端实现策略

后端 适配器语言 实现方式 事件流
自研调度器 Go 调用 apiserver REST API(cgo 桥接 C backend) ✅ 原生实时事件推送
LSF Go + Python sidecar Phase 0-1: bjobs/bsub CLI 解析;Phase 2+: Python SDK ⚠️ 轮询
Slurm Go Phase 0-1: squeue/sbatch CLI 解析;Phase 2+: slurmrestd ⚠️ 轮询
Kubernetes Go client-go 直接调用 K8s API Server ✅ Informer/Watch

⚠️ 已修正(2026-07-26):myxce 调度内核是 C(Cap'n Proto + Raft HA),Go 只存在于 apiserver(cgo 桥接 libxce)和 xcecli。因此 Native Adapter 的实现路径是 mcp-server 调用 apiserver 现成 REST API,而非进程内 import Go package。

4.3 语言选择策略

主体语言:Go。

  1. 自研调度器是 Go 栈——Adapter 可 import 内部 client 包(性能最优)
  2. 单二进制分发——ssh 到 login node 不需要装运行时
  3. os/exec + stdout 解析天然适配 CLI-based adapter(LSF/Slurm)
  4. 并发/事件流——goroutine + channel 完美适配 WatchJobs

分阶段语言演进:

Phase 0-1:  纯 Go (MCP Server + 所有 adapter)
                ↓ 当需要 LSF C 库 / Python SDK 深度集成时
Phase 2+:   Go 主体 + LSF 侧 Python Sidecar(UDS/gRPC 通信)

4.4 MCP 协议接口(对外暴露的工具集)

通过 MCP Server 暴露给 Claude Code、Cursor 等 MCP 客户端,或自建的 Chat UI。

4.4.1 读工具

Tool 说明
scheduler_list_jobs(filter) 列出作业,支持按状态/队列/owner 过滤
scheduler_get_job(id) 获取作业详情
scheduler_list_queues() 列出队列及容量、运行/排队数
scheduler_list_nodes() 列出节点及资源使用情况
scheduler_job_logs(id, tail?, since?) 获取作业输出日志
scheduler_cluster_metrics() 集群整体负载、使用率概览

4.4.2 写工具(默认 require confirm)

Tool 说明
scheduler_submit(job_spec) 提交作业,使用格式化参数或模板名称
scheduler_cancel(id) 取消作业
scheduler_hold(id) 暂停止作业
scheduler_release(id) 恢复暂停的作业
scheduler_modify(id, changes) 修改运行中作业的参数

4.4.3 高级工具

Tool 说明
scheduler_analyze_failure(id) 自动诊断作业失败原因(日志分析 + 退出码 + 资源分析)
scheduler_suggest_resources(description) 根据自然语言任务描述推荐资源配置
scheduler_estimate_wait_time(queue_spec) 估算排队时间

4.5 安全模型

这是作为调度器厂商最重要的护城河。Agent 的错误操作会直接侵蚀对产品的信任。

4.5.1 安全链路

┌──────┐    ┌──────┐    ┌───────────┐    ┌────────────┐    ┌─────────┐
│ 用户  │ →  │ LLM  │ →  │ Agent 层  │ →  │ Audit Proxy│ →  │ 调度器  │
└──────┘    └──────┘    └───────────┘    └────────────┘    └─────────┘
                               ↑               │
                               │               └→ 审计日志
                               └── 写操作 require confirm
                                   Autopilot 需用户显式启用

4.5.2 安全原则

  1. 所有写操作默认 require confirm:LLM 生成命令/参数,展示给用户确认后再执行
  2. Autopilot 模式:用户通过 --autopilot 显式启用后,Agent 可在授权范围内自主执行
  3. 完整审计日志:每条 AI 操作记录 [timestamp] [user] [action] [params] [confirmed?]
  4. 拒绝不安全操作:直接修改调度器配置、操作他人作业(无授权时)、sudo/root 操作
  5. 操作范围绑定:用户可通过 prompt 限定 Agent 作用域("只操作我的作业" / "只在这个队列")

4.5.3 凭证模型

  • mcp-server 用服务账号 API Key(xce_ak_ 前缀)调用 apiserver,而非透传终端用户 JWT
  • API Key 不做 IP 绑定(面向长期运行的自动化客户端,源 IP 不稳定)
  • Phase 0 用 mcp_readonly 角色(仅 :view 权限)
  • 写操作阶段引入 mcp_operator 等带写权限的角色

4.6 事件流设计

4.6.1 当前调研结论(2026-07-30)

XCE 产品目前零对外实时推送实现。 所有客户端通信均为 100% 请求/响应模式。

已有(进程内):

  • C Controller → NotificationHandler(OnJobCreated/OnJobUpdated/OnJobFinished...)→ DefaultHandler → 写入内存 DataStore
  • 事件到进程就停了,没有对外通道

确认没有的:

  • SSE endpoint、WebSocket、gRPC streaming、长轮询、Subscribe/Watch API、Pub/Sub 均不存在
  • Gin 已带 github.com/gin-contrib/sse(间接依赖),无需额外引入

4.6.2 设计方向

在 apiserver 侧加 SSE endpoint + EventBroker,把 DefaultHandler 收到的事件同时广播给订阅者。

C Controller ──OPCode_push──→ apiserver ──SSE──→ mcp-server / 浏览器
                               NotificationHandler
                               ↓ 仅需在 handler 加一行
                                  broker.Publish(event)

4.6.3 工作量估算

任务 工作量 位置
apiserver 加 SSE endpoint + EventBroker 1 天 controllers/events.go(新建)
NotificationHandler → Broker 转发 0.5 天 handler.go 加 publish
RBAC event:subscribe 权限 0.5 天 config/rbac.yaml + middleware
schedulerclient 加 WatchJobs() 0.5 天 httpclient.go SSE 解析
mcp-server 集成 0.5 天 Agent 工作流:提交→监控→自动处理

总计 2-3 天。 决策:Phase 1 走通写操作后再接入。


5. 实施路线图

5.1 Phase 0 — 只读 MCP Server(✅ 已完成代码,待集群验证)

  • 实现自研调度器的只读 adapter(ListJobs / GetJob / ListQueues / ListNodes / GetJobLogs)
  • 暴露 6 个 MCP 读工具
  • 验证:自然语言问"我的作业状态"、"队列里有什么"

输入:schedulerclient Go package(只读接口) 输出:可运行的 MCP Server,连接 Claude Code 后可以用自然语言查集群状态

5.2 Phase 1 — 作业提交 + 模板(+2 天)

  • Submit / Cancel / Hold / Release / Modify 写操作工具
  • 覆盖团队最常用的 3-5 种作业模板
  • 严格的参数校验 + --review 模式(先展示命令再执行)
  • 安全性审查

5.3 Phase 2 — 监控 + 纠错 loop(+1 周)

  • Agent 工作流:提交 → WatchJobs 接收事件 → 发现失败 → 分析日志 → 建议修复
  • 自研调度器的实时事件流是核心差异点:作业状态变化时 adapter 直接推送事件,LLM 自动触发处理
  • 与 LSF/Slurm 适配器的"轮询"模式形成体验代差

5.4 Phase 3 — LSF 适配器(+1 月)

  • LSF adapter:先用 CLI 解析(bjobs -o "id stat queue slots" -noheader),需要时加 Python Sidecar
  • 目标:LSF 用户迁移到自研调度器时体验零摩擦

5.5 Phase 4 — Slurm + K8s 适配器(+1 月)

  • Slurm adapter:slurmrestd REST API + CLI 回退
  • K8s adapter:client-go
  • 市场叙事:"Any cluster, natural language"

6. 代码仓库结构

6.1 目标结构(scheduler-agent 全量)

scheduler-agent/
├── cmd/
│   └── mcp-server/            # MCP Server 入口
├── internal/
│   ├── server/                # MCP Server 核心
│   │   ├── server.go          # JSON-RPC 处理
│   │   ├── tools.go           # Tool 定义注册
│   │   └── session.go         # Agent session 状态管理
│   ├── urm/                   # 统一资源模型
│   │   ├── job.go
│   │   ├── queue.go
│   │   └── node.go
│   └── adapters/              # 后端适配器
│       ├── native/            # 自研调度器
│       │   └── adapter.go
│       ├── lsf/               # LSF
│       │   ├── adapter.go
│       │   └── parser.go      # CLI 输出解析
│       ├── slurm/             # Slurm
│       │   ├── adapter.go
│       │   └── parser.go
│       └── k8s/               # Kubernetes
│           └── adapter.go
├── test/
│   └── golden/                # Golden test

6.2 当前落地位置(myxce 仓库内)

myxce/src/frontend/
├── apiserver/                 # Go REST API server(cgo 桥接 C backend)
├── xcecli/                    # Go CLI 工具
├── schedulerclient/           # ← Phase 0 ✅ scheduler-agent 只读 Go client
│   ├── client.go              #   Client interface
│   ├── types.go               #   URMJob / URMQueue / URMNode
│   ├── statusmap.go           #   状态映射(含单测)
│   └── httpclient.go          #   resty HTTP 实现
└── mcp-server/                # ← Phase 0 ✅ MCP Server 二进制
    ├── cmd/main.go            #   入口,注册 6 个 MCP Tool,启动 stdio server
    └── internal/app.go        #   Tool handlers 连接 schedulerclient

7. 测试策略

测试是商业化的真正护城河。模型不重要,验证套件才重要。

7.1 测试分层

test/
├── backends/
│   ├── native/      # 自研调度器 mock
│   ├── lsf/         # 需要 LSF 测试集群
│   ├── slurm/       # 需要 Slurm 测试集群
│   └── k8s/         # kind/minikube
├── scenarios/
│   ├── simple_submit.yaml        # "帮我跑这个脚本"
│   ├── job_dependency.yaml       # "按 A→B→C 顺序提交"
│   ├── job_array.yaml            # "做 100 个参数的扫描"
│   ├── failure_diagnosis.yaml    # "为什么失败了"
│   ├── multi_step_pipeline.yaml  # "提交→监控→分析→重试"
│   └── cross_platform.yaml       # 同场景在不同后端的表现对比
├── golden/
│   └── expected_tool_calls/      # 每个 scenario 期望的 tool call 链
└── integration/
    └── agent_e2e_test.go         # 端到端:自然语言输入 → 验收结果

7.2 Golden Test 回归

每次 adapter 改动用 golden test 回归——同样的自然语言输入,产生同样的 tool call 序列。


8. 设计原则

8.1 Narrow First(先窄后宽)

先吃透自研调度器,再扩展。自研调度器适配器的体验必须显著优于第三方适配器,形成竞争壁垒。

8.2 功能 vs 兼容的取舍

URM 不做最小公分母。核心字段通用,扩展字段用 extensions 兜底。LLM prompt 动态注入后端能力文档。

  • 通用能力:所有后端一致
  • 专有能力:extensions 暴露,模型自动识别是否可用

8.3 Write-Protected by Default

所有写操作默认 require confirm。Audit Log 是产品的一等公民,不是后加的功能。

8.4 LLM 是路由器,不是执行器

LLM 负责意图识别、规划、纠错。调度器交互由 adapter 的确定性代码执行。

  • 调度器升级只需更新 adapter,不需调优模型
  • 错误路径清晰:LLM 幻觉不会传递到调度器操作层

8.5 渐进的上下文窗口管理

Agent loop 跨多轮调度器轮次保持上下文:

  • 作业 <= 60s:一步到位(提交→等待→返回)
  • 作业 > 60s:事件流异步通知,状态持久化,Agent 通过 GetJob() 恢复
  • 上下文满:auto-compact 历史轮次,保留最新状态摘要

9. 决策记录(ADR)

9.1 ADR-001:mcp-server 用服务账号 API Key 鉴权(已确认)

  • 状态:✅ 已实施(2026-07-26)
  • 决策:mcp-server 用服务账号 API Key(xce_ak_ 前缀)调用 apiserver,而非透传终端用户 JWT
  • 理由:API Key 面向长期运行的自动化客户端,源 IP 不一定稳定,不做 IP 绑定
  • 实现:store/apikey.go + models/apikey.go + controllers/auth.go + middleware/validatehandler.go + router/routers.go + config/rbac.yaml

9.2 ADR-002:schedulerclient 放在 myxce 仓库内(已确认)

  • 状态:✅ 已实施
  • 决策:代码放在 myxce/ 仓库内新增目录(与 apiserver/xcecli 同级),不另起独立仓库

9.3 ADR-003:Native Adapter 走 apiserver REST API(已确认)

  • 状态:✅ 已确认(2026-07-26)
  • 决策:mcp-server 调用 apiserver 现成 REST API,不是进程内 import Go package
  • 理由:myxce 调度内核是 C,Go 只存在于 apiserver(cgo 桥接)和 xcecli。直接 cgo 链接 libxce 绕开 apiserver 复杂度接近重写一次 apiserver

9.4 ADR-004:事件流对外通道用 SSE(待实施)

  • 状态:🕐 设计完成,Phase 1 后实施
  • 决策:apiserver 加 SSE endpoint + EventBroker,复用已有 NotificationHandler 进程内事件

10. 当前进度状态(2026-08-01)

10.1 已完成

任务 内容 状态
Task #1 架构与设计文档 ✅
Task #2 API Key 鉴权机制(TDD) ✅ 全绿
Task #3 schedulerclient 只读客户端 ✅ 33 单测
Task #4 mcp-server MCP 二进制 ✅ 构建通过

Phase 0 完整链路(代码层面就绪):

用户自然语言 → Claude Code → MCP stdio → mcp-server → schedulerclient → apiserver REST API → 调度器

10.2 待办(阻塞项)

# 阻塞项 状态 责任方
1 运行中的 apiserver + C 编译环境 🚫 阻塞 用户准备集群
2 生成 API Key(mcp_readonly 角色) 🚫 依赖 #1 用户/管理员
3 配置 Claude Code MCP ✅ 拿到 key 后 1 分钟 用户

10.3 未决决策项

  • 事件流接口(SubscribeJobEvents)对外通道设计 —— 已验证前提成立,待 Phase 2 实施
  • LLM 选型:Claude API / 自部署本地模型 / 混合策略
  • 多集群场景:URM 如何标识作业来源(集群 ID 字段)
  • on-prem vs cloud:客户私有化部署时能否访问 LLM API

11. 风险与缓解

风险 影响 缓解
LLM 幻觉导致错误操作 作业丢失/资源浪费 写操作 require confirm;LLM 只做路由不做执行
自研调度器事件流未打通 Phase 2 体验差 已确认进程内事件存在,SSE 通道工作量 2-3 天
LSF/Slurm 轮询延迟 体验代差 通过 agent 工作流 + 模板缓解
上下文窗口膨胀 长任务监控失效 auto-compact + 状态摘要策略

12. 附录

12.1 相关文档索引

文档 位置 说明
本文档 doc/Scheduler-Agent-设计文档.md 设计权威来源
CLAUDE.md(根目录) CLAUDE.md AI 实施向导(含最新进度)
架构图源文件 architecture_overview Graphviz DOT
架构图渲染 architecture_overview.svg 可视化架构图
架构图生成脚本 generate_diagram.py diagrams 库
myxce 产品文档 myxce/.kiro/steering/ 产品/技术/结构/安全等
feature 规格 myxce/.kiro/specs/ 各功能 spec

12.2 关键实现细节备忘

  • 认证:apiserver 的 GetUsernameFromToken/isValidToken 已支持 xce_ak_ 前缀,JWT 和 API Key 透明共存(27 处调用点零改动)
  • schedulerclient 内存单位:假设 apiserver 返回 MB(HPC 惯例),转 bytes 存入 URM
  • schedulerclient 认证:Authorization header 直接传 token(不拼 Bearer,服务端会 TrimPrefix)
  • mcp-server 依赖:github.com/mark3labs/mcp-go@v0.57.0,replace schedulerclient => ../schedulerclient