前阵子和一个做 AI 平台的朋友聊天他说把 Agent 放到 Kubernetes 上跑总觉得哪里不对劲Pod 都起来了可 Agent 的状态、记忆、工具调用全散落在代码和 YAML 里想在集群层面统一管控又无从下手。这个话题最近因为“Agent Substrate”的讨论又热了起来核心主张就是在 Kubernetes 之上给 Agent 造一层新的原语让 Agent 像容器一样被描述、调度、交付而不是每次从零搭一套运行时。这篇文章我想聊聊这层“原语”到底在解决什么问题K8s 为什么管不好 Agent以及如果真要落地应该怎么设计、怎么操作。1. 为什么 K8s 管得好容器却管不好 Agent1.1 先捋清 K8s 原语解决了什么问题在讨论 Agent 之前得先把 Kubernetes 的成功原因拆开看。很多人以为 K8s 的核心是容器其实它真正的核心是一套围绕容器建立的声明式原语。Pod 是最小调度单元Deployment 描述期望的副本数Service 提供稳定的访问入口ConfigMap 和 Secret 管理配置HPA 负责弹性伸缩。就容器这个执行体来说Kubernetes 问的问题非常集中跑什么镜像、开几个端口、需要多少资源、出问题怎么重启。这些问题一旦被定义成原语上层发布、扩缩容、故障转移全都可以通过声明式的方式自动完成。“原语”这个词听起来很学术但放到云原生语境里并不难理解它就是平台能识别的最小描述单位。编程语言里的原语是原子操作云原生领域的原语就是你写 YAML 时描述期望状态的那些对象。K8s 之所以能管理成千上万个容器就是因为它把“跑一个进程”这件事抽象成了几个稳定的对象并给出了统一的调和循环我看到的状态和期望状态不一致就通过一系列操作把它拉回来。这个模型对容器非常有效因为它抓住了容器生命周期管理的全部关键维度。但问题来了Agent 这种计算实体是不是也可以用同一套模型来管1.2 Agent 并不是一种“容器化之后就能被管理好的进程”一个稍微完整的 Agent至少包含这些组成部分模型配置、System Prompt、上下文状态、短期记忆、长期记忆、工具调用能力、多轮对话历史再加上多 Agent 协作时的依赖关系。这些组成部分在容器抽象里几乎是盲区。K8s 擅长处理的是无状态 Workload或者通过 StatefulSet 管理有状态的存储节点但 Agent 本质上是有认知状态的计算实体。它的状态不只是 PVC 里的数据文件而是上下文窗口内容、工具调用结果、会话记忆、正在执行中的推理链路。这些状态散落在进程内存、Redis、向量数据库、消息队列里Kubernetes 本身完全不感知。你用一个 Deployment 起一个 Agent 服务K8s 只能看到这个容器是否 Running、内存是否超限、探针是否通过至于这个 Agent 当前在思考什么东西、上一步工具调用失败了几次、记忆有没有命中K8s 一概不知道。它就像一个只负责把货物搬上船的码头不关心货物是衣服还是机器更不关心这票货该送去哪个商场。维度K8s 对容器的抽象Agent 实际需要的抽象运行实体Pod / DeploymentAgentRun / AgentDeployment配置ConfigMap / SecretPrompt、模型参数、记忆配置、工具权限状态PVC、StatefulSet会话上下文、短期/长期记忆、向量库发现Service工具端点、Agent 间消息路由安全RBAC / NetworkPolicy工具调用审计、Prompt 注入防护、记忆隔离这里所说的 AgentRun、AgentDeployment 并不是某个固定标准而是基于当前 CRD 实践的常见设计倾向。平台要做到生产级 Agent 托管几乎都得考虑这类抽象。1.3 把 Agent 硬塞进 Pod 会踩到哪些坑现在很多团队的做法是直接用一个 Deployment 跑 Agent 服务把 Prompt 塞进 ConfigMap把 API Key 放进 Secret然后自己写代码处理记忆、工具调用和上下文管理。这条路不是不能用但有几个问题会随着规模增长集中爆发。第一个问题是重复造轮子。每个团队都在实现同一套“Agent 运行时管理”会话怎么拉起、记忆怎么清理、工具调用的鉴权和重试怎么做、Agent 崩溃后怎么恢复。这些逻辑跟业务几乎无关但每个项目都要写一遍。第二个问题是调度粒度太粗。Deployment 扩容只是把副本数变大但它不理解“会话级任务”这个概念。一个跑数据分析的 Agent 任务可能在执行到一半时被 OOM KillK8s 会把它重新调度可新实例并不知道上一半任务处理到哪里。第三个问题是排障困难。K8s 层面只能看到容器状态看不到 Agent 本轮调用模型花了几秒、是哪把工具失败、记忆有没有命中。整个过程非常依赖业务日志的质量而日志又往往只覆盖应用层跨不到 K8s 的资源层。这些问题的根源不是 K8s 不行而是 K8s 在设计时压根没考虑过“Agent 语义”。所以现在业内开始有人提出在 K8s 之上补一层 Agent 领域原语把 Agent 特有的一切变成平台能力。这就引出了 Agent Substrate。2. Agent Substrate 到底在补哪一层2.1 Substrate 是什么意思它和 K8s 是什么关系Substrate 直译是“基底”在软件体系里通常指承载上层业务的公共底座。把它放在 Kubernetes 之上意图就很明显了它不想重新发明调度器、网络、存储、可观测性而是想做Agent 领域的 Kubernetes 化抽象层。下面是 K8s 的调度和基础设施上面是 Agent 应用的控制编排逻辑。这个分层很像操作系统内核与运行时库之间的关系。Linux 内核管理进程、内存、文件系统但它不关心你的程序是 Python 还是 Go 写的运行时库才负责把你的语言运行时和具体业务连接起来。K8s 管理 Pod、Service、存储卷它就是 Agent 的操作系统内核Agent Substrate 则试图承担运行时库的角色把 Agent 的模型调用、记忆访问、工具执行、协作流程从业务代码里抽出来变成平台能力。更重要的是它不该把存储、调度、网络这些重活再做一遍。前面说了K8s 的调度器经历了大规模生产环境验证网络插件有 CNI 生态存储有 CSI 生态监控有 Prometheus 生态如果 Agent 平台自己重造一套等于把整个云原生基础设施重新发明一遍没有任何现实意义。正确的分工是K8s 管“怎么跑”Agent Substrate 管“Agent 怎么思考、怎么协作”。2.2 这一层需要哪些原语按领域模型来拆一套面向 Agent 的原语绕不开下面这几类。这里我按常见 CRD 设计习惯命名具体实现时各家可以不同但能力边界大致如此。AgentRun / AgentDeployment描述一个 Agent 任务的期望状态。除了镜像和副本数它还携带模型名称、System Prompt、上下文窗口长度、执行超时、失败策略。MemoryStore描述 Agent 用什么方式保存短期和长期记忆。底层可能是 Redis、向量库或对象存储但对上层暴露的是“读记忆、写记忆、检索记忆”这些稳定操作。ToolBinding把外部系统能力绑定给 Agent。包括函数签名、Endpoint、认证方式、调用频率限制、审计开关。SkillSet把一组预设能力打包让 Agent 在需要时动态装载而不是每次启动都把全部技能塞进上下文。MessageBus / TaskRouter描述多 Agent 协作关系比如任务队列、事件订阅、依赖拓扑。为什么要把这些能力定义成原语而不是留在代码里因为只有原语化之后K8s 控制器才能对资源做调和。用户声明“我要一个具备代码审查能力的 Agent记忆保留 72 小时允许调用 GitLab 只读接口”控制器收到声明后就会自动去创建底层 Deployment、PVC、NetworkPolicy、Secret并在 Agent 状态变化时不停收敛。这就是声明式管理的价值人和系统说的是同一套语言。2.3 为什么不自己写一套 Agent 专用调度器这个问题几乎每次聊都会被问既然 K8s 对 Agent 不够用为什么不干脆做一个 Agent 专用调度器直接管理模型运行时、记忆库和工具网关我的回答是可以但得不偿失。K8s 最值钱的地方不是它的调度算法有多巧妙而是它周边已经长成一个完整的生态。存储有 CSI网络有 CNI安全有 RBAC、NetworkPolicy、OPA/Gatekeeper观测有 Metrics Server、Prometheus、OpenTelemetry。Agent 专用调度器如果从零开始意味着这些全都要自己搭一遍。而 Agent 调度真正难的地方不是“把进程放到哪台机器”而是“如何描述 Agent 的意图和状态”。后者完全不依赖 K8s 的调度细节完全可以做成上层的 CRD 和控制器逻辑。用一个生活类比来说K8s 像码头它管集装箱怎么装卸、怎么堆放、怎么调配Agent Substrate 更像货代系统关心每一单货从哪里收、什么时候装、送给谁。码头不关心货是衣服还是机器货代系统关心。如果货代系统非要自己再造一个码头显然不划算。这个类比也解释了一个现象现在很多 Agent 平台的底座都是 K8s但 K8s 本身并不直接提供 Agent 编排——中间这层就是 Substrate 的机会。2.4 Agent 平台演进到生产阶段后这层原语的价值Agent 应用从 Demo 走到生产会遇到一批完全不是业务问题的共性问题会话需要保持、工具调用要被审计、记忆要可复用、多个 Agent 要协同。这些需求有两个共同点第一它们和具体 Prompt 无关第二它们和模型供应商无关。无论你用 GPT、Claude、通义千问还是本地模型无论你做的是客服机器人还是代码助手都需要这些能力。这正是把它们沉淀为平台原语的前提。原语化之后的价值有三方面。第一是降低开发成本业务团队只需要描述“我要什么样的 Agent、能用哪些工具、记忆放在哪里”剩下的是平台的事。第二是提升稳定性运行时管理、补偿重试、故障恢复由控制器统一处理不会因为换了一个开发者就让 Agent 行为发生漂移。第三是增强可控性所有 Agent 的工具调用、记忆访问都有审计记录合规和风控变得可落地。3. 核心细节Agent 原语的四种设计考量3.1 状态与记忆把上下文当成一等资源Pod 的状态和 Agent 的状态完全是两回事。K8s 里 StatefulSet 管的是网络标识和存储挂载Agent 的“状态”更多是会话上下文、对话历史、记忆检索结果。现在很多人做 Agent 记忆会在项目代码里直接连 Redis 和向量数据库短期记忆放 Redis长期记忆放向量库永久记忆放对象存储。看起来挺灵活但一旦 Agent 数量上来这套代码就是运维噩梦。更合理的做法是把 MemoryStore 定义成资源。控制器负责创建底层的 Redis、向量库、PVC并且在 Agent 被销毁时按策略清理。上层用户只需要在 YAML 里声明记忆的 TTL、检索方式、持久化等级。记忆分级也是这个领域讨论很多的话题短期记忆通常保持在上下文窗口内中期记忆可能需要 Redis 或内存数据库长期记忆需要向量检索永久记忆则需要对象存储加索引。把这些机制收敛到平台层之后业务代码就不需要关心“这条记忆该存到哪里”了。我在实际部署中有一个很深的体会记忆不是缓存是业务资产。不能因为 Agent 实例重启就把所有记忆丢光也不能把所有对话历史无限期堆在向量库里。设计 MemoryStore 时一定要把 TTL、容量上限、回收策略写清楚。否则上线三个月之后存储成本会让你回头来补这一课。3.2 工具调用与权限比 Service 暴露更细一层Agent 工具调用有两个很容易被忽略的问题。第一是工具协议。LLM 需要知道函数的 JSON Schema 才能发起正确调用这个协议不能散落在业务代码里否则 Agent 的能力边界完全不可控。第二是权限与审计。Agent 调用一个内部系统时需要清晰的凭证、频率限制和操作审计。ToolBinding 就是用来解决这两个问题的原语。在 K8s 里ToolBinding 可以绑定到一个 Service 或外部 Endpoint并通过 ServiceAccount、Secret、NetworkPolicy 完成授权和网络隔离。以一个内部工单系统为例Agent 被允许创建工单但只能给某个特定服务账号调用Secret 里存的只是受限 token不是管理员凭证每一次调用都记录入审计日志。这样的设计能保证 Agent 即使被恶意 Prompt 诱导也无法越权操作。建议把工具调用设计成显式的“外部副作用”资源并在 YAML 里声明超时、重试次数、并发上限。这一点越早想明白后面做治理就越轻松。我见过不少项目把工具调用写成 Python 函数随手requests.post一下结果线上出问题时根本不知道是哪个 Agent、在哪一轮对话、以什么参数调用了外部系统。这不是技术问题是抽象问题。3.3 多 Agent 协作需要比 Service 发现更上层的语义K8s 的 Service 解决的是进程间寻址但 Agent 之间的协作不是单纯的 A 调 B 的 HTTP 接口。一个典型的协作场景常常包含任务拆解、结果传递、依赖等待、失败重分配。这种拓扑关系如果写死在业务代码里代码复杂度会随着 Agent 数量增加而失控。我在架构设计中比较推荐的方式是把协作拓扑定义成 CRD。比如一个 Workflow 资源里声明多个 Agent 节点和边哪个 Agent 先跑跑到什么状态算成功结果传给谁失败之后是重试、人工介入还是换一个 Agent 接管。控制器收到 Workflow 之后逐个创建 AgentRun并监听各自的状态。这样一来Agent 编排就从业务代码提升到了声明式平台层每一次协作的拓扑都可以被审计、回放和灰度修改。多 Agent 协作还有一个很实际的问题消息传递。两个 Agent 之间要传一个 JSON 结果是直接用 HTTP 回调还是走消息队列我倾向于在平台层提供 MessageBus 原语把 Agent 之间的消息体、消息格式、有/无序、重试策略统一封装。业务团队只需要声明消息主题和消费者不用维护一堆临时接口。3.4 可观测性与安全原语层最容易忽略的角落Agent 应用的可观测性比普通微服务更难因为它存在推理、工具调用、记忆命中这些非标准事件。如果平台层不提供 Agent 级别的事件模型开发人员就只能扒模型响应日志效率很低。有了原语层之后控制器可以在资源状态里记录统一事件比如 Agent 已创建、模型调用开始、工具调用失败、记忆未命中、Token 消耗增加、任务完成。这些事件可以直接落到 K8s Event 里也可以通过 OpenTelemetry 转发到监控系统。安全方面最值得关注的是工具调用审计。谁在什么上下文里调用了什么工具、传入什么参数、结果如何这些必须有留痕。即使是在本地实验环境我也建议打开审计开关因为 Agent 的工具调用行为本身就是一个巨大的调试信号。Prompt 注入也不能忽视模型层做防护是一方面工具权限的最小化授权是另一方面。Agent 能调用的东西越少被诱导时造成的破坏就越有限。可观测性原语还有一个容易被低估的作用它能把“模型为什么这么回答”这个问题变成可查询的数据。你可能无法完全解释 LLM 的推理但你可以知道它在回答之前检索了哪些记忆、调用过哪些工具、上下文里包含了什么。这些信息组合起来足以定位大多数异常行为。4. 实操验证在 K8s 1.26 上搭一个最小组合4.1 环境准备与 preflight 检查我在本地实验用的集群版本是 v1.26.0。如果是用 kubeadm 初始化的启动时通常会在日志里看到类似这样的输出[init] using kubernetes version: v1.26.0 [preflight] running pre-flight checks这一段看起来不起眼但其实很重要。preflight 阶段会检查主机名是否合法、端口是否被占用、内核参数是否满足要求、容器运行时是否可用任何一项不满足都会直接终止初始化。很多控制器的异常都和环境不合规有关所以在装任何 Operator 之前把 preflight 检查认真过一遍是值得的。假设你要在 K8s 上装一个 Agent 编排控制器基础依赖建议准备这几样K8s 1.26 集群kubectl 可正常访问Helm用来安装控制器cert-manager处理 webhook 证书一个可用的 StorageClass用于 Agent 记忆和向量库一个 LLM 服务的访问入口和 API Key。为什么特别强调 cert-manager因为大多数控制器都会注册 MutatingAdmissionWebhook 或 ValidatingAdmissionWebhookwebhook 必须用 TLS 证书对外提供服务用 cert-manager 做证书签发和续期是最省事的方案。4.2 一份演示用的 Agent CRD 配置下面给一个简化的示例。需要说明的是这里的字段命名和结构是基于常见 CRD 设计惯例做的演示不是某个既定开源项目的真实配置。目的是让原理可以落地你可以按这个思路去对接具体的控制器实现。apiVersion: agent-substrate.io/v1alpha1 kind: AgentRun metadata: name: k8s-assistant namespace: agent-system spec: agent: model: qwen2.5:7b systemPrompt: | 你是一个 Kubernetes 运维助手。 你可以查询集群资源状态但禁止执行删除操作。 contextLength: 8192 memory: type: vector storageClass: standard ttl: 72h tools: - name: k8s-readonly endpoint: internal://kubernetes.default.svc timeoutMs: 3000 retries: 2 audit: true secretsRef: agent-credentials replicas: 1保存为agentrun.yaml后执行kubectl apply -f agentrun.yaml kubectl get agentrun -n agent-system kubectl describe agentrun k8s-assistant -n agent-system如果控制器工作正常你会看到 AgentRun 的状态被置为 Ready并且控制器自动创建了底层的 Deployment、ConfigMap、PVC、NetworkPolicy。想看控制器到底干了什么用这条命令kubectl logs -n agent-system deployment/agent-substrate-controller -f这种声明式方式的优势在于业务方不需要关心 Agent 的记忆服务部署在哪、工具的网络访问怎么打通。描述清楚之后控制器负责把 Agent 的各个组成部分翻译成 K8s 原生资源。这比在启动脚本里写一大段if else要整洁得多。4.3 与存量 K8s 资源的组合打法Agent 如果需要访问 Kubernetes API建议创建一个独立 ServiceAccount只授予只读权限然后通过 Secret 把 kubeconfig 或 token 注入到 Agent。如果工具只允许访问内网再补一条 NetworkPolicyapiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: agent-egress-restrict spec: podSelector: {} policyTypes: [Egress] egress: - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: kube-system ports: - protocol: TCP port: 443这条策略的效果是该 namespace 下所有 Agent Pod 只能访问 kube-system 的 443 端口外网一律不通。在调试 Agent 的工具调用时网络策略往往是第一处要检查的对象。很多 Agent 调外部工具超时不是代码问题而是出口直接被策略挡掉了。监控方面可以让 Agent 控制器暴露 Prometheus 指标同时把 Agent 级别状态写进 K8s Events。我会额外记录几个自定义指标比如agent_tool_call_total、agent_conversation_turns、agent_memory_hit_rate。这些指标对判断 Agent 行为和系统性能很有帮助比单纯看 CPU 和内存更有业务洞察力。4.4 踩过的坑和一些实践心得第一CRD 和 CR 要分开 apply。很多人第一次写 CR 时直接kubectl apply -f all.yaml如果 CRD 还没注册会得到类似error: unable to recognize all.yaml: no matches for kind AgentRun in version agent-substrate.io/v1alpha1的报错。正确流程是先安装 CRD等kubectl get crd里能看到这个资源再 apply 实例。第二webhook 没有就绪时创建资源会报Internal error occurred: failed calling webhook ...。这时候不要急着改 CRD先看 cert-manager 的 Certificate 是否 Ready。证书没签发出来webhook 服务就一直不可用YAML 写得再对也没用。第三Agent Pod 反复 CrashLoopBackOff先用kubectl describe pod看 Events。我遇到的大部分情况是内存超限或 Secret 没找到和模型、Prompt 没关系。定位问题要从外层到内层不要一上来就怀疑推理逻辑。第四LLM 的 API Key 务必放进 Secret然后通过secretsRef字段引用不要硬编码进 ConfigMap 或镜像。这个原则和普通应用没有区别但 Agent 项目里因为牵扯 Prompt 和记忆配置面更广泄漏路径也更多。5. 常见问题与排查技巧实录5.1 一个快速定位问题的分层方法Agent 排障最容易犯的错就是一上来就翻 YAML 和 Prompt。我的习惯是分三层排查先看 K8s 调度层Pod 是否 Running、是否被驱逐、事件里有没有 OOM再看 Agent 运行时层控制器日志、模型 API 返回、进程标准输出最后才看语义层Prompt 是否合理、上下文是否超长、记忆检索是否命中。这样做的好处很明显大量“Agent 不可用”的问题归根结底是底层 PVC 没绑定或网络策略拦截了流量跟模型和 Prompt 没有关系。如果你花一小时去调 Prompt实际问题是 Secret 没挂载那就太冤了。K8s 生态的可观测性工具已经很成熟你要做的是把 Agent 的排障流程也纳入这套体系而不是游离在业务日志之外。5.2 问题速查表现象可能原因排查命令 / 手段解决思路Agent 资源创建后状态长期不更新控制器未启动或 RBAC 权限不足kubectl logs deployment/agent-substrate-controller、kubectl auth can-list agentruns检查控制器 Deployment 和 ServiceAccount 授权工具调用一直超时NetworkPolicy 限制出网或 DNS 异常临时起一个 curl Pod 测试连通性、kubectl describe networkpolicy调整 Egress 规则检查 CoreDNSAgent 记忆写入失败StorageClass 不存在或 PVC Pendingkubectl get pvc -n agent-system、kubectl describe pvc配置默认 StorageClass显式指定存储类模型响应时好时坏上下文超长或 Token 超限查看agent_conversation_turns、agent_context_length指标压缩历史、滚动上下文窗口CrashLoopBackOff内存 Limit 太小或 Secret 缺失kubectl describe pod pod调大 resources检查 secretsRef 引用多 Agent 协作消息丢失消息队列消费组异常查看 MessageBus 组件日志和数据流状态检查 topic、消费位点、死信队列5.3 最后再聊一点个人体会我在本地 K8s 集群上把 Agent 塞进 Pod 折腾过一轮之后最大的感受是K8s 是一个极其优秀的“执行底座”但它对你的 Agent 如何思考、如何记忆、如何调用外部工具并不关心。Agent Substrate 这类方案的价值不只是新增几个 CRD而是把交互语义和调度语义做了分层让 Agent 真正成为平台可以编排的资源。如果你正在把 Agent 推向生产我的建议是别急着把所有逻辑写进容器启动脚本。先把状态、记忆、工具、协作这些概念抽出来做成声明式描述再让控制器去收敛。这个抽象过程本身往往比多写几个微服务更有长期价值。毕竟 Agent 的价值核心在认知能力而不在进程管理把前者从后者里解放出来才是这层“新原语”真正的意义。
阅读完成 · 觉得有帮助?