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