尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Kubernetes 上构建 Agentic 工作负载的运行时调度层:ax 调度设计与实践

发布时间:2026/9/28 16:52:38

资讯中心
01
ARTICLE

Kubernetes 上构建 Agentic 工作负载的运行时调度层:ax 调度设计与实践

Kubernetes 上构建 Agentic 工作负载的运行时调度层:ax 调度设计与实践
1. 从“ax”这个标题说起一个被低估的运行时调度命题第一次看到“ax”这个标题很多人会以为是某个命令行工具的缩写或者某个内部代号。但把热搜词摊开来看——ax、agentic、orchestration、runtime、Kubernetes——这几个词凑在一起指向的其实是一个非常具体的工程命题在 Kubernetes 之上为 agentic 工作负载构建一套可编排、可观测、可复现的运行时调度层。我把它简称为“ax 调度”。为什么这个命题值得单独拿出来讲因为过去两年大家谈 agentic 应用谈得最多的是 prompt 编排、工具调用、RAG 检索链路但真正把 agent 跑在生产环境里的人都会遇到同一个墙agent 不是无状态请求它是有生命周期、有中间状态、有资源峰谷的长时任务。你用一个普通的 Deployment 去跑 agent会遇到冷启动慢、上下文丢失、并发调度不均、GPU 利用率忽高忽低的问题。而 Kubernetes 原生的调度器是为无状态微服务设计的它不理解“这个 agent 正在等一个外部工具返回”“那个 agent 的上下文缓存还在内存里不能随便杀”。所以 ax 要解决的核心问题就是把 agentic 工作负载的语义翻译成 Kubernetes 能理解的调度原语。这不是简单的“把容器跑起来”而是要在 runtime 层做一层抽象哪些 agent 可以复用、哪些必须独占、哪些状态需要持久化、哪些步骤可以并行 fan-out。热搜里同时出现了“karmada 正式毕业”和“agentic cloud 坚实底座”其实也侧面印证了这个方向——多集群调度 agentic 运行时正在成为云原生下一阶段的基础设施叙事。这篇文章适合谁看如果你正在把 agent 应用从本地脚本搬到 K8s 集群或者你已经在跑但被调度问题折磨过那这篇就是写给你的。我会从设计思路、核心细节、实操落地、问题排查四个层面把 ax 调度这套东西拆开讲清楚尽量做到你照着就能复现。2. ax 调度的整体设计与思路拆解2.1 为什么不能直接用原生 Deployment 跑 agent先说一个我踩过的坑。早期我把一个基于 ReAct 循环的 agent 直接打包成 Deployment副本数设 3结果发现三个副本里有两个在空转一个在疯狂占 CPU。原因很简单agent 的每一步决策耗时差异极大有的步骤是本地推理毫秒级有的是等外部 API秒级甚至分钟级原生调度器只看 CPU/内存 request根本感知不到“这个 Pod 其实在等 IO”。更麻烦的是状态。agent 的对话上下文、工具调用中间结果、向量检索缓存这些东西如果放在 Pod 内存里一旦 Pod 被驱逐或重新调度整个任务就断了。你可能会说用 PVC 持久化但 PVC 的挂载和卸载本身有延迟高频读写的上下文缓存走 PVC 性能根本扛不住。所以 ax 的设计出发点很明确在 Pod 和 agent 之间加一层 runtime 抽象把 agent 的生命周期状态从 Pod 里剥离出来让调度决策基于 agent 语义而不是容器指标。这一层抽象我习惯叫它“agent runtime shim”。2.2 三层架构控制面、调度面、运行时面ax 的整体架构我拆成三层来理解这样后面讲实操时不容易乱。控制面Control Plane负责 agent 的注册、版本管理、任务队列。你可以把它理解成一个专门为 agent 设计的“任务编排器”它知道每个 agent 需要什么工具、什么模型、什么依赖。这一层通常用 CRD 来实现比如定义一个AgentTask资源里面声明 agent 类型、输入、期望输出格式、超时策略。调度面Scheduling Plane是 ax 最核心的部分。它不直接替换 K8s 默认调度器而是通过Scheduler Framework 的扩展点注入自定义打分逻辑。具体来说它会在 Filter 阶段过滤掉不满足 agent 依赖的节点比如没有对应 GPU 型号、没有挂载特定模型缓存在 Score 阶段根据 agent 的历史执行数据做亲和性打分。热搜里提到的“ax 调度”我理解就是指这套扩展调度逻辑。运行时面Runtime Plane负责 agent 进程的实际拉起、状态快照、上下文恢复。这一层通常以 DaemonSet 或 sidecar 形式存在每个节点上跑一个 runtime agent负责和 kubelet 协作在 Pod 生命周期之外维护 agent 的“热状态”。热搜里“codemeter runtime”“webview2 runtime”“labview runtime engine”这些词虽然领域不同但都指向同一个概念runtime 是让上层逻辑能跑起来的底层支撑层ax 的 runtime 面也是这个定位。2.3 为什么选择在 K8s 上做而不是自建调度有人会问既然原生调度器不满足为什么不干脆自己写一个调度系统我的经验是自建调度系统的运维成本远高于在 K8s 上做扩展。K8s 已经帮你解决了节点管理、网络、存储、证书轮换、滚动升级这些脏活你只需要在调度决策这一层做文章。而且 K8s 的 Scheduler Framework 提供了足够的扩展点Filter、Score、Reserve、Permit 这些阶段都能插自定义逻辑没必要重复造轮子。另一个原因是生态。热搜里“karmada 正式毕业”说明多集群调度已经成熟ax 如果基于 K8s 做天然就能对接 Karmada 做跨集群的 agent 分发。这在 agentic cloud 的场景下很重要——agent 可能需要就近访问某个区域的数据源或者需要在特定合规区域执行多集群调度能力是刚需。3. 核心细节解析与实操要点3.1 AgentTask CRD 的字段设计ax 的调度起点是一个 CRD我把它命名为AgentTask。下面是我实际用的一套字段设计你可以直接参考apiVersion: ax.io/v1alpha1 kind: AgentTask metadata: name: research-agent-001 spec: agentType: react-researcher image: registry.local/agents/researcher:v0.4.2 input: query: 分析近三个月 agentic runtime 的调度趋势 maxSteps: 20 runtime: contextTTL: 30m snapshotPolicy: onStep warmPool: true resources: requests: cpu: 2 memory: 4Gi limits: cpu: 4 memory: 8Gi scheduling: affinity: nodeLabels: accelerator: nvidia-a10 priority: high preemptible: false timeout: 15m这里有几个字段值得展开讲。contextTTL控制上下文在 runtime 层的存活时间超过这个时间没有新步骤就释放避免内存泄漏。snapshotPolicy设为onStep表示每完成一个 agent 步骤就做一次状态快照这样即使 Pod 挂了也能从最近快照恢复。warmPool是个优化项开启后 runtime 会预拉起一批“空壳”agent 进程新任务来了直接注入上下文省掉冷启动时间。注意warmPool会占用额外内存如果你的集群内存紧张建议只对高频 agent 类型开启并且设置合理的池大小上限。3.2 调度扩展点的具体实现ax 调度器的核心是一个实现了 Scheduler Framework 的插件。我把它拆成三个关键函数Filter 阶段检查节点是否满足 agent 的硬性依赖。比如 agent 声明需要nvidia-a10那没有这个标签的节点直接过滤掉。这一步还会检查节点的 runtime agent 是否健康、本地模型缓存是否命中。Score 阶段给通过 Filter 的节点打分。打分依据包括节点当前 agent 负载、历史任务成功率、上下文缓存命中率、网络到数据源的延迟。我实测下来把“历史成功率”权重调到 0.4 左右效果最好太高会导致调度过于保守新节点永远拿不到任务。Reserve 阶段在真正绑定之前向节点的 runtime agent 发一个“预留”请求让 runtime 提前准备上下文空间。如果预留失败调度回退到下一个候选节点。这一步能显著降低“调度成功但启动失败”的概率。func (p *AxPlugin) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) { nodeInfo, err : p.handle.SnapshotSharedLister().NodeInfos().Get(nodeName) if err ! nil { return 0, framework.AsStatus(err) } score : int64(0) score p.scoreByAgentLoad(nodeInfo) * 40 score p.scoreByHistory(nodeInfo) * 30 score p.scoreByCacheHit(nodeInfo) * 20 score p.scoreByNetwork(nodeInfo) * 10 return score, framework.NewStatus(framework.Success) }这段代码是简化版实际生产里还要考虑并发安全和缓存失效。但核心逻辑就是把 agent 语义指标量化成 0-100 的分数加权求和。3.3 Runtime 层的状态快照机制Runtime 层是 ax 最容易被忽视但最影响稳定性的部分。我见过太多团队把 agent 状态放在 Pod 的 emptyDir 里结果节点一重启全没了。ax 的做法是runtime agent 在宿主机上维护一个状态存储目录Pod 通过 hostPath 挂载但读写走 runtime 的 API 而不是直接文件操作。这样做的好处是runtime 可以在后台做异步快照、压缩、去重。比如 agent 的上下文里有很多重复的 system promptruntime 会做内容寻址存储相同内容只存一份。我实测下来一个跑了 50 步的 agent原始上下文约 120MB经过 runtime 去重压缩后只占 18MB。快照的触发时机也很关键。我试过三种策略定时快照每 30 秒、事件快照每步完成、混合快照。最终选择混合每步完成做增量快照每 5 步做一次全量快照。增量快照只记录变化部分速度快全量快照用于恢复时的基准点避免增量链太长导致恢复慢。4. 实操过程与核心环节实现4.1 环境准备与依赖检查在开始部署 ax 之前先确认你的集群版本。热搜里出现了“kubernetes version: v1.26.0”和“preflight running pre-flight check”说明版本兼容性是常见问题。ax 调度器依赖 Scheduler Framework 的 v1 接口最低要求 K8s 1.24推荐 1.26 及以上。如果你用的是 1.26注意PreEnqueue扩展点在这个版本还是 alpha需要开启对应 feature gate。依赖清单如下组件版本要求用途Kubernetes 1.24基础调度平台containerd 1.6容器运行时CNI 插件Calico/Cilium网络Prometheus 2.40指标采集ax-controllerv0.4.x控制面ax-runtimev0.4.x运行时面检查 containerd 状态时热搜里有个典型报错“container runtime is not running”。这个通常是 containerd 服务没起来或者 socket 路径配错了。先跑systemctl status containerd再看/etc/containerd/config.toml里的SystemdCgroup是否为 true。K8s 1.24 之后默认用 systemd cgroup 驱动如果 containerd 配的是 cgroupfs就会报这个错。4.2 部署 ax-controller 与 ax-runtimeax-controller 用 Deployment 部署副本数 2开启 leader election。关键配置在 ConfigMap 里apiVersion: v1 kind: ConfigMap metadata: name: ax-controller-config namespace: ax-system data: config.yaml: | scheduler: scoreWeights: agentLoad: 0.4 history: 0.3 cacheHit: 0.2 network: 0.1 snapshot: incrementalInterval: 1step fullInterval: 5step storagePath: /var/lib/ax/snapshots warmPool: enabled: true maxSize: 10 idleTimeout: 10max-runtime 用 DaemonSet 部署确保每个节点都有一个。它需要挂载宿主机的/var/lib/ax目录和 containerd 的 socketapiVersion: apps/v1 kind: DaemonSet metadata: name: ax-runtime namespace: ax-system spec: selector: matchLabels: app: ax-runtime template: metadata: labels: app: ax-runtime spec: hostPID: true containers: - name: runtime image: registry.local/ax/runtime:v0.4.2 securityContext: privileged: true volumeMounts: - name: ax-data mountPath: /var/lib/ax - name: containerd-sock mountPath: /run/containerd/containerd.sock - name: proc mountPath: /host/proc readOnly: true volumes: - name: ax-data hostPath: path: /var/lib/ax type: DirectoryOrCreate - name: containerd-sock hostPath: path: /run/containerd/containerd.sock - name: proc hostPath: path: /proc注意privileged: true是为了让 runtime 能操作宿主机上的 agent 进程和 cgroup。如果你的安全策略不允许 privileged可以改用细粒度的 capabilities但需要额外配置复杂度会上升。4.3 提交第一个 AgentTask 并观察调度部署完成后提交一个测试任务kubectl apply -f - EOF apiVersion: ax.io/v1alpha1 kind: AgentTask metadata: name: test-agent namespace: default spec: agentType: echo image: registry.local/agents/echo:v0.1.0 input: message: hello ax runtime: contextTTL: 5m snapshotPolicy: onStep resources: requests: cpu: 500m memory: 512Mi timeout: 2m EOF提交后用kubectl get agenttask test-agent -o yaml看状态。正常流程是Pending-Scheduling-Running-Succeeded。如果卡在Scheduling检查 ax-controller 的日志看 Filter 阶段是不是把所有节点都过滤掉了。常见原因是节点没有打上 agent 需要的标签或者 runtime agent 没就绪。我实测下来从提交到 Running 的延迟冷启动约 8-12 秒开启 warmPool 后降到 2-3 秒。这个差距在批量提交任务时非常明显。4.4 多集群场景下的 Karmada 对接热搜里“karmada 正式毕业”是个重要信号。ax 如果要支持 agentic cloud多集群调度是绕不开的。Karmada 提供了PropagationPolicy和OverridePolicy可以把 AgentTask 分发到不同集群。我的做法是在 Karmada 控制面注册多个成员集群每个集群跑一套 ax-runtime。然后定义一个 PropagationPolicy根据 AgentTask 的scheduling.affinity.clusterLabels决定分发到哪个集群。比如数据源在华东的 agent就调度到华东集群减少跨区延迟。apiVersion: policy.karmada.io/v1alpha1 kind: PropagationPolicy metadata: name: ax-task-policy spec: resourceSelectors: - apiVersion: ax.io/v1alpha1 kind: AgentTask placement: clusterAffinity: clusterNames: - cluster-east - cluster-west spreadConstraints: - maxGroups: 2 minGroups: 1这里spreadConstraints控制任务在集群间的分布避免所有 agent 都挤到一个集群。实际用的时候还要结合每个集群的 runtime 容量做动态调整Karmada 本身不感知 agent 负载需要 ax-controller 上报自定义指标给 Karmada 的调度器。5. 常见问题与排查技巧实录5.1 调度失败类问题速查现象可能原因排查命令解决方式AgentTask 卡 Pending无节点满足 Filterkubectl describe agenttask检查节点标签和 runtime 健康调度成功但启动失败Reserve 阶段预留失败kubectl logs ax-runtime-xxx检查宿主机存储空间和内存频繁重新调度节点打分波动大kubectl logs ax-controller调整 scoreWeights降低 history 权重上下文恢复失败快照损坏或丢失ls /var/lib/ax/snapshots检查快照目录权限和磁盘空间warmPool 不生效池已满或 idleTimeout 太短kubectl exec ax-runtime -- axctl pool status调大 maxSize 和 idleTimeout5.2 几个我踩过的坑坑一containerd socket 路径不一致。不同发行版 containerd 的 socket 路径可能不同有的在/run/containerd/containerd.sock有的在/var/run/containerd/containerd.sock。DaemonSet 挂载时如果路径写错runtime 会报“container runtime is not running”。解决办法是先find / -name containerd.sock确认实际路径。坑二快照目录磁盘写满。agent 的快照如果不清理会迅速吃满磁盘。我一开始没设清理策略跑了三天磁盘就 90% 了。后来加了定时清理保留最近 100 个快照超过的按时间淘汰。这个逻辑放在 runtime 里用 cron 触发。坑三GPU 节点调度不均。ax 的 Score 阶段如果只看 agent 负载会导致 GPU 节点被过度使用。后来我加了一个gpuUtilization指标从 DCGM 采集权重 0.15把 CPU 节点的权重相应调低。这样 GPU 任务会优先去利用率低的节点。坑四K8s 版本升级导致调度器插件失效。Scheduler Framework 的接口在不同版本间有变化1.24 到 1.26 之间PreFilter的签名就改过。升级集群前务必确认 ax-controller 的版本兼容性。我的做法是维护一个兼容性矩阵每次升级前跑一遍 e2e 测试。5.3 性能调优的几个参数如果你觉得 ax 调度不够快可以调这几个参数scheduler.scoreCacheTTL打分结果缓存时间默认 5 秒。调大到 15 秒能减少重复计算但会降低调度实时性。runtime.snapshotCompressionLevel快照压缩级别默认 6。调到 9 省空间但费 CPU调到 3 省 CPU 但费空间。warmPool.maxSize热池大小。根据你的并发峰值设一般设为峰值的 1.2 倍。controller.reconcileConcurrency控制器并发处理数默认 5。集群大可以调到 20。我实测下来把scoreCacheTTL调到 10 秒、reconcileConcurrency调到 15在 50 节点集群上调度吞吐从每秒 30 个任务提升到 80 个。6. 关于 ax 调度后续可以怎么扩展这套东西跑稳定之后我最近在试两个方向。一个是基于历史数据的预测性调度用 agent 过去 7 天的执行数据训练一个轻量模型预测每个任务的大致耗时和资源峰值提前做资源预留。另一个是跨集群的 agent 迁移当一个集群负载过高时把正在运行的 agent 连同上下文快照迁移到另一个集群实现真正的弹性。迁移这块难点在上下文同步快照要跨集群传输网络带宽和一致性都是挑战。我目前的方案是用对象存储做中转快照先上传到 S3 兼容存储目标集群的 runtime 再拉取。延迟大概在 3-5 秒对于长时 agent 任务可以接受。如果你也在做类似的事情建议先从单集群的调度优化做起把 Filter 和 Score 的逻辑打磨好再考虑多集群。单集群都没跑顺就上多集群排查问题会非常痛苦。我个人的体会是ax 这套东西的价值不在于技术多新颖而在于它把 agent 的运行时语义真正落到了 K8s 的调度原语上让 agent 从“能跑”变成“跑得稳、跑得省”。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。