編排原語(yǔ))
最近 K8s 社區(qū)那場(chǎng)關(guān)于 Agent Substrate 的對(duì)談我反反復(fù)復(fù)看了三遍。Kubernetes 之父 Brendan Burns 出來(lái)聊“為什么要在 K8s 之上給 Agent 造一層新原語(yǔ)”幾乎每一句話都戳在我過(guò)去一年做 AI infra 踩過(guò)的坑上。過(guò)去一年我所在的團(tuán)隊(duì)一直在折騰 Agent 平臺(tái)的底層早期方案就是“把 Agent 當(dāng)作普通 Pod 跑”后來(lái)被多輪會(huì)話、記憶持久化、工具權(quán)限、多 Agent 協(xié)作連續(xù)打臉才意識(shí)到 Agent 這類工作負(fù)載和傳統(tǒng)無(wú)狀態(tài)服務(wù)有本質(zhì)區(qū)別。這場(chǎng)對(duì)談最大的價(jià)值不是講了一個(gè)酷炫的新項(xiàng)目而是用一群人最有說(shuō)服力的歷史視角說(shuō)清了“原語(yǔ)缺失”這件事。Kubernetes 之所以能統(tǒng)治容器世界是因?yàn)樗谶M(jìn)程之上抽象出了 Pod、Service、Deployment 這些穩(wěn)定原語(yǔ)。而 Agent 時(shí)代我們其實(shí)還在拿這些為“無(wú)狀態(tài)進(jìn)程”設(shè)計(jì)的原語(yǔ)硬套“有狀態(tài)、會(huì)推理、能調(diào)用工具、還會(huì)自己決定下一步做什么”的智能體中間產(chǎn)生的摩擦就是大家天天在群里吐槽的“Agent 沒(méi)跑幾天就崩了”“會(huì)話狀態(tài)不知道放哪”“兩個(gè) Agent 互相調(diào)參數(shù)調(diào)死循環(huán)”。這篇文章把我對(duì)這場(chǎng)對(duì)談的理解以及過(guò)去一年在 K8s 上落地 Agent 平臺(tái)的實(shí)操經(jīng)驗(yàn)一起沉淀下來(lái)。我會(huì)先拆解“為什么 K8s 現(xiàn)有原語(yǔ)不夠用”再梳理 Agent Substrate 這批新原語(yǔ)到底應(yīng)該長(zhǎng)什么樣最后給出一個(gè)今天就能在 K8s 上動(dòng)手實(shí)現(xiàn)的模擬方案和避坑清單。適合正在做 Agent 平臺(tái)、AI infra、或者負(fù)責(zé)把 LLM 應(yīng)用工程化的同學(xué)尤其是那些已經(jīng)被“Pod 崩了重啟但 Agent 忘了自己是誰(shuí)”折磨過(guò)的人。1. 一場(chǎng)對(duì)談引發(fā)的思考K8s 和 Agent 之間到底缺了什么1.1 為什么是“K8s 之父”站出來(lái)聊 Agent如果拋開(kāi)標(biāo)題里的光環(huán)這場(chǎng)對(duì)談?wù)嬲业氖钦f(shuō)話人的身份。Brendan Burns 是看著 K8s 從 Borg 論文變成行業(yè)標(biāo)準(zhǔn)的親歷者他比絕大多數(shù)人都清楚“原語(yǔ)”對(duì)一個(gè)基礎(chǔ)設(shè)施層意味著什么。他在對(duì)話里反復(fù)強(qiáng)調(diào)一個(gè)觀點(diǎn)Kubernetes 解決的是“進(jìn)程”的編排問(wèn)題而 Agent 和普通進(jìn)程最大的不同在于Agent 的行為不是完全確定的它不是一個(gè)“啟動(dòng)后按代碼路徑跑完就退出”的程序而是一個(gè)“根據(jù)輸入、上下文和工具返回結(jié)果不斷決策”的循環(huán)。這個(gè)區(qū)別聽(tīng)起來(lái)很簡(jiǎn)單但影響非常深遠(yuǎn)。K8s 里最核心的編排單位是 PodPod 的假設(shè)是“里面跑的進(jìn)程是無(wú)狀態(tài)的、可替換的、死了重啟一個(gè)新的就行”。可 Agent 一旦跑了多輪對(duì)話積累了用戶偏好、調(diào)用了外部工具、產(chǎn)生了中間推理狀態(tài)這個(gè)“進(jìn)程”就不能隨便被替換。你可能遇到過(guò)這種情況模型服務(wù)本身好好的Pod 因?yàn)楣?jié)點(diǎn)抖動(dòng)被重新調(diào)度新的 Pod 起來(lái)了但 Agent 的會(huì)話上下文全沒(méi)了用戶下一句話發(fā)過(guò)來(lái)它像失憶一樣重新打招呼。這不是 Bug是我們沒(méi)有為 Agent 提供正確的編排原語(yǔ)造成的必然結(jié)果。對(duì)談里有一句話讓我印象很深大意是說(shuō)我們不該問(wèn)“Agent 能不能跑在 K8s 上”而該問(wèn)“K8s 上缺了哪些讓 Agent 能好好跑的零件”。這個(gè)視角把問(wèn)題從“容器運(yùn)行時(shí)適配”拉升到了“平臺(tái)語(yǔ)義設(shè)計(jì)”這才是真正的 K8s 人思考問(wèn)題的方式。1.2 Agent 不是“跑在 K8s 里”就夠了很多團(tuán)隊(duì)的 Agent 落地路徑和我最初一樣寫(xiě)一個(gè) Python/Node 服務(wù)里面封裝 LLM 調(diào)用、工具調(diào)用、會(huì)話邏輯然后打一個(gè)鏡像丟進(jìn) K8s配個(gè) Deployment 和 Service覺(jué)得萬(wàn)事大吉。Demo 階段確實(shí)能跑一上真實(shí)流量就開(kāi)始連環(huán)翻車。問(wèn)題出在哪Deployment 語(yǔ)義里只有“副本數(shù)”和“滾動(dòng)更新”它不知道一個(gè) Agent 實(shí)例正在跟某個(gè)用戶進(jìn)行一場(chǎng)有狀態(tài)的對(duì)話也不知道這次對(duì)話中還持有了哪些外部工具的資源。HPA 根據(jù) CPU 和內(nèi)存擴(kuò)容但 Agent 的瓶頸往往是 LLM 的限流配額、外部 API 的并發(fā)限制這類“非 CPU 類”指標(biāo)。Pod 的重啟策略翻來(lái)覆去就是 Always/OnFailure/Never但 Agent 需要的是“斷點(diǎn)續(xù)跑”需要重啟后能把之前的會(huì)話狀態(tài)、推理軌跡、工具調(diào)用結(jié)果重新加載回來(lái)。還有一個(gè)被低估的地方是觀測(cè)性。傳統(tǒng)服務(wù)你打點(diǎn) QPS、延遲、錯(cuò)誤率就夠了Agent 你至少還要知道它現(xiàn)在處于思考的哪個(gè)階段、準(zhǔn)備調(diào)哪個(gè)工具、工具返回了什么、它下一步的決策依據(jù)是什么。這些信息如果不成為平臺(tái)原語(yǔ)的一部分而是散落在業(yè)務(wù)日志里那你根本沒(méi)法定位一次 Agent 行為異常是模型問(wèn)題、提示詞問(wèn)題、還是工具鏈路問(wèn)題?!芭茉?K8s 里”和“被 K8s 正確編排”是兩碼事。前者是所有 AI 應(yīng)用都能做到的后者才是 Agent Substrate 想解決的。1.3 Substrate 這個(gè)詞的真正含義Substrate 直譯是“基底”“底層”在生物學(xué)里指酶作用的底物在材料學(xué)里指襯底。用在 Agent 領(lǐng)域它的意思很明確Agent 不是憑空生長(zhǎng)的它需要一個(gè)承載它運(yùn)行、記憶、通信、權(quán)限、評(píng)估的系統(tǒng)性底座。這個(gè)底座不是某一個(gè)組件而是一組統(tǒng)一的抽象讓上層應(yīng)用和下層基礎(chǔ)設(shè)施可以圍繞這些抽象協(xié)作。你可以把它理解為“Agent 的操作系統(tǒng)”。傳統(tǒng)操作系統(tǒng)給進(jìn)程提供了文件、網(wǎng)絡(luò)、內(nèi)存、進(jìn)程間通信這些原語(yǔ)Agent Substrate 要做的就是給 Agent 提供會(huì)話生命周期、持久記憶、Agent 間通信、工具調(diào)用策略、權(quán)限邊界、評(píng)估反饋這些原語(yǔ)。K8s 對(duì)容器的價(jià)值是“把基礎(chǔ)設(shè)施變成 API”Agent Substrate 對(duì) Agent 的價(jià)值是把“智能體運(yùn)行所需的各種能力變成一組標(biāo)準(zhǔn) API”。理解了這層再看對(duì)談里提到的各種設(shè)計(jì)就順了。Brendan 強(qiáng)調(diào)“不要重新發(fā)明容器但要重新抽象工作負(fù)載”意思是底層調(diào)度、資源隔離、節(jié)點(diǎn)管理這些 K8s 已經(jīng)解決得很好的部分繼續(xù)用但在更上層要為 Agent 這類新工作負(fù)載定義新的對(duì)象和生命周期模型。所謂“在 K8s 之上造一層新原語(yǔ)”指的是用 CRD、Operator、控制器這種 K8s 天然支持的方式擴(kuò)展語(yǔ)義而不是另起爐灶再造一套調(diào)度系統(tǒng)。2. K8s 現(xiàn)有原語(yǔ)面對(duì) Agent 的四個(gè)“不夠用”2.1 Pod 描述的是“進(jìn)程”不是“智能體”Pod 是 K8s 的最小調(diào)度單位一個(gè) Pod 里可以有一個(gè)或多個(gè)容器共享網(wǎng)絡(luò)和存儲(chǔ)。這套模型對(duì)微服務(wù)非常合適因?yàn)槲⒎?wù)的核心假設(shè)就是“實(shí)例無(wú)狀態(tài)狀態(tài)放外部存儲(chǔ)”。但 Agent 的天然形態(tài)是“一個(gè)擁有身份、記憶和行為策略的實(shí)體”它不完全等價(jià)于一個(gè)運(yùn)行中的進(jìn)程。舉個(gè)例子同一個(gè) Agent 服務(wù)可以同時(shí)服務(wù)一萬(wàn)個(gè)用戶會(huì)話每個(gè)會(huì)話是一個(gè)獨(dú)立的 Agent 執(zhí)行上下文。這時(shí)候 Pod 的數(shù)量對(duì)應(yīng)的是“服務(wù)實(shí)例數(shù)”而不是“Agent 會(huì)話數(shù)”。你需要一個(gè)能表達(dá)“當(dāng)前有多少個(gè)活躍 Agent 會(huì)話、每個(gè)會(huì)話的狀態(tài)在哪、什么時(shí)候銷毀”的原語(yǔ)。Pod 沒(méi)有這個(gè)語(yǔ)義kubectl scale 調(diào)整的是副本數(shù)但無(wú)法告訴你某一會(huì)話是否已經(jīng)超出最大輪數(shù)、是否需要?dú)w檔。另一個(gè)問(wèn)題是身份。傳統(tǒng) Pod 的身份由 Deployment 和 label 決定替換后身份基本沒(méi)意義。但 Agent 有身份它有名字、性格設(shè)定、偏好、歷史記憶甚至對(duì)外部系統(tǒng)來(lái)說(shuō)它有 API 憑證和權(quán)限。Pod 的 uid 每次重建都會(huì)變沒(méi)法承載 Agent 身份。你需要的是一個(gè)類似 AgentProfile 的持久對(duì)象它記錄 Agent 的靜態(tài)配置和動(dòng)態(tài)狀態(tài)而 Pod 只是它某一次運(yùn)行的載體。2.2 Service/Ingress 解決南北流量解決不了 Agent 之間的網(wǎng)狀通信K8s 的 Service 解決的是“客戶端如何訪問(wèn)一組 Pod”的問(wèn)題Ingress 解決的是“外部流量如何進(jìn)入集群”的問(wèn)題它們本質(zhì)上是南北向的。但 Agent 系統(tǒng)里大量的通信是東西向的一個(gè)主 Agent 拆解任務(wù)后要調(diào)用多個(gè)子 Agent子 Agent 之間要交換中間結(jié)果Agent 要回調(diào)外部系統(tǒng)獲取數(shù)據(jù)。這種通信模式有幾個(gè)特點(diǎn)第一通信關(guān)系是動(dòng)態(tài)的Agent 根據(jù)任務(wù)現(xiàn)場(chǎng)決定接下來(lái)要聯(lián)系誰(shuí)而不是啟動(dòng)時(shí)靜態(tài)配置好第二消息不是簡(jiǎn)單的請(qǐng)求-響應(yīng)而是帶有上下文的異步消息接收方可能需要較長(zhǎng)時(shí)間思考后才會(huì)回復(fù)第三通信本身有語(yǔ)義比如“這是一個(gè)任務(wù)委派”“這是一個(gè)結(jié)果回傳”“這是一個(gè)需要確認(rèn)的問(wèn)題”這些語(yǔ)義如果只用 HTTP 裸請(qǐng)求來(lái)表達(dá)那 Agent 框架層就要重復(fù)造輪子。Service Mesh 能解決一部分流量治理問(wèn)題但它管的是 TCP/HTTP 層不懂 Agent 的消息語(yǔ)義。K8s 也沒(méi)有內(nèi)置的“Agent 目錄”或“Agent 能力發(fā)現(xiàn)”機(jī)制。你在對(duì)談里能感受到他們的主張需要一個(gè)類似 AgentLink 的原語(yǔ)讓 Agent 之間可以按名字、按能力、按任務(wù)上下文進(jìn)行尋址和通信并且通信過(guò)程能被記錄、審計(jì)、限流。2.3 Deployment/StatefulSet 管“實(shí)例數(shù)”管不了“會(huì)話生命周期”在 K8s 里如果你要跑一個(gè)有狀態(tài)服務(wù)通常會(huì)用 StatefulSet配合 PVC 來(lái)保證每個(gè)實(shí)例有獨(dú)立的存儲(chǔ)。但 Agent 的狀態(tài)模型比這復(fù)雜得多。Agent 狀態(tài)不是一個(gè)固定大小的數(shù)據(jù)庫(kù)文件而是由多輪對(duì)話歷史、短期工作記憶、長(zhǎng)期用戶檔案、工具調(diào)用軌跡、當(dāng)前執(zhí)行計(jì)劃組成的復(fù)合體而且這些信息有各自的更新頻率和持久化要求。Deployment 的滾動(dòng)更新策略也不適配 Agent。你更新一個(gè) Agent 的提示詞或者工具列表不能簡(jiǎn)單粗暴地把所有實(shí)例滾動(dòng)重啟因?yàn)檎谶M(jìn)行的會(huì)話需要平滑遷移。理想情況下新版本的 Agent 應(yīng)該接管新的會(huì)話老版本繼續(xù)處理存量會(huì)話直到它們自然結(jié)束而不是把用戶和 Agent 的“關(guān)系”一刀切斷。還有擴(kuò)縮容。Deployment 和 HPA 只關(guān)心“實(shí)例數(shù)量”但 Agent 場(chǎng)景更自然的指標(biāo)是“活躍會(huì)話數(shù)”“等待外部工具響應(yīng)的會(huì)話數(shù)”“隊(duì)列深度”。我曾經(jīng)試過(guò)用自定義指標(biāo)給基于會(huì)話數(shù)的 Agent 做 HPAKEDA 確實(shí)能造這種 trigger但總感覺(jué)是拿膠水粘出來(lái)的因?yàn)榈讓拥?Workload 抽象并不真正理解會(huì)話生命周期。2.4 Namespace/NetworkPolicy 的隔離粒度對(duì) Agent 太粗K8s 的 Namespace 是資源隔離和權(quán)限控制的主要邊界NetworkPolicy 可以做到 IP 和端口級(jí)別的網(wǎng)絡(luò)隔離。但 Agent 場(chǎng)景的隔離維度要更細(xì)不同的 Agent 可能共享同一個(gè)命名空間卻需要不同的工具權(quán)限和數(shù)據(jù)訪問(wèn)范圍同一個(gè) Agent 在不同任務(wù)里可能被授予不同的權(quán)限級(jí)別。比如你有兩個(gè) Agent一個(gè)負(fù)責(zé)處理客戶訂單一個(gè)負(fù)責(zé)內(nèi)部知識(shí)庫(kù)問(wèn)答。它們跑在同一個(gè) Namespace 里但前者只能調(diào)用訂單 API后者只能查知識(shí)庫(kù)。這種能力的差異如果只靠 NetworkPolicy 來(lái)限制粒度根本不夠。你需要的是在 Agent 對(duì)象上直接聲明它的工具白名單、數(shù)據(jù)域、模型配額、調(diào)用外部服務(wù)的憑證。這就是 AgentPolicy 原語(yǔ)要承擔(dān)的角色。另外K8s 的 RBAC 針對(duì)的是“用戶操作 K8s 資源”而 Agent 需要的是“Agent 對(duì)外部業(yè)務(wù)系統(tǒng)”的權(quán)限模型。這兩個(gè)體系要打通但又不能混在一起?,F(xiàn)有的 Secret、ServiceAccount 可以解決一部分憑證問(wèn)題但缺少“這個(gè) Agent 在什么情況下可以用這個(gè)憑證”這種策略性約束而這恰好是 Agent 安全里最核心的問(wèn)題。場(chǎng)景維度K8s 現(xiàn)有原語(yǔ)Agent 需要的新原語(yǔ)運(yùn)行單位Pod無(wú)狀態(tài)進(jìn)程AgentRun有狀態(tài)智能體執(zhí)行單元身份與配置Deployment ConfigMapAgent/AgentProfile持久身份會(huì)話狀態(tài)PVC / 外部存儲(chǔ)手工管理AgentState/Memory一等公民服務(wù)發(fā)現(xiàn)Service / IngressAgentLink按能力尋址隔離與策略Namespace / NetworkPolicyAgentPolicy工具、數(shù)據(jù)、模型、憑證擴(kuò)縮容依據(jù)CPU / 內(nèi)存 / 自定義指標(biāo)會(huì)話數(shù) / 任務(wù)隊(duì)列 / 模型限流3. Agent Substrate 新原語(yǔ)拆解給 Agent 造專用“操作系統(tǒng)”3.1 AgentRun一次性任務(wù)還是長(zhǎng)駐服務(wù)Agent Substrate 里我認(rèn)為最基礎(chǔ)的原語(yǔ)是 AgentRun它定義一個(gè) Agent 的一次具體執(zhí)行生命周期。一個(gè) AgentRun 可能對(duì)應(yīng)一次用戶請(qǐng)求、一個(gè)自動(dòng)觸發(fā)的后臺(tái)任務(wù)或者一個(gè)持續(xù)運(yùn)行的多輪工作流。它和 Pod 最大的區(qū)別是Pod 的生命周期是“進(jìn)程從啟動(dòng)到退出”AgentRun 的生命周期是“目標(biāo)從開(kāi)始到完成”。AgentRun 要回答的關(guān)鍵問(wèn)題包括這個(gè) Agent 實(shí)例用的是哪個(gè) AgentProfile、模型配置、工具集合它最多允許幾輪推理超時(shí)時(shí)間是多少它的上下文窗口有多大它允許消費(fèi)多少資源它的執(zhí)行結(jié)果要回到哪里這些信息組合在一起就是一個(gè)可以被調(diào)度的、可以被審計(jì)的、可以被重啟恢復(fù)的 Agent 執(zhí)行單元。在我腦中這很像批處理里的 Job但比 Job 智能得多。Job 定義了 Pod 的完成條件AgentRun 定義了 Agent 的完成條件——可能是用戶說(shuō)“結(jié)束對(duì)話”可能是任務(wù)目標(biāo)達(dá)成可能是達(dá)到最大輪數(shù)也可能是被管理員中止。對(duì)于長(zhǎng)期運(yùn)行的客服 AgentAgentRun 可能對(duì)應(yīng)一段連續(xù)會(huì)話對(duì)于離線批量任務(wù)型 AgentAgentRun 可能就對(duì)應(yīng)一次任務(wù)執(zhí)行。平臺(tái)圍繞 AgentRun 可以做優(yōu)雅終止、狀態(tài)持久化、失敗重試和資源回收。apiVersion: substrate.example.com/v1alpha1 kind: AgentRun metadata: name: support-agent-20250401-001 namespace: ai-team spec: agentRef: name: customer-support version: v2 session: timeoutSeconds: 3600 maxTurns: 50 modelRef: name: llm-main provider: internal toolsRef: - order-lookup - refund-api policyRef: name: support-policy resources: cpu: 2 memory: 4Gi status: phase: Running currentStep: tool-call toolName: order-lookup turnCount: 12 lastHeartbeat: 2025-04-01T12:34:56Z這段 YAML 是我結(jié)合對(duì)談思路做的模擬示例不代表真實(shí)項(xiàng)目接口但能幫我們理解 AgentRun 到底“多管了多少事”。status 里不只有 Pod 的 Ready 狀態(tài)還有 Agent 當(dāng)前的推理輪次、正在執(zhí)行的動(dòng)作、最近一次心跳。有了這些運(yùn)維才能真正回答“這個(gè) Agent 到底卡在哪了”。3.2 AgentState / Memory持久狀態(tài)的一等公民K8s 里 PersistentVolumeClaim 是“一等公民”你可以直接聲明我要多大存儲(chǔ)。Agent Substrate 里對(duì)應(yīng)的原語(yǔ)是 AgentState但它比 PVC 更明確它要區(qū)分短期工作記憶、中期會(huì)話狀態(tài)、長(zhǎng)期用戶檔案和持久知識(shí)庫(kù)。短期工作記憶可以存在于 AgentRun 的上下文緩存里跟著 Run 走中期會(huì)話狀態(tài)要在 Agent 和用戶的對(duì)話過(guò)程中持續(xù)保存確保 Pod 重啟后會(huì)話可以恢復(fù)長(zhǎng)期記憶是跨會(huì)話的Agent 記住用戶偏好、歷史決策、項(xiàng)目背景。這三類數(shù)據(jù)的訪問(wèn)頻率、一致性要求、備份策略完全不同不應(yīng)該混在一個(gè)對(duì)象里。實(shí)操中我們會(huì)把長(zhǎng)期記憶放到外部存儲(chǔ)向量數(shù)據(jù)庫(kù)用于語(yǔ)義檢索、關(guān)系庫(kù)用于結(jié)構(gòu)化偏好、對(duì)象存儲(chǔ)用于對(duì)話歷史歸檔。但平臺(tái)層要提供統(tǒng)一的讀寫(xiě)原語(yǔ)讓 Agent 代碼調(diào)用的是“memory.get(key, namespaceuser_123)”而不是直接拼 SQL 或調(diào)向量庫(kù) SDK。這樣后續(xù)你想把底層的存儲(chǔ)從一個(gè)向量庫(kù)換成另一個(gè)Agent 業(yè)務(wù)代碼不需要改一行。AgentState 還必須處理并發(fā)和一致性問(wèn)題。一個(gè)用戶的兩個(gè)請(qǐng)求可能觸發(fā)兩個(gè) AgentRun 同時(shí)更新同一個(gè)記憶如果不加版本控制可能會(huì)互相覆蓋。我見(jiàn)過(guò)最粗暴的解法是給整個(gè)用戶加鎖結(jié)果就是同一用戶的請(qǐng)求全部串行體驗(yàn)很差。正確的做法應(yīng)該是按字段級(jí)版本號(hào)做條件更新或者用事件溯源的方式合并記憶變更。3.3 AgentLink / AgentMeshAgent 之間的尋址與通信對(duì)談里有個(gè)觀點(diǎn)我很認(rèn)同單個(gè) Agent 的能力再?gòu)?qiáng)也無(wú)法覆蓋復(fù)雜系統(tǒng)的所有需求產(chǎn)業(yè)鏈最終會(huì)走向多 Agent 協(xié)作。而 K8s 現(xiàn)有的 Service 模型并不能很好地支撐這種協(xié)作。AgentLink 設(shè)計(jì)上的核心是為每個(gè) Agent 提供一個(gè)邏輯地址這個(gè)地址與它的運(yùn)行位置解耦。Agent A 想要調(diào)用“訂單查詢 Agent”它不需要知道對(duì)方跑在哪個(gè)節(jié)點(diǎn)、哪個(gè) Pod只需要通過(guò)某種目錄服務(wù)做能力尋址。K8s DNS 能做一部分但 Agent 目錄不只是 DNS它還要帶元數(shù)據(jù)這個(gè) Agent 當(dāng)前忙不忙、支持哪些工具、有什么輸入輸出約束、是否接受委派。通信協(xié)議方面我傾向于基于消息隊(duì)列而不是直接 HTTP。因?yàn)?Agent 的處理時(shí)間不可控LLM 一次推理可能要幾秒一個(gè)復(fù)雜子 Agent 可能要幾十秒直接 HTTP 同步等待會(huì)浪費(fèi)大量連接資源。基于消息的異步通信能讓 Agent 之間解耦主 Agent 發(fā)出任務(wù)后可以訂閱結(jié)果事件。K8s 生態(tài)里 Kafka、NATS、RabbitMQ 都是現(xiàn)成的底座但平臺(tái)層需要給它們包一層 Agent 語(yǔ)義讓消息帶上任務(wù) ID、協(xié)議版本、上下文快照、安全令牌。另一個(gè)容易忽略的點(diǎn)是通信的審計(jì)與追溯。多 Agent 協(xié)作一旦出問(wèn)題你得能回放整個(gè)消息鏈路。所以每個(gè) Agent 間消息都應(yīng)該有不可變的 trace ID并且在平臺(tái)層長(zhǎng)期保存。這在技術(shù)實(shí)現(xiàn)上不復(fù)雜但如果不從原語(yǔ)層面強(qiáng)制業(yè)務(wù)代碼往往會(huì)嫌麻煩而不打。3.4 AgentPolicy準(zhǔn)入、配額與安全邊界如果說(shuō) AgentRun 是“執(zhí)行力”AgentLink 是“協(xié)作力”那 AgentPolicy 就是“安全感”。Agent 可以調(diào)用工具、訪問(wèn)數(shù)據(jù)、調(diào)用模型這些都是有成本、有風(fēng)險(xiǎn)的行為必須受策略約束。AgentPolicy 可以定義以下內(nèi)容這個(gè) Agent 允許調(diào)用哪些工具每個(gè)工具的頻率限制是多少這個(gè) Agent 可以訪問(wèn)哪些數(shù)據(jù)域不能訪問(wèn)哪些這個(gè) Agent 使用哪個(gè)模型服務(wù)最大 token 預(yù)算是多少在什么條件下這個(gè) Agent 可以升級(jí)權(quán)限、需要誰(shuí)審批外部工具的憑證從哪獲取是否允許緩存。安全方面的挑戰(zhàn)在于Agent 的工具調(diào)用是動(dòng)態(tài)產(chǎn)生的你沒(méi)辦法在部署前窮舉所有可能的調(diào)用。所以策略必須能實(shí)時(shí)評(píng)估“這次調(diào)用是否被允許”而不是靜態(tài)綁定在鏡像里。K8s 生態(tài)里的 OPA/Gatekeeper、Kyverno 可以做準(zhǔn)入控制但對(duì) Agent 來(lái)說(shuō)策略評(píng)估的時(shí)機(jī)不止是創(chuàng)建時(shí)還包括運(yùn)行中的每一次工具調(diào)用和每一次數(shù)據(jù)訪問(wèn)。作為平臺(tái)方我在落地的時(shí)候給出的最小可行方案是Agent 的所有工具調(diào)用都經(jīng)過(guò)一個(gè)統(tǒng)一的 ToolGatewayToolGateway 根據(jù) AgentPolicy 做鑒權(quán)和限流。Agent 本身永遠(yuǎn)不直接持有外部 API 憑證它只持有 ToolGateway 簽發(fā)的短期令牌令牌作用域精確到“哪幾個(gè)工具、多長(zhǎng)時(shí)間、調(diào)用多少次”。這樣即使某個(gè) Agent 的提示注入導(dǎo)致它想調(diào)用危險(xiǎn)工具ToolGateway 也能攔下來(lái)。3.5 和 Kubernetes 原生原語(yǔ)的關(guān)系不是替代是組合有人聽(tīng)到“給 Agent 造新原語(yǔ)”第一反應(yīng)是“又來(lái)一個(gè)想替代 K8s 的東西”。對(duì)談里其實(shí)說(shuō)得很清楚不是替代而是在 K8s 的能力之上延伸。AgentRun 最終還是要調(diào)度成 Pod 去跑AgentState 最終要落到 PVC 或外部存儲(chǔ)AgentLink 的服務(wù)發(fā)現(xiàn)最終還是要依賴 K8s DNS 或 etcdAgentPolicy 的執(zhí)行最終還是要靠 RBAC、NetworkPolicy、Secret 來(lái)承載。正確的做法是把 Agent 原語(yǔ)定義成 CRD用 Operator 控制器把 Agent 原語(yǔ)翻譯成 K8s 原生資源。Operator 負(fù)責(zé)監(jiān)聽(tīng) AgentRun 的創(chuàng)建為它創(chuàng)建相應(yīng)的 Deployment 或 StatefulSet并把 AgentState 對(duì)應(yīng)的存儲(chǔ)掛載進(jìn)去。上層用戶面對(duì)的是 Agent 語(yǔ)義底層平臺(tái)復(fù)用 K8s 的調(diào)度、自愈、滾動(dòng)升級(jí)能力。這樣你既沒(méi)有丟掉 K8s 生態(tài)也不用逼著用戶去理解 Pod 的細(xì)節(jié)。對(duì)平臺(tái)團(tuán)隊(duì)成員來(lái)說(shuō)這種架構(gòu)還有個(gè)好處你可以分階段交付。先做 AgentRun 和 Operator把生命周期管理落地再做 AgentLink把通信打通最后做 AgentPolicy把安全和治理補(bǔ)上。每塊都能獨(dú)立產(chǎn)生價(jià)值不用等一個(gè)“大而全”的平臺(tái)。4. 如果今天就要落地怎么在 K8s 上“模擬”這套原語(yǔ)4.1 最小閉環(huán)用 CRD Operator 定義 AgentRun真實(shí)場(chǎng)景中你不可能等社區(qū)標(biāo)準(zhǔn)定了再動(dòng)手。我的建議是先搭一個(gè)最小閉環(huán)寫(xiě)一個(gè) AgentRun CRD再寫(xiě)一個(gè)簡(jiǎn)單的 Operator把 AgentRun 轉(zhuǎn)換成 Deployment 加 PVC。今天就能用后續(xù)標(biāo)準(zhǔn)演進(jìn)時(shí)再遷移。CRD 的 schema 不要一上來(lái)就設(shè)計(jì)得很復(fù)雜先包含最關(guān)鍵字段agent 鏡像地址、模型配置、工具白名單、會(huì)話超時(shí)、內(nèi)存/CPU 配額、持久狀態(tài)開(kāi)關(guān)。我第一版就吃了設(shè)計(jì)過(guò)度的虧字段寫(xiě)了一堆結(jié)果 Agent 團(tuán)隊(duì)根本填不滿最后還得我來(lái)維護(hù)默認(rèn)值。最小可用版本比完美版本更有價(jià)值。Operator 的實(shí)現(xiàn)可以用 kubebuilder 或者 operator-sdk核心邏輯并不復(fù)雜watch AgentRun 資源創(chuàng)建對(duì)應(yīng)的 Deployment 和 PVC更新 AgentRun 的 status。難一點(diǎn)的地方在于“會(huì)話恢復(fù)”如果 Pod 被重啟新 Pod 啟動(dòng)時(shí)要能讀取 PVC 里的會(huì)話快照并帶著完整上下文繼續(xù)服務(wù)。這部分建議在 Agent 框架層配合Agent 啟動(dòng)時(shí)先嘗試從固定路徑加載 state 文件存在就恢復(fù)不存在就初始化新會(huì)話。# 創(chuàng)建 AgentRun 資源 kubectl apply -f agentrun.yaml # 觀察狀態(tài)流轉(zhuǎn) kubectl get agentruns.substrate.example.com -n ai-team -w # 查看某個(gè) AgentRun 的詳細(xì)信息 kubectl describe agentruns.substrate.example.com support-agent-20250401-001 # 查看對(duì)應(yīng) Pod 日志 kubectl logs -l substrate.agent/run-idsupport-agent-20250401-001 --tail100這套流程跑通之后你就有了一臺(tái)“能感知 Agent 會(huì)話”的 K8s 控制面。Agent 團(tuán)隊(duì)不再關(guān)心 Pod 叫什么、PVC 怎么掛他們只需要提交 AgentRun平臺(tái)自動(dòng)處理其余部分。4.2 記憶層選型與掛載設(shè)計(jì)記憶層是 Agent 平臺(tái)最容易糾結(jié)的地方因?yàn)槭忻嫔线x項(xiàng)太多Redis、PostgreSQL、Elasticsearch、Milvus、Chroma、MongoDB。我的經(jīng)驗(yàn)是先按數(shù)據(jù)類型拆不要一個(gè)庫(kù)解決所有問(wèn)題。對(duì)話歷史和事件流用普通的關(guān)系庫(kù)或?qū)ο蟠鎯?chǔ)量大但沒(méi)有高并發(fā)檢索需求用戶偏好和結(jié)構(gòu)化屬性用 Redis 或鍵值庫(kù)訪問(wèn)延遲要低需要語(yǔ)義檢索的長(zhǎng)期知識(shí)用向量數(shù)據(jù)庫(kù)。平臺(tái)層封裝的時(shí)候可以做成類似存儲(chǔ)適配器的接口內(nèi)部實(shí)現(xiàn)可替換。PVC 能不能做記憶層短期可以但我不建議把重要記憶放在本地 PVC 上。原因一是節(jié)點(diǎn)故障時(shí) PVC 的恢復(fù)涉及存儲(chǔ)遷移耗時(shí)不可控原因二是多個(gè) AgentRun 可能要共享同一份記憶PVC 的 ReadWriteOnce 模式不方便原因三是 Agent 平臺(tái)大概率要跨集群容災(zāi)本地 PVC 根本不是對(duì)手。所以我的方案是Pod 本地 emptyDir 只放臨時(shí)工作緩存重要狀態(tài)實(shí)時(shí)同步到獨(dú)立的狀態(tài)服務(wù)PVC 主要供 Agent 框架寫(xiě)入可恢復(fù)的會(huì)話快照。還有一個(gè)設(shè)計(jì)細(xì)節(jié)記憶的寫(xiě)入要支持事務(wù)和版本號(hào)。Agent 的決策鏈很長(zhǎng)期間用戶可能又發(fā)來(lái)一條消息如果你不加并發(fā)控制后完成的寫(xiě)入可能會(huì)覆蓋先完成的。我們?cè)诖a里用類似 CAS 的機(jī)制每次寫(xiě)入都帶上 based_on_version發(fā)現(xiàn)版本沖突就把兩個(gè)版本做合并或者把沖突事件拋給上層 Agent 決策。4.3 通信層從 Service Mesh 到消息總線Agent 之間的通信體系我建議分兩步走。第一步先引入消息總線保證 Agent 之間能異步收發(fā)任務(wù)和結(jié)果。這一步技術(shù)上很成熟NATS 或者 Redis Streams 都能勝任關(guān)鍵是消息格式要標(biāo)準(zhǔn)化消息頭里必須帶 taskId、senderAgent、receiverAgent、contextVersion、timestamp。有了這五個(gè)字段審計(jì)和追蹤就有基礎(chǔ)。第二步才考慮做 Agent 目錄和動(dòng)態(tài)尋址。這一步的價(jià)值在于讓主 Agent 能動(dòng)態(tài)發(fā)現(xiàn)“誰(shuí)能完成這個(gè)子任務(wù)”。實(shí)現(xiàn)上可以借用 K8s 的 Service 加上自定義元數(shù)據(jù)為每個(gè) Agent 創(chuàng)建一個(gè) Service同時(shí)在 Service 的 annotation 里注冊(cè)它的能力描述然后做一個(gè)輕量級(jí)目錄服務(wù)讀取這些信息。Agent 發(fā)起協(xié)作時(shí)先向目錄服務(wù)問(wèn)“誰(shuí)支持 refund 這個(gè)工具”拿到候選列表后再投遞消息。關(guān)于 Service Mesh它主要管的是東西向流量的安全、重試和可觀測(cè)性。如果 Agent 問(wèn)的通信走 HTTP 同步調(diào)用把 Agent 納入 Service Mesh 是有好處的。但如果是異步消息模式Service Mesh 的熔斷和重試語(yǔ)義就派不上大用場(chǎng)這時(shí)候需要的是消息隊(duì)列自己的限流和死信處理。所以不要盲目迷信 Service Mesh先搞清楚你的 Agent 協(xié)作是同步還是異步。4.4 可觀測(cè)性日志/鏈路/評(píng)估三板斧Agent 的可觀測(cè)性比傳統(tǒng)服務(wù)多一個(gè)維度不僅要看系統(tǒng)健康還要看智能體行為是否合理。我把它拆成三條線系統(tǒng)可觀測(cè)性、行為可觀測(cè)性、質(zhì)量可觀測(cè)性。系統(tǒng)可觀測(cè)性沿用 K8s 那套metrics、logs、traces 三件套關(guān)注 CPU、內(nèi)存、LLM 調(diào)用時(shí)延、Token 消耗量。行為可觀測(cè)性要記錄 Agent 每一步的決策過(guò)程它接收了什么輸入、選擇了什么工具、工具返回了什么、最終生成了什么決策。我會(huì)強(qiáng)制要求所有 Agent 運(yùn)行時(shí)把決策軌跡以結(jié)構(gòu)化日志輸出方便回放。質(zhì)量可觀測(cè)性是最容易被忽略的。Agent 的響應(yīng)沒(méi)有簡(jiǎn)單的“對(duì)錯(cuò)”之分需要引入評(píng)估體系對(duì)簡(jiǎn)單任務(wù)可以做規(guī)則校驗(yàn)比如是否包含必要字段對(duì)復(fù)雜對(duì)話可以接離線評(píng)估模型定期抽樣打分。評(píng)估結(jié)果要回寫(xiě)到 AgentRun 的 status 里這樣平臺(tái)才能在發(fā)布新提示詞版本時(shí)比較新舊版本的質(zhì)量分?jǐn)?shù)決定是否灰度放量。4.5 一套可復(fù)制的參考架構(gòu)把上面這些串起來(lái)我腦子里比較穩(wěn)定的一套拓?fù)涫沁@樣的用戶請(qǐng)求進(jìn)入 API GatewayGateway 創(chuàng)建或關(guān)聯(lián)一個(gè) AgentRunAgentRun 被 Operator 翻譯成實(shí)際 PodPod 內(nèi)的 Agent 運(yùn)行時(shí)負(fù)責(zé) LLM 交互和工具調(diào)用AgentState 服務(wù)負(fù)責(zé)記憶的存取ToolGateway 作為所有外部調(diào)用的唯一出入口AgentLink 目錄服務(wù)負(fù)責(zé)多 Agent 協(xié)作的尋址可觀測(cè)性組件采集系統(tǒng)和行為日志。這套架構(gòu)不需要一次全部建設(shè)可以按“單 Agent 跑通 → 有狀態(tài) → 可協(xié)作 → 有治理”的順序推進(jìn)。每一步都能看到明確的收益也讓團(tuán)隊(duì)技術(shù)在演進(jìn)中逐步沉淀。關(guān)鍵是不要用“我們還沒(méi)有標(biāo)準(zhǔn)”當(dāng)借口拖延K8s 自己也是從 Borg 論文里的一個(gè)小原型長(zhǎng)成今天的規(guī)模的。5. 實(shí)際踩坑記錄與排查清單5.1 Agent 優(yōu)雅退出比容器退出難十倍K8s 里給 Pod 配 preStop hook 和 terminationGracePeriodSeconds對(duì)普通服務(wù)來(lái)說(shuō)已經(jīng)夠用。但 Agent 多了一步它可能正在調(diào)用外部工具可能正在生成一段長(zhǎng)回復(fù)退出前必須決定是否保存當(dāng)前進(jìn)度、是否需要回滾半成品、是否需要通知上下游 Agent。我們遇到過(guò)一次線上事故Agent 在調(diào)用外部支付接口的途中Pod 因節(jié)點(diǎn)排空被 evict視同進(jìn)程被強(qiáng)殺。結(jié)果訂單那邊生成了支付請(qǐng)求Agent 這邊沒(méi)來(lái)得及記錄狀態(tài)用戶回頭來(lái)查訂單時(shí) Agent 一臉懵。后來(lái)我們的解決方案是在 AgentRun 上顯式聲明 gracefulTimeout讓 Operator 在收到 Pod 刪除請(qǐng)求后先通知 Agent 暫停推理、落盤狀態(tài)、歸還工具令牌再真正停止容器。這個(gè)通知必須走業(yè)務(wù)級(jí)信號(hào)不能只依賴 SIGTERM因?yàn)?Agent 的狀態(tài)往往跨多個(gè)服務(wù)需要協(xié)調(diào)處理。5.2 并發(fā)執(zhí)行時(shí)的資源配額審計(jì)Agent 和傳統(tǒng)服務(wù)的資源畫(huà)像完全兩樣。傳統(tǒng)服務(wù) CPU 是主要資源Agent 這邊模型調(diào)用次數(shù)和 Token 消耗可能比 CPU 更容易成為瓶頸。K8s 的 ResourceQuota 能限制 CPU 和內(nèi)存但沒(méi)法直接限制“每個(gè) AgentRun 最多調(diào)用模型 500 次”。我們的做法是在平臺(tái)層做配額核算每個(gè) AgentRun 創(chuàng)建時(shí)分配一個(gè)預(yù)算包含 token 上限、工具調(diào)用次數(shù)上限、總耗時(shí)上限。Agent 運(yùn)行時(shí)要通過(guò)平臺(tái)中間件上報(bào)消耗超過(guò)預(yù)算就自動(dòng)降級(jí)或者中止任務(wù)。這個(gè)機(jī)制幫我們解決了一個(gè)很現(xiàn)實(shí)的問(wèn)題某些 Agent 在缺少明確約束時(shí)會(huì)因?yàn)樘崾驹~寫(xiě)得不好陷入無(wú)限循環(huán)一次任務(wù)把一個(gè)月預(yù)算燒光。預(yù)算體系的本質(zhì)是給不可控的行為加一個(gè)硬邊界。5.3 多 Agent 協(xié)作時(shí)的循環(huán)依賴和調(diào)用風(fēng)暴多 Agent 協(xié)作上線后最典型的故障是兩個(gè) Agent 互相丟任務(wù)誰(shuí)也不真正推進(jìn)形成邏輯死循環(huán)。更隱蔽的是“扇爆”一個(gè)主 Agent 同時(shí)給 30 個(gè)子 Agent 下達(dá)任務(wù)子 Agent 各自執(zhí)行時(shí)又產(chǎn)生新的子任務(wù)數(shù)量指數(shù)級(jí)增長(zhǎng)直接把消息總線打爆。排查這類問(wèn)題最重要的就是鏈路 ID 和深度限制。我們?cè)?AgentLink 的消息頭里加了 hopCount 字段每經(jīng)過(guò)一個(gè) Agent 加一超過(guò)閾值直接拒收并上報(bào)異常。同時(shí)在主 Agent 側(cè)限制每輪最多生成多少個(gè)子任務(wù)。這套約束讓協(xié)作系統(tǒng)的行為變得可預(yù)測(cè)也讓異常能被快速發(fā)現(xiàn)。5.4 誤刪狀態(tài)存儲(chǔ)導(dǎo)致 Agent 身份丟失這是我在測(cè)試環(huán)境犯過(guò)一次的低級(jí)錯(cuò)誤清理資源時(shí)執(zhí)行了 kubectl delete pvc --all結(jié)果把十幾個(gè) Agent 的長(zhǎng)期記憶全刪了。Agent 本身還能啟動(dòng)但所有用戶偏好、歷史對(duì)話都沒(méi)了對(duì)用戶的回答變成“我們不認(rèn)識(shí)”。這次事故讓我明白Agent 狀態(tài)存儲(chǔ)必須在平臺(tái)層面做保護(hù)核心記憶卷加上 finalizer刪除 Agent 前必須先導(dǎo)出歸檔生產(chǎn)環(huán)境的存儲(chǔ)開(kāi)啟跨集群備份任何批量刪除操作必須經(jīng)過(guò)策略審核。5.5 常見(jiàn)問(wèn)題速查表現(xiàn)象可能原因快速排查動(dòng)作Agent 重啟后失憶會(huì)話狀態(tài)沒(méi)有持久化檢查 AgentState 是否掛載、啟動(dòng)時(shí)是否執(zhí)行恢復(fù)邏輯Agent 長(zhǎng)時(shí)間無(wú)響應(yīng)卡在等待工具返回查看當(dāng)前的 tool-call 狀態(tài)、外部 API 是否超時(shí)多個(gè) Agent 互相反復(fù)調(diào)用缺少協(xié)作終止條件檢查 hopCount、任務(wù)超時(shí)、死循環(huán)檢測(cè)Token 消耗異常飆升提示詞循環(huán)、無(wú)預(yù)算約束查看 AgentRun 配額、審計(jì)工具調(diào)用頻率工具調(diào)用被拒絕但無(wú)日志策略評(píng)估鏈路斷了查看 ToolGateway 日志、確認(rèn) AgentPolicy 已生效會(huì)話恢復(fù)后上下文錯(cuò)亂記憶版本沖突、覆蓋寫(xiě)入檢查版本號(hào)、事件合并策略排查 Agent 問(wèn)題時(shí)我自己的習(xí)慣是先用 kubectl describe agentrun 看當(dāng)前階段再用行為日志回放最后幾輪決策最后才去看系統(tǒng)指標(biāo)。順序反了很容易被 CPU 占用、Pod 重啟這類表面現(xiàn)象帶偏浪費(fèi)半天時(shí)間才發(fā)現(xiàn)根本原因是工具返回的格式不滿足提示詞里的要求。把 Agent 當(dāng)成真正的 Workload而不是 Pod 的附屬品是我這一年最大的體會(huì)。Agent Substrate 里的很多原語(yǔ)現(xiàn)在看像是一種“理想標(biāo)準(zhǔn)”但哪怕只吸收了其中一部分設(shè)計(jì)思路也能讓平臺(tái)的穩(wěn)定性上一個(gè)臺(tái)階。先跑起來(lái)在真實(shí)流量里迭代你很快會(huì)知道自己缺的到底是哪個(gè)零件。