☰
Agent Substrate:在K8s之上为Agent补齐编排原语
2026/9/26 18:46:06 网站建设 项目流程

"Kubernetes 之父对谈 Agent Substrate:为什么要在 K8s 之上给 Agent 造一层新原语"这个话题,乍一看是个标准的云原生新闻标题,但拆开揉碎之后,你会发现它其实在问一个非常要命的问题:K8s 这套已经赢了十年的编排范式,是不是真的可以直接拿给 Agent 用?如果答案是不能,那缺的那一层到底该怎么造、由谁来造、造完之后长什么样。

我过去几年一直在做云原生基础设施相关的落地工作,最近半年又开始重度接触 Agent 类应用。站在这个交叉点上,我越来越认同一个判断:K8s 和 Agent 之间不是"能不能跑"的问题,而是"跑得好不好、协作得顺不顺"的问题。今天这篇文章,我想从一个普通基础设施从业者的视角,聊聊为什么 Agent 需要新的原语、K8s 到底给 Agent 留了哪些空,以及"Agent Substrate"这件事现在做到哪一步了。

1. 从容器调度到 Agent 协作:编排对象的一次历史转向

1.1 K8s 为什么会成为"云原生操作系统"

先回到根上。Kubernetes 之所以能成为今天所有云厂商的默认底座,不是因为它调度容器调度得多快,而是它重新定义了"运维接口"。在 K8s 之前,我们描述一个应用要写一堆启动脚本、健康检查、负载均衡配置、扩缩容策略;在 K8s 之后,你只需要写一个 YAML,声明"我要三个副本、每个副本监听 8080、内存上限 512Mi",剩下的交给控制面。

这个转变的本质,是把命令式操作变成了声明式期望。你告诉系统目标状态,系统自己想办法收敛到目标状态。Deployment 里的 replicas 字段就是最典型的例子,它不是一个"启动三个进程"的指令,而是一个"永远保持三个副本"的承诺。这个承诺由 ReplicaSet、Controller、etcd、kubelet 这一整套机制在背后背书。

这套机制厉害到什么程度?它把"运维"这种以前靠老师傅经验和人肉盯监控的活儿,变成了一门可以在任何云上复用的工程学科。所以后来大家说 K8s 是"云原生操作系统",一点也不夸张。

1.2 Agent 缺一个属于自己的控制平面

但问题来了。当我们开始认真把 Agent 当作生产级应用来部署时,你会发现这套"操作系统"并不完全适配 Agent 的生理结构。

传统的服务是无状态的,请求进来、处理、返回,进程本身不保留对话记忆,状态全部外置到数据库。所以 K8s 对传统服务的抽象非常精准——Pod 随时可以被杀掉重建,因为只要是"无状态",杀了也无所谓。

Agent 不一样。一个 Agent 实例背后挂着会话上下文、工具调用链路、多步推理的中间状态、甚至长期记忆库。今天很多团队跑 Agent 的方式,本质上是把它当成一个"有状态的长跑服务"硬塞进 K8s,然后用 Redis、Postgres、向量库在外面疯狂打补丁。

这就好比你想盖一座桥,却硬要用造独木舟的工具。不是工具不好,是对象完全不匹配。Agent 需要的不只是调度容器,而是调度"对话"、"记忆"和"协作关系"。这些东西在 K8s 的 API 对象里找不到对应物。

1.3 "原语"这个词到底指什么

聊到这儿,必须把"原语"(primitive)这个概念说清楚,不然很多人会以为这是一个装腔作势的学术词。

原语,简单理解就是"系统提供给你的、不可再拆解的基础构件"。K8s 里的 Pod、Service、Deployment、Ingress 都是原语。你不需要自己实现容器生命周期管理,因为 Pod 帮你做了;你不需要自己搞服务发现,因为 Service 帮你做了。原语的意义在于:把高频、复杂、容易出错的操作,封装成低层的、语义清晰的、人人可用的接口。

Agent Substrate 的核心主张,就是要在 K8s 之上,为 Agent 补充一组这样的原语。这些原语不再以"容器"为单位,而是以"任务(Task)"、"记忆(Memory)"、"工具(Tool)"、"代理(Agent)"为单位。说白了,就是把 Agent 世界里那些反复出现的模式,沉淀成像 Pod 一样人人都会用、人人都按同一个规范来实现的东西。

2. K8s 给 Agent 留了哪三个空?

2.1 身份与状态:Controller Loop 对 Agent 太僵化

先说最痛的一点:K8s 的自动化模型是"持续收敛",而 Agent 的工作模式是"临场发挥"。

K8s 的 Controller Loop 假设世界是这样的:资源有期望状态和实际状态,Controller 不断比较两者,有偏差就纠正。这套模型处理无状态 Web 应用堪称完美——流量大了给你加副本,Pod 死了给你重启,配置变了给你滚动更新。

但 Agent 呢?Agent 的工作流程是一个带有目标导向性和不确定性的过程。它可能需要在对话中途暂停,等用户确认某个操作再继续;可能需要调用十几个工具,每个工具的返回值都会改变它接下来的策略;它可能运行两个小时,也可能在第五步就发现目标不可达,需要换一条路径。

在这种情况下,"期望状态"是什么?"实际状态"又是啥?你没法用 replicas 字段描述一个正在多步推理的 Agent。如果你强行让 Controller 按 K8s 那套逻辑去管 Agent,只会有两种结果:要么 Agent 被频繁重启导致对话上下文丢失,要么你被迫把整个推理过程包在一个巨型 Pod 里、放弃弹性和可观测性。

这就是第一个空:Agent 缺一个能描述"有状态、长周期、过程可变"任务的运行时原语。

2.2 通信模型:Service 更像是寻址系统,不是对话系统

第二个空在通信层。K8s 的 Service 解决的是一个很经典的问题:客户端怎么稳定地找到一组 Pod?它通过 Label Selector 选出一组 Pod,再通过 kube-proxy 或 DNS 做负载均衡,本质上是一个静态寻址系统。

但 Agent 之间的通信,不是"Client -> Server"那么简单,而是"Agent A -> Agent B -> Agent C 的协作文档",有时是链式传递,有时是广播通知,有时还需要带上下文来回扯皮。这里面有两个 K8s 原生能力完全顾不上的诉求:

  • 动态拓扑:Agent 协作的网络结构不是固定的,经常是"先和数据分析 Agent 聊,再决定要不要调任务规划 Agent",这种关系由一个中心规划器动态生成。Service 的静态 selector 对这种"运行时才决定和谁说话"的场景毫无帮助。
  • 带记忆的会话:Agent 之间的一次对话是连续的、有上下文状态的。Service 只管把请求转给一个后端,它不保证"同一个会话始终由同一个 Agent 实例处理",也不保存任何中间语义状态。你完全可以在应用层自己做会话亲和(sticky session),但这对一个需要水平扩展、弹性伸缩的系统来说,只是在给基础设施擦屁股。

2.3 生命周期:Pod 和 Job 都假设任务是"有终点的"

第三个空是生命周期模型。K8s 提供的最长生命周期的对象是 Job / CronJob,但 Job 的语义是"执行完就结束"。Agent 的任务往往不是"执行完就结束",而是"执行到一个阶段后挂起,等外部事件继续"。

举个例子:一个采购 Agent 被指派"找一个价格低于 5000 块的 GPU 云服务器"。它查了十家云厂商,发现都没有满足条件的,于是它不应该"结束",而应该"等待"——等新机型上线,等某个降价通知,甚至等用户手动调整预算。这个等待可能持续几小时,也可能持续几天。

用 K8s 原生模型处理这种"挂起-唤醒"的任务非常别扭:你可以用一个 Pod 在那儿 sleep,但这是在浪费资源;你也可以把任务拆成多段、每段一个 Job,但中间状态怎么传、怎么管理、怎么重试,全得自己造轮子。

Agent Substrate 想补的,恰恰是这种"可暂停、可恢复、生命周期以业务目标为准"的任务原语。

3. Agent Substrate 在填的,其实是三层协作协议

聊完缺口,再来看 Agent Substrate 具体在做什么。我把它拆成三层来讲,这样你会发现它其实不是某个具体项目,而是一整套设计思路。

3.1 运行时层:Agent 进程谁启动、怎么盯着

最底层是运行时管理。Agent Substrate 不是要取代 K8s 的 Pod,而是要在 Pod 之上定义一个新的 Workload 类型,比如可以叫 AgentPod 或者 TaskRun。这种 Workload 的 CRD 大体长这样:

apiVersion: agent.run/v1alpha1 kind: Agent metadata: name: procurement-agent spec: model: provider: anthropic name: claude-sonnet-4 memory: maxTokens: 32000 storageClass: agent-mem tools: - name: cloud-vendor-api endpoint: http://cloud-vendor-service:8080 permissions: allowedActions: ["query", "compare", "notify"] lifecycle: suspendOnIdle: true resumeOn: ["schedule", "webhook"]

注意这里的变化:它声明的不是"镜像和副本数",而是Agent 的模型、记忆、工具权限、生命周期策略。Controller 创建出来的也不是一个裸 Pod,而是一个带持久化卷、带工具网关、带状态存储的复合执行单元。

这就是我理解的"运行时原语"——它把 Agent 的很多通用能力(模型接入、记忆挂载、工具调用权限)从代码里抽出来,放进声明式配置里。

3.2 记忆与状态层:把"上下文"和"复盘"做成持久化原语

第二层是记忆与状态。这是 Agent Substrate 和传统调度器差别最大的一层。

在 K8s 里,状态是外置的,数据库自己跑,Pod 不碰数据。但在 Agent 场景里,记忆就是 Agent 本身。一个没有记忆的 Agent 和一段无状态的 HTTP 接口没有任何区别。所以 Agent Substrate 里有一个类似于 PersistentVolumeClaim 的东西,但它申请的不是一块磁盘,而是一个"记忆会话"。

这个记忆会话的典型结构大概是:

conversation_id: uuid thread: - role: user content: "..." timestamp: ... - role: assistant content: "..." tool_calls: [...] timestamp: ... long_term: - topic: "cloud vendor pricing" summary: "as of 2025-Q3, vendor A is cheaper..." last_updated: ...

底层可以接向量库、Redis、或者普通 Postgres,但这不重要。重要的是——记忆被抽象成了平台级能力,而不是每个 Agent 自己额外搭一套的私活。以后你换掉底层记忆库,Agent 代码一行都不用改。

3.3 协作层:从 MCP/编排协议到"多 Agent 操作系统的内核"

第三层是协作。这一层目前是整个领域最活跃、也最混乱的部分。

一方面,大家已经在做标准化的尝试,比如 MCP(Model Context Protocol)就是把"Agent 如何调用工具"这件事标准化,OpenAI 后来推的 Agents SDK 又把"Agent 如何编排子任务"做了一层定义,LangGraph 则在更上层提供了状态图和条件分支的抽象。但在 Agent Substrate 的理念里,这些还不够——它们解决的是"Agent 与工具"和"Agent 与子任务"的协议问题,但"Agent 与 Agent"之间公共基础设施还几乎是空白。

一个多 Agent 系统里,A 要委托任务给 B,谁来负责任务路由?谁持有任务状态的全局视图?B 失败之后,工作流状态如何回滚?A 和 B 共用的记忆库如何避免脏读写?这就需要一个类似于分布式事务协调器 + 消息队列 + 状态机的复合组件,运行在每个 Agent Pod 的旁边,负责它们之间的协作。

在 Agent Substrate 的设计里,每个 Agent 被拉起时会同时拉起一个 Sidecar,这个 Sidecar 就是它的"协作接口":

  • 接收来自其他 Agent 的任务,写入本地队列;
  • 汇报自己的状态和进度到中心控制面;
  • 在任务失败时,向调度器申请重试或回滚。

你可能会说,这不就是把 Service Mesh 换了个马甲吗?有那味,但侧重点完全不同。Service Mesh 管的是流量,Agent Substrate 的协作层管的是语义和状态,它要理解"任务完成"和"任务失败"与"HTTP 200 和 500"之间的本质差异。流量层面的东西反而退居其次,因为 Agent 之间的对话,帧率不重要,语义一致性才重要。

4. 现在就想上车?实操侧的三种姿势与踩坑预判

理论聊再多,都得落到能不能上手。以目前(2025 年下半年)Agent 基础设施的成熟度,我总结出三条务实的接入路径,大家可以根据自己的处境选择。

4.1 姿势一:用 CRD 扩展已有 K8s 集群(最稳)

如果你团队里已经有一套 K8s,并且你不想把 Agent 的编排逻辑写死在业务代码里,我建议你从 CRD + Operator 模式开始。

用 Kubebuilder 或者 controller-runtime 定义一个你自己的 Agent CRD,字段可以比我上面写的例子更精简,先覆盖三个最高频的需求:任务生命周期管理、记忆持久化、工具调用审计。

写一个 Controller 去 watch 这个 CR 的变化,一旦有人创建了一个 Agent 自定义资源,你的 Controller 负责:

  1. 拉起对应的 Deployment/StatefulSet;
  2. 挂载记忆卷(可以先用一个 PVC 怼着);
  3. 注册到这个 Agent 的路由表里;
  4. 报告 READY 状态。

这一步的成本大概是一个中级工程师 1-2 周的工作量。但收益很大:你团队里所有 Agent 项目从此有统一的部署形态和运维面板,后续再加 Agent ,不再需要从零写编排逻辑。

我记得我第一次用 Kubebuilder 搭这类扩展时,最容易被绕进去的是Controller 的 Reconcile 逻辑设计:你要搞清楚,哪些状态变化需要触发 Reconcile,哪些不需要。如果你把每次记忆更新都当成一次 K8s 事件,etcd 会被写爆,Controller 会被活活累死。记忆同步应该走数据面,不走控制面——这是我从那个坑里爬出来之后最深刻的心得。

4.2 姿势二:把 Agent 编译成"次世代 Workload"跑在集群上

第二种姿势激进一点:把 Agent 的运行时直接容器化,但再加一层适配器,让它能原生地使用 K8s 平台的调度、伸缩、观测能力。

开源生态里已经有不少类似的尝试,比如 Dapr 的 Actors 模型、以及一些专门面向 AI 工作负载的运行时项目。Dapr 的思路很值得参考:你的 Agent 代码照写,但把状态管理、发布订阅、Actor 激活/停用这些能力,都通过 Sidecar 的 HTTP/gRPC API 暴露给业务代码。这样 K8s 依然负责最底层的容器调度,而 Agent 能享受到的平台能力比裸跑在 Pod 里多得多。

这种姿势的优点是渐进式:你的业务代码可以一点点从硬编码的状态管理迁移到 Sidecar API,不用推倒重来。缺点是 Sidecar 本身是个长期运行的 Pod,资源占用不低(内存普遍 200-500MB 起步),而且目前这些项目大多还在快速迭代,API 说变就变,一不留神就得跟着升级做兼容。

4.3 姿势三:直接采用某个 Agent Substrate 项目(最快但不一定最对)

第三种就是直接押注某个宣称要做 "Agent 基础设施" 的平台或开源项目,比如一两年前洛林·张(Lorin Zhang)在 KubeCon 上演示过的一些 Agent 编排原型,以及目前各类做 Agent Gateway、Agent Runtime 的创业项目。

我的态度是:可以密切关注,但生产环境先别急着踩坑。原因很简单,这个领域目前连"Agent 的部署单元是什么"都还没完全统一。你今天部署的平台,可能半年后就改架构了。如果你只是一个普通业务团队,你不太适合当小白鼠。

我个人的建议是,把姿势二作为主要路径,用姿势一的 CRD 方式管理周边依赖,然后持续跟踪姿势三那边有没有出现"社区大量采用 + 接口稳定"的信号,等信号明确了再上也不迟。

4.4 三个我预判一定会踩的坑

最后分享几个我预判(以及部分已经踩过)的坑,给你们提前打个预防针。

坑一:CRD 数量失控。这东西和微服务化一样,一不留神就会设计出十几个 CRD。结果控制面复杂度爆炸,一个集群里 run 着几百个 Controller-created 的资源,谁是谁的依赖都说不清。我建议你在设计 CRD 时给自己立一条规矩:能复用 K8s 原生对象的不要自己造。比如配置用 ConfigMap 就好,状态用 Status 字段就好,DataSource 挂载用 PVC 语义就好。

坑二:LLM 返回不稳定导致 Reconcile 循环抖动。K8s 的收敛模型建立在"结果可预期"的基础上,但 LLM 的输出天生有随机性。如果你让一个 Controller 根据 LLM 的返回去调节某个资源,很可能陷入"改了又改、永远收敛不了"的循环。我的应对方案是**:在 Controller 和 LLM 之间加一个轻量的规则引擎或者策略层**,LLM 只负责提出建议,最终是否变更由确定性规则裁决,这样既能保留智能,又不会让集群状态反复横跳。

坑三:记忆存储的选择过早优化。我看过很多团队一上来就用向量数据库存全部记忆,结果成本和运维复杂度直接起飞。实际上短期记忆用 Redis 就够了,长期记忆里真正值得向量化的可能只有一成——那些需要语义检索的决策记录和背景知识。先按访问频率把记忆分热温冷三层,再决定每层用什么存储,你会省下大量冤枉钱。

5. 边界与隐忧:新原语会不会变成过度抽象

聊了这么多新原语的好处,我也得泼几盆冷水。Agent Substrate 这个方向我很认可,但它并不天然正确,甚至存在几个值得警惕的倾向。

5.1 平台复杂性的螺旋上升

"加一层抽象"解决眼前的问题,往往是在为未来制造新的复杂度。K8s 本身就是最好的例子——它解决了单体脚本时代的问题,但代价是控制面的复杂度高到只有专业团队才玩得转,以至于后来催生了"K8s 太复杂,我们要 Serverless"的反弹。

Agent Substrate 如果只是把"容器编排"升级成"任务编排",最终很可能陷入同样的困境:CRD 越写越厚,Controller 越写越重,Sidecar 一个接一个。我特别担心的一点是,很多团队会把"多 Agent 协作"这个配置密集型的工作,搞成比手写业务流程还要复杂的 YAML 瀑布。

能不能避免?可以,前提是新原语必须真正减少重复劳动,而不是把重复劳动搬个家。比如"记忆持久化"确实减少了每个 Agent 项目自己接数据库的工作,这就是有效抽象;但如果某个原语只是把原来的一个步骤拆成五个步骤,那它就是过度设计。

5.2 安全审计的空白期

另一个绕不开的问题是安全。传统 K8s 环境里,网络策略、RBAC、PodSecurityContext 是一套相对成熟的体系。但 Agent 的权限模型完全不同——一个 Agent 可能被赋予调用云 API 的权限、读写内部知识库的权限、甚至执行财务操作的权限。这些权限如果只是映射成 K8s 的 RBAC 角色,粒度完全不够。

我见过的 Agent 攻击面有两个尤其需要关注:

  • 工具调用链的提权:一个本来只有只读权限的 Agent,在推理过程中可能会调用另一个有写权限的工具,如果工具网关不校验调用来源,这就是一条提权路径。Agent Substrate 在做工具原语时,必须把"谁在用这个工具、工具调用的可追溯性"作为一等公民。
  • 记忆投毒:如果恶意用户能在你共享的记忆库里塞入虚假信息,Agent 在后续推理时就可能把错误信息当作事实使用,导致"输出幻觉"变成"认知污染"。这个风险已经被安全团队注意到了,比如 a-memguard 等防御框架的出现,说明大家已经开始正视它。

5.3 标准化未定:别把项目写成时代的眼泪

最后是一个很现实的问题:标准化。K8s 之所以成为今天的 K8s,是因为有 CNCF 背书,有 Google 拉着各大厂商一起搞。而 Agent Substrate 目前还处在"各说各话"的战国时代——你家的 Memory API 和我家的完全对不上,他家的 Agent CRD 和我的 Controller 根本没法互通。

这种情况下,押错宝的代价很大。我观察到有些团队已经在做选择,有的是 Dapr + LLM 混合,有的是在 LangGraph 的 graph 定义外面再包一层 K8s CRD,有的干脆自己造轮子。我觉得这会是一个持续两到三年的混沌期,等到 MCP 这类协议被大规模接纳、几个头部开源项目形成事实标准之后,赛道才会逐渐清晰。

在那之前,我的建议是:接口多用标准开放的,实现尽量薄,别把自己绑定在任何一家私有 API 上。

6. 说点我个人看法

聊到最后,聊聊我自己对这个方向的真实感受。

我确实经历过一个转变。最早我做云原生相关工作,天天在琢磨 Pod、Deployment、Helm Chart,满脑子都是"编排一切"的冲动。当时看 Agent 类的应用,总觉得它们是花架子——不就一个 LLM API 套壳吗?有什么好编排的?

直到我真的开始把一些业务逻辑交给 Agent 去跑,比如让它自主调研竞品价格、生成报告、并且根据结果触发内部工单流转,我才意识到问题比我想象的复杂得多。Agent 最难的不是写 Prompt,而是怎么让这个有自主性的东西,在一条负责任、可审计、可回滚的轨道上工作。这恰好是基础设施层最应该解决、而现有 K8s 完全没有解决的问题。

所以我对 Agent Substrate 这类方向的评价是:方向对了,路还长。K8s 当年的成功,很大程度上是因为它把"分布式系统运维"这一混乱领域标准化了。Agent 的编排、记忆、协作协议,现在也是一片沼泽,谁能在保持工程简洁的前提下把这片沼泽填成马路,谁就握住了下一代基础设施的船票。

最后再分享一个我自己踩过记忆存储坑之后的实操经验。如果你现在就打算在自己的 K8s 集群里小规模试跑 Agent 工作负载,不用急着引入任何新平台。最快的起步方案是:一个 StatefulSet 挂 PVC 存短期会话,一个 Postgres 存长期决策记录,一个简单的 Restful 接口把 Agent 的每个决策点暴露出来打日志。先用这套最朴素的组合把 Agent 跑起来,等你真的遇到"三个 Agent 抢同一份记忆"或者"任务挂起就忘了唤醒"这类问题了,再开始研究要不要上 Substrate。到时候你会比那些追着热度走但从未被问题教育过的人,更能辨清哪些原语是刚需,哪些只是新瓶装旧酒。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询