度設(shè)計(jì)指南:從混亂協(xié)作到穩(wěn)定編排的落地避坑方案)
做多智能體的人大概都經(jīng)歷過(guò)這么一段心路最開(kāi)始只有兩三個(gè) Agent大家各干各的配合得像模像樣等到數(shù)量慢慢漲到七八個(gè)、十幾個(gè)系統(tǒng)就開(kāi)始“鬧鬼”了。我在做某模擬項(xiàng)目X的時(shí)候曾經(jīng)把智能體從4個(gè)擴(kuò)展到8個(gè)結(jié)果問(wèn)題接踵而至兩個(gè) Agent 同時(shí)看中同一份客戶(hù)資料一個(gè)改完另一個(gè)覆蓋一次咨詢(xún)進(jìn)來(lái)三個(gè) Agent 分別給出了三套答案用戶(hù)差點(diǎn)當(dāng)場(chǎng)懵掉。問(wèn)題并不出在某個(gè) Agent 的模型能力上而是它們根本不知道還有誰(shuí)在同時(shí)干活。直到我把“總調(diào)度”作為獨(dú)立模塊加進(jìn)去所有任務(wù)先排隊(duì)、再分派、最后匯總整條鏈路才算穩(wěn)定下來(lái)。這篇博客就把我踩過(guò)的坑、驗(yàn)證過(guò)的方案講清楚多智能體越多為什么越需要一個(gè)總調(diào)度以及這個(gè)總調(diào)度應(yīng)該怎么設(shè)計(jì)、怎么落地、怎么避坑。適合正在從單 Agent 走向多 Agent 的開(kāi)發(fā)者也適合準(zhǔn)備把智能體系統(tǒng)接進(jìn)真實(shí)業(yè)務(wù)的架構(gòu)師。1. 智能體一多亂的不是代碼是協(xié)作拓?fù)?.1 從兩個(gè)Agent說(shuō)起雙人協(xié)作和十人混戰(zhàn)差別在哪兩個(gè) Agent 協(xié)作其實(shí)不需要什么調(diào)度器。A 把結(jié)果直接丟給 BB 處理完再回傳雙方約定好接口就能跑起來(lái)。三個(gè) Agent 也還行讓其中一個(gè)充當(dāng)臨時(shí)協(xié)調(diào)者另外兩個(gè)聽(tīng)它分配??梢坏┏^(guò)五個(gè)、十個(gè)問(wèn)題就來(lái)了每個(gè) Agent 都要知道“我該聽(tīng)誰(shuí)的”“誰(shuí)在等我”“我和誰(shuí)共享同一份數(shù)據(jù)”這種知識(shí)散落在各個(gè) Agent 的提示詞和上下文里根本維護(hù)不住。我見(jiàn)過(guò)不少團(tuán)隊(duì)把協(xié)作規(guī)則寫(xiě)進(jìn)系統(tǒng)提示詞比如“如果你是財(cái)務(wù) Agent你只能回答財(cái)務(wù)問(wèn)題”“遇到不確定的情況請(qǐng)?jiān)儐?wèn)審計(jì) Agent”。這在兩個(gè) Agent 的場(chǎng)景下有效但十個(gè) Agent 時(shí)協(xié)作關(guān)系就變成了完全圖。N 個(gè) Agent 之間的雙向協(xié)作關(guān)系數(shù)量是 N×(N-1)8 個(gè) Agent 就有 56 種潛在交互。實(shí)際運(yùn)行時(shí)未必每一種都會(huì)發(fā)生但只要缺少全局計(jì)劃任何一種交互都可能被觸發(fā)并且往往是意外觸發(fā)。最后的結(jié)果就是系統(tǒng)行為變得極其隨機(jī)同一個(gè)任務(wù)跑三次三次的路徑都不一樣誰(shuí)也說(shuō)不清哪條是對(duì)的。這個(gè)階段的亂本質(zhì)上是協(xié)作拓?fù)涫Э?。代碼本身沒(méi)有語(yǔ)法錯(cuò)誤單個(gè) Agent 的 Prompt 也沒(méi)有明顯問(wèn)題但組合起來(lái)就是不穩(wěn)定。我在項(xiàng)目X里遇到過(guò)最典型的情況一個(gè)“合同審查”任務(wù)被同時(shí)分給了法律 Agent 和合規(guī) Agent兩個(gè) Agent 各自調(diào)用了不同的外部工具得出了兩個(gè)互相矛盾的結(jié)論。單獨(dú)看任何一方都沒(méi)有錯(cuò)但放在同一條業(yè)務(wù)鏈路里就變成了嚴(yán)重事故。1.2 常見(jiàn)的三種失序現(xiàn)象搶活、空轉(zhuǎn)、互相等待把多智能體系統(tǒng)跑起來(lái)以后最常見(jiàn)的失序現(xiàn)象有三種。第一種叫“搶活”能力重疊的兩個(gè) Agent 同時(shí)收到同樣一個(gè)任務(wù)。原因通常是任務(wù)路由沒(méi)有統(tǒng)一入口或者入口只管分發(fā)、不管查重。比如你有一個(gè)負(fù)責(zé)寫(xiě)郵件草稿的 Agent又有一個(gè)負(fù)責(zé)“商務(wù)溝通文案”的 Agent兩個(gè)能力描述高度相似同一個(gè)請(qǐng)求就可能同時(shí)命中它們。結(jié)果就是兩邊各做一遍浪費(fèi)算力不說(shuō)返回給用戶(hù)的結(jié)果還得你自己挑一個(gè)挑錯(cuò)了就是事故。第二種叫“空轉(zhuǎn)”Agent 在等待另一個(gè) Agent 的結(jié)果而那個(gè) Agent 也在等待別人甚至整個(gè)鏈路里沒(méi)有任何一個(gè)任務(wù)正式開(kāi)始執(zhí)行。這類(lèi)問(wèn)題在引入異步執(zhí)行之后尤其容易出現(xiàn)。A 任務(wù)依賴(lài) B 任務(wù)B 任務(wù)依賴(lài) C 任務(wù)而 C 任務(wù)的觸發(fā)條件又寫(xiě)成了“等待 A 完成”于是一條環(huán)形依賴(lài)直接把整批任務(wù)卡死。沒(méi)有調(diào)度器的時(shí)候這類(lèi)問(wèn)題只能靠日志一條條翻翻到最后你甚至?xí)l(fā)現(xiàn)部分 Agent 根本沒(méi)有被調(diào)用過(guò)。第三種叫“上下文污染”一個(gè) Agent 讀取了共享數(shù)據(jù)源并做了修改另一個(gè) Agent 讀到的卻是修改前的舊快照。我在項(xiàng)目X里就踩過(guò)這個(gè)坑。兩個(gè) Agent 并行處理同一份合同的不同條款其中一個(gè)把“金額”字段更新了另一個(gè)手里還攥著老版本的全文結(jié)果最終報(bào)告里金額前后不一致。這三個(gè)現(xiàn)象的根因全部指向同一個(gè)地方缺少一份所有任務(wù)都認(rèn)可的全局執(zhí)行計(jì)劃缺少一個(gè)唯一的事實(shí)來(lái)源。1.3 為什么多Agent不是算力問(wèn)題而是結(jié)構(gòu)性矛盾很多人第一反應(yīng)是“加計(jì)算資源”“換更強(qiáng)的模型”。但多 Agent 系統(tǒng)的問(wèn)題并不是單個(gè)步驟算不動(dòng)而是步驟之間的銜接關(guān)系亂了。無(wú)論模型多強(qiáng)你都無(wú)法通過(guò)一條系統(tǒng)提示詞讓十個(gè) Agent 長(zhǎng)期保持步調(diào)一致。大模型的每一次推理都帶有概率性哪怕同一個(gè) Agent給它完全相同的輸入兩次也可能給出略有差異的輸出。讓這樣一批概率性組件去自行協(xié)調(diào)相當(dāng)于讓一群各自拿著半張地圖、且地圖信息還會(huì)過(guò)期的士兵協(xié)同作戰(zhàn)結(jié)果自然不可控。多智能體系統(tǒng)本質(zhì)上是一個(gè)分布式系統(tǒng)。分布式系統(tǒng)的第一法則就是不能假設(shè)所有節(jié)點(diǎn)都會(huì)主動(dòng)配合。放在智能體場(chǎng)景里也一樣你不能假設(shè)每個(gè) Agent 都會(huì)主動(dòng)上報(bào)進(jìn)度不能假設(shè)每個(gè) Agent 都在用最新版本的數(shù)據(jù)不能假設(shè)兩個(gè) Agent 不會(huì)對(duì)同一個(gè)外部工具做重復(fù)調(diào)用。總調(diào)度就是把“隱性的協(xié)作假設(shè)”變成“顯式的執(zhí)行約束”。它不一定是復(fù)雜系統(tǒng)但必須是獨(dú)立于業(yè)務(wù) Agent 之外的一個(gè)角色專(zhuān)門(mén)負(fù)責(zé)回答四個(gè)問(wèn)題現(xiàn)在該做什么、由誰(shuí)來(lái)做、做完之后給誰(shuí)、遇到?jīng)_突聽(tīng)誰(shuí)的。補(bǔ)充一點(diǎn)調(diào)度不是限制自由度。恰恰相反有了總調(diào)度之后每個(gè) Agent 反而可以更自由。因?yàn)樗鼈儾恍枰訇P(guān)心“別人在干什么”“該不該主動(dòng)匯報(bào)”只需要把眼前的任務(wù)做好把結(jié)果標(biāo)準(zhǔn)化地交回去。整個(gè)系統(tǒng)的自由度從“無(wú)序自治”變成了“有限自治”問(wèn)題復(fù)雜度會(huì)立刻降一個(gè)臺(tái)階。2. 總調(diào)度不是“加一個(gè)Agent”而是獨(dú)立分層2.1 總調(diào)度器區(qū)別于普通Agent的三個(gè)特征很多人在設(shè)計(jì)多智能體系統(tǒng)時(shí)第一反應(yīng)是“再加一個(gè)主管 Agent 來(lái)分配任務(wù)”。這個(gè)思路方向?qū)Φ菀鬃銎?。主?Agent 本質(zhì)上仍然是一個(gè) LLM Agent它還是會(huì)有隨機(jī)性還是會(huì)漏狀態(tài)還是可能遺忘上下文。真正穩(wěn)定的總調(diào)度器應(yīng)當(dāng)是一個(gè)獨(dú)立的分層模塊而不是一個(gè)加了特殊 Prompt 的普通 Agent。總調(diào)度器至少有三個(gè)特征。第一它不直接產(chǎn)出業(yè)務(wù)結(jié)果??傉{(diào)度不寫(xiě)文案、不判斷合同條款、不做數(shù)據(jù)抽取。它的產(chǎn)出物是“任務(wù)分配方案”“執(zhí)行順序”“沖突裁定結(jié)果”。一旦調(diào)度器下場(chǎng)干活它就失去了中立性也會(huì)把自己的算力消耗和狀態(tài)管理混進(jìn)業(yè)務(wù)鏈路復(fù)雜度不降反升。第二它擁有全局狀態(tài)。只有調(diào)度器能看到所有 Agent 的任務(wù)狀態(tài)、輸出摘要、資源占用情況。普通 Agent 只能看到分配給它自己的那部分上下文這是一個(gè)刻意的隔離設(shè)計(jì)。Agent 知道得越少就越不容易產(chǎn)生上下文污染。第三它有最終仲裁權(quán)。當(dāng)兩個(gè) Agent 給出的結(jié)論互相矛盾時(shí)誰(shuí)來(lái)拍板不能靠?jī)蓚€(gè) Agent 繼續(xù)對(duì)話(huà)協(xié)商因?yàn)樗鼈兒芸赡芨髯詧?jiān)持己見(jiàn)。仲裁權(quán)必須收歸到調(diào)度器或者由調(diào)度器決定“是否需要引入第三方復(fù)核”“是否直接進(jìn)入人工通道”。沒(méi)有仲裁權(quán)的調(diào)度器本質(zhì)上只是消息轉(zhuǎn)發(fā)器。2.2 總調(diào)度要管的四件事路由、狀態(tài)、依賴(lài)、仲裁展開(kāi)來(lái)說(shuō)總調(diào)度至少要做四件事。第一件是任務(wù)路由。接收一個(gè)外部請(qǐng)求后調(diào)度器要判斷這個(gè)請(qǐng)求屬于什么類(lèi)型再由能力匹配算法選擇合適的 Agent。路由不是簡(jiǎn)單的關(guān)鍵詞匹配。同一個(gè)請(qǐng)求可能有多個(gè) Agent 都聲稱(chēng)自己能處理這時(shí)候就要有一個(gè)打分機(jī)制把“能力描述相似度”“當(dāng)前負(fù)載”“歷史成功率”等因素綜合進(jìn)去。第二件是狀態(tài)維護(hù)。每個(gè)任務(wù)都要有明確的生命周期狀態(tài)等待中、運(yùn)行中、已完成、失敗、超時(shí)、被仲裁。狀態(tài)是全局唯一的所有下游邏輯都以這個(gè)狀態(tài)為準(zhǔn)。你可以用一張數(shù)據(jù)庫(kù)表、一個(gè) Redis 緩存或者內(nèi)存字典來(lái)維護(hù)核心是要讓狀態(tài)成為“唯一事實(shí)來(lái)源”。第三件是依賴(lài)協(xié)調(diào)。業(yè)務(wù)復(fù)雜以后任務(wù)之間會(huì)有先后關(guān)系。比如必須先把文檔解析完才能做條款提取條款提取完才能做風(fēng)險(xiǎn)評(píng)估。調(diào)度器必須能表達(dá)這種依賴(lài)關(guān)系。我建議用 DAG 來(lái)表達(dá)每個(gè)任務(wù)是一個(gè)節(jié)點(diǎn)依賴(lài)關(guān)系是邊只有入度為 0 的任務(wù)才進(jìn)入執(zhí)行隊(duì)列。這樣可以自然表達(dá)并行和串行。第四件是沖突仲裁。兩個(gè) Agent 的結(jié)果不一致調(diào)度器要決定如何處理。我的經(jīng)驗(yàn)是不要盲目信任“最新結(jié)果”或“置信度最高”的一方。置信度高不代表正確最新也不代表更準(zhǔn)確。最穩(wěn)妥的策略是“能自動(dòng)合并則合并不能合并則走人工復(fù)核通道”。哪怕是多花一點(diǎn)時(shí)間也好過(guò)讓錯(cuò)誤結(jié)果進(jìn)入下一個(gè)環(huán)節(jié)。2.3 機(jī)場(chǎng)塔臺(tái)類(lèi)比調(diào)度員不該自己開(kāi)飛機(jī)總調(diào)度最合適的類(lèi)比是機(jī)場(chǎng)塔臺(tái)。機(jī)場(chǎng)不會(huì)讓每個(gè)飛行員通過(guò)公共頻道廣播自己的航線(xiàn)讓所有人自行協(xié)調(diào)避讓而是由塔臺(tái)統(tǒng)一統(tǒng)籌。塔臺(tái)知道每架飛機(jī)的當(dāng)前位置、計(jì)劃航線(xiàn)、跑道占用情況然后給出清晰的指令你現(xiàn)在保持高度你跟著前面的飛機(jī)進(jìn)近你暫時(shí)在等待區(qū)盤(pán)旋。Agent 也一樣。有了總調(diào)度之后每個(gè) Agent 不需要感知全局。它只接收三樣?xùn)|西格式化的任務(wù)描述、任務(wù)必要的上下文、輸出格式要求。執(zhí)行完畢后上報(bào)結(jié)果摘要。這個(gè)模式的優(yōu)點(diǎn)很明顯低耦合、可演進(jìn)。新增一個(gè) Agent 時(shí)只需要向調(diào)度器注冊(cè)它的能力和約束條件其他 Agent 的代碼完全不用動(dòng)。整個(gè)系統(tǒng)從“網(wǎng)狀協(xié)作”變成了“星型協(xié)作”生態(tài)位清晰了故障定位也容易了。一個(gè)任務(wù)出問(wèn)題先查調(diào)度記錄里“分配給誰(shuí)”“執(zhí)行多久”“輸出摘要是什么”基本一眼就能定位到是路由錯(cuò)了、還是某個(gè) Agent 自身能力不行。還有一條紀(jì)律值得特別注意調(diào)度器一定不要順手做一些“簡(jiǎn)單但緊急”的業(yè)務(wù)任務(wù)。比如看到某個(gè)數(shù)據(jù)格式需要轉(zhuǎn)換就自己寫(xiě)個(gè)轉(zhuǎn)換邏輯。一次兩次沒(méi)事時(shí)間長(zhǎng)了調(diào)度器就會(huì)變成一個(gè)隱形的業(yè)務(wù) Agent它的輸出也開(kāi)始需要被別人調(diào)度最終回到老路上去。3. 實(shí)現(xiàn)總調(diào)度的四種模式與選型依據(jù)3.1 中央調(diào)度器模式直接但別讓中心變成瓶頸最常見(jiàn)的實(shí)現(xiàn)方式是把調(diào)度器做成一個(gè)獨(dú)立的中央服務(wù)。外部請(qǐng)求先進(jìn)入調(diào)度器調(diào)度器把請(qǐng)求轉(zhuǎn)成內(nèi)部任務(wù)塞進(jìn)隊(duì)列然后按順序或按優(yōu)先級(jí)分發(fā)給各個(gè) Agent。每個(gè) Agent 執(zhí)行完自己的部分把結(jié)果摘要回傳給調(diào)度器調(diào)度器再?zèng)Q定下一步動(dòng)作。這種模式的優(yōu)勢(shì)是簡(jiǎn)單直接控制力強(qiáng)。所有任務(wù)都過(guò)同一個(gè)入口狀態(tài)集中在一個(gè)地方管理出現(xiàn)問(wèn)題時(shí)排查路徑非常短。我一般建議幾十個(gè) Agent 以?xún)?nèi)的系統(tǒng)優(yōu)先采用中央調(diào)度器模式。不要一上來(lái)就搞分布式協(xié)調(diào)那是過(guò)度設(shè)計(jì)。但中央調(diào)度器也有明顯的軟肋它本身可能成為性能瓶頸和單一故障點(diǎn)。如果所有任務(wù)都是同步等待來(lái)一個(gè)請(qǐng)求就阻塞一個(gè)線(xiàn)程并發(fā)一高調(diào)度器立刻變成最慢的環(huán)節(jié)。我的處理方式是把同步調(diào)用改成異步任務(wù)隊(duì)列調(diào)度器只負(fù)責(zé)入隊(duì)、分派、記錄狀態(tài)Agent 執(zhí)行完了通過(guò)回調(diào)或者輪詢(xún)上報(bào)結(jié)果。這樣調(diào)度器本身的耗時(shí)只占整個(gè)鏈路的一小部分瓶頸壓力會(huì)小很多。另外調(diào)度器一定要做持久化不能只把狀態(tài)放在內(nèi)存里。否則一旦服務(wù)重啟所有在途任務(wù)全部丟失屏幕上全是“任務(wù)狀態(tài)未知”。3.2 工作流/狀態(tài)機(jī)模式適合流程固定、過(guò)程可預(yù)期的系統(tǒng)如果業(yè)務(wù)場(chǎng)景是一個(gè)穩(wěn)定的流程比如“客戶(hù)工單進(jìn)來(lái) - 意圖識(shí)別 - 信息抽取 - 分類(lèi) - 自動(dòng)回復(fù)生成 - 質(zhì)檢”那么用工作流/狀態(tài)機(jī)模式會(huì)更舒服。所謂工作流模式就是把調(diào)度邏輯預(yù)先定義成一張流程圖或狀態(tài)表當(dāng)前處于什么狀態(tài)、滿(mǎn)足什么條件、接下來(lái)把任務(wù)交給哪個(gè) Agent。與中央調(diào)度器相比工作流模式的優(yōu)勢(shì)在于流程可視化、結(jié)果可預(yù)期。開(kāi)發(fā)階段就可以把整條鏈路畫(huà)出來(lái)評(píng)審的時(shí)候大家直接對(duì)著流程圖討論而不是讀代碼。真實(shí)項(xiàng)目里我習(xí)慣用 JSON 或 DSL 來(lái)描述流程定義而不是硬編碼在代碼里。這樣流程調(diào)整不需要改代碼重新發(fā)布運(yùn)營(yíng)同學(xué)改個(gè)配置就能實(shí)現(xiàn)“先做 B 再做 A”。這種模式的代價(jià)是靈活性差。一旦業(yè)務(wù)流程開(kāi)始變得動(dòng)態(tài)比如“根據(jù)上一步的產(chǎn)出決定下一步的分支”工作流描述就會(huì)迅速膨脹。分支多了以后配置文件和傳統(tǒng)代碼一樣難以維護(hù)。所以我通常只在“流程確定性比較高、變化頻率低”的場(chǎng)景采用這個(gè)模式。如果每?jī)商炀鸵右粋€(gè)新分支建議回到中央調(diào)度器模式把決策邏輯交給代碼。3.3 事件總線(xiàn)分布式協(xié)調(diào)適合高動(dòng)態(tài)、長(zhǎng)時(shí)運(yùn)行的系統(tǒng)當(dāng) Agent 數(shù)量繼續(xù)增加或者任務(wù)是長(zhǎng)時(shí)運(yùn)行、中間有大量等待時(shí)事件驅(qū)動(dòng)模式會(huì)更合適。Agent 不再直接向調(diào)度器匯報(bào)“我做完了”而是向事件總線(xiàn)發(fā)布一個(gè)事件比如“合同條款提取完成結(jié)果存儲(chǔ)在某個(gè)可訪問(wèn)地址”。調(diào)度器監(jiān)聽(tīng)自己關(guān)心的事件類(lèi)型根據(jù)事件內(nèi)容推進(jìn)后續(xù)任務(wù)。這個(gè)模式和前兩種的核心差別在于調(diào)度器和 Agent 之間解耦了。Agent 不需要知道調(diào)度器是誰(shuí)調(diào)度器也不需要惦記每個(gè) Agent 的實(shí)時(shí)狀態(tài)。事件總線(xiàn)天然支持消息的異步投遞也方便新 Agent 接入。代價(jià)是調(diào)試復(fù)雜度明顯上升。事件是分布式系統(tǒng)中的雙刃劍它會(huì)亂序會(huì)重復(fù)投遞也可能丟失。所以每個(gè)事件必須攜帶唯一的任務(wù) ID消費(fèi)方要做冪等處理。在項(xiàng)目X的后期跑多個(gè)環(huán)境時(shí)我甚至見(jiàn)過(guò)同一事件被重復(fù)消費(fèi)導(dǎo)致任務(wù)執(zhí)行兩遍對(duì)外表現(xiàn)為重復(fù)扣費(fèi)。后來(lái)在消費(fèi)邏輯里加了“按任務(wù) ID 去重”的機(jī)制才算止住。事件總線(xiàn)模式比較適合已經(jīng)有一定分布式系統(tǒng)經(jīng)驗(yàn)的團(tuán)隊(duì)新手團(tuán)隊(duì)直接上手容易被打得暈頭轉(zhuǎn)向。3.4 多級(jí)調(diào)度先全局規(guī)劃再局部自治還有一種模式往往在大型系統(tǒng)里出現(xiàn)多級(jí)調(diào)度。全局調(diào)度器只負(fù)責(zé)大的階段劃分比如“先做資料準(zhǔn)備再做分析最后出報(bào)告”每個(gè)階段內(nèi)部又有一個(gè)局部調(diào)度器負(fù)責(zé)細(xì)化該階段里的 Agent 分工。這就像公司組織架構(gòu)里的部門(mén)制。全局調(diào)度器是總經(jīng)理局部調(diào)度器是部門(mén)主管??偨?jīng)理只管目標(biāo)和結(jié)果不干預(yù)部門(mén)內(nèi)部誰(shuí)做哪一步部門(mén)主管負(fù)責(zé)把目標(biāo)拆成具體動(dòng)作指揮下面的人干活。這樣做的好處是隔離故障某個(gè)局部調(diào)度器出了事故最多影響那個(gè)階段不會(huì)拖垮全鏈路。多級(jí)調(diào)度的難點(diǎn)在于兩級(jí)狀態(tài)怎么同步。局部調(diào)度器上報(bào)給全局的狀態(tài)必須有一個(gè)清晰的信息模型否則會(huì)出現(xiàn)“全局認(rèn)為任務(wù)已經(jīng)完成局部還在跑”的錯(cuò)位。我常用的思路是上級(jí)只下發(fā)目標(biāo)和約束不干預(yù)微觀操作下級(jí)只上報(bào)狀態(tài)和完成事件不試圖影響其他階段。各管各的才能確保邊界清晰不至于兩級(jí)互相打架。3.5 選型對(duì)照表與決策經(jīng)驗(yàn)不同模式的取舍我整理了一張選型對(duì)照表方便直接照著看。模式適用規(guī)模流程確定性靈活性實(shí)現(xiàn)成本主要風(fēng)險(xiǎn)中央調(diào)度器幾十個(gè) Agent 以?xún)?nèi)任意高低中心節(jié)點(diǎn)性能瓶頸工作流/狀態(tài)機(jī)流程穩(wěn)定場(chǎng)景高低中分支膨脹難維護(hù)事件總線(xiàn)分布式協(xié)調(diào)大規(guī)模、長(zhǎng)時(shí)任務(wù)中很高高事件亂序、重復(fù)、丟失多級(jí)調(diào)度大型跨團(tuán)隊(duì)系統(tǒng)中中高兩級(jí)狀態(tài)同步復(fù)雜選型不需要一步到位。我的建議是剛開(kāi)始做多智能體系統(tǒng)直接選中央調(diào)度器跑通之后發(fā)現(xiàn)流程固定再抽工作流規(guī)模真正大了再考慮事件總線(xiàn)和多級(jí)調(diào)度。不要在一開(kāi)始就搭一個(gè)包含全部機(jī)制的“豪華調(diào)度平臺(tái)”大概率只會(huì)得到一個(gè)沒(méi)人能維護(hù)的大泥球。4. 一個(gè)可以抄作業(yè)的總調(diào)度落地樣例4.1 給Agent定義統(tǒng)一的“任務(wù)執(zhí)行協(xié)議”紙上談兵容易但落地時(shí)最關(guān)鍵的是給所有 Agent 定義一個(gè)統(tǒng)一的任務(wù)執(zhí)行協(xié)議。我在項(xiàng)目X里用了非常樸素的 HTTP 接口每個(gè) Agent 暴露一個(gè)POST /execute接口接收統(tǒng)一的請(qǐng)求結(jié)構(gòu)返回統(tǒng)一的結(jié)果結(jié)構(gòu)。請(qǐng)求結(jié)構(gòu)大致長(zhǎng)這樣{ task_id: task_20241218_001, task_type: contract_clause_extraction, payload: { document_url: s3://bucket/contracts/2024-12-18/a.pdf, clause_types: [payment, liability, term] }, context_uri: s3://bucket/shared_context/2024-12-18/contract_001.json, output_schema: { type: object, properties: { clauses: {type: array}, confidence: {type: number} } } }響應(yīng)結(jié)構(gòu)統(tǒng)一為{ task_id: task_20241218_001, status: success, summary: 共提取到 12 個(gè)條款覆蓋支付、責(zé)任、期限三類(lèi)置信度 0.92, result_uri: s3://bucket/results/task_20241218_001.json }這里有兩個(gè)容易被忽略的設(shè)計(jì)點(diǎn)。第一調(diào)度器不直接請(qǐng)求 Agent 返回完整結(jié)果而是只拿 summary引用 result_uri。原因很簡(jiǎn)單完整結(jié)果可能很大如果在調(diào)度器里全部加載再傳遞給下游 Agent上下文很快就會(huì)被塞滿(mǎn)調(diào)度器也會(huì)變成內(nèi)存消耗大戶(hù)。第二output_schema 必須顯式聲明讓 Agent 明確知道自己該輸出什么結(jié)構(gòu)。沒(méi)有這個(gè)約束Agent 自由發(fā)揮返回格式千奇百怪下游解析代碼會(huì)變成一場(chǎng)災(zāi)難。所有 Agent 在接入系統(tǒng)時(shí)還要向調(diào)度器注冊(cè)注冊(cè)名、能力描述、輸入輸出 schema、最大并發(fā)數(shù)、平均處理時(shí)延。注冊(cè)信息是路由模塊的基礎(chǔ)數(shù)據(jù)。4.2 調(diào)度器的核心數(shù)據(jù)結(jié)構(gòu)與路由規(guī)則調(diào)度器內(nèi)部最重要的數(shù)據(jù)結(jié)構(gòu)有兩張表任務(wù)表和能力路由表。任務(wù)表記錄所有任務(wù)的全局狀態(tài)。字段包括task_id、task_type、status、depends_on、assignee、retries、timeout、created_at。能力路由表記錄每個(gè) Agent 能干什么agent_id、capabilities、max_concurrency、current_load、success_rate。任務(wù)進(jìn)來(lái)時(shí)先不看 Agent而是先看它依賴(lài)的任務(wù)是不是都完成了。依賴(lài)沒(méi)完成的任務(wù)直接掛起不參與路由。路由規(guī)則我最初用的是最簡(jiǎn)單的關(guān)鍵詞重合度后來(lái)發(fā)現(xiàn)不夠。一個(gè) Agent 的能力描述寫(xiě)成“合同條款審查”另一個(gè)寫(xiě)成“法律風(fēng)險(xiǎn)分析”關(guān)鍵詞重合度很低但實(shí)際業(yè)務(wù)上承擔(dān)的工作很接近。于是改為“能力描述向量相似度 負(fù)載系數(shù) 歷史成功率”的組合評(píng)分。偽代碼大致如下def route_task(task): candidates [] for agent in agents: if not agent.available(): continue score compute_capability_score(task, agent) # 基于向量相似度 score * (1 - agent.current_load / agent.max_concurrency) score * agent.success_rate candidates.append((score, agent)) if not candidates: return defer_task(task, reasonall_agents_busy) candidates.sort(reverseTrue) return candidates[0][1]這段邏輯并不復(fù)雜但它把一個(gè)關(guān)鍵原則落地了寧可讓任務(wù)排隊(duì)也不要同時(shí)發(fā)給多個(gè) Agent 去搶。沒(méi)有總調(diào)度的時(shí)候任務(wù)廣播出去誰(shuí)響應(yīng)快誰(shuí)干有總調(diào)度以后每次只派給一個(gè) Agent。這個(gè)“唯一指派”原則是減少搶活的有效手段。4.3 依賴(lài)解析與沖突仲裁的判別邏輯依賴(lài)解析我用的是標(biāo)準(zhǔn) DAG 算法。每個(gè)任務(wù)生成時(shí)會(huì)聲明它依賴(lài)哪些任務(wù) ID。調(diào)度器維護(hù)一個(gè) pending 隊(duì)列只把入度為 0 的任務(wù)放出去執(zhí)行。任務(wù)完成以后更新所有下游任務(wù)的依賴(lài)計(jì)數(shù)當(dāng)某個(gè)任務(wù)的所有依賴(lài)都完成時(shí)它就可以進(jìn)入待執(zhí)行隊(duì)列。這個(gè)邏輯用 Python 寫(xiě)起來(lái)非常直觀官方數(shù)據(jù)結(jié)構(gòu)就能實(shí)現(xiàn)。沖突仲裁稍微難一點(diǎn)。一個(gè)典型場(chǎng)景合同金額抽取結(jié)果一個(gè) Agent 從文本里識(shí)別出“100 萬(wàn)”另一個(gè) Agent 從表格附件里識(shí)別出“120 萬(wàn)”。兩個(gè)結(jié)果都不為空并且都聲稱(chēng)置信度 0.85 以上。這時(shí)候調(diào)度器怎么辦我的策略分三步第一步比較置信度取高的一方第二步如果置信度接近比較數(shù)據(jù)的來(lái)源時(shí)間戳取更新的一份第三步如果雙方都相差不大直接不再自動(dòng)決定置為needs_review狀態(tài)進(jìn)入人工復(fù)核隊(duì)列。特別說(shuō)一句人工復(fù)核不是無(wú)奈之舉而是多智能體系統(tǒng)的保險(xiǎn)絲。自動(dòng)流程追求的是效率和覆蓋率但總有少數(shù)邊界情況是自動(dòng)裁決搞不定的。與其讓系統(tǒng)帶著不確定性繼續(xù)往下跑不如把不確定性顯式暴露出來(lái)讓人類(lèi)接手。項(xiàng)目X上線(xiàn)后的真實(shí)數(shù)據(jù)表明進(jìn)入人工復(fù)核的任務(wù)只占總量的 3% 左右但對(duì)最終業(yè)務(wù)準(zhǔn)確率的影響非常大。4.4 超時(shí)、降級(jí)與人工介入通道Agent 是外部依賴(lài)永遠(yuǎn)要假設(shè)它會(huì)失聯(lián)、會(huì)卡死、會(huì)返回亂數(shù)據(jù)。所以超時(shí)和降級(jí)機(jī)制必須設(shè)計(jì)在前面而不是出了問(wèn)題再補(bǔ)。我用的超時(shí)策略不是固定值而是動(dòng)態(tài)計(jì)算單個(gè)任務(wù)的超時(shí)上限為“該 Agent 的歷史平均處理時(shí)延乘以 3再加上 30 秒”。這樣既不會(huì)給慢任務(wù)誤判也不會(huì)讓一個(gè)卡死的任務(wù)占用隊(duì)列太久。超時(shí)之后不馬上標(biāo)記失敗而是重試一次。如果重試仍然超時(shí)再看當(dāng)前是否有替代 Agent。有就轉(zhuǎn)移任務(wù)沒(méi)有就把它降級(jí)成“規(guī)則兜底”比如用簡(jiǎn)單的字符串匹配邏輯先給一個(gè)臨時(shí)結(jié)果并明確標(biāo)記為“低置信度未經(jīng) Agent 驗(yàn)證”。降級(jí)不能靜默發(fā)生所有降級(jí)事件都必須記錄原因輸出到監(jiān)控看板。人工介入通道要做得極其簡(jiǎn)單。我見(jiàn)過(guò)一些系統(tǒng)把人工復(fù)核做成一個(gè)復(fù)雜的審批流結(jié)果一線(xiàn)人員根本不愿意用。實(shí)用性設(shè)計(jì)是一個(gè)只有三列的任務(wù)列表待復(fù)核、已通過(guò)、已駁回通過(guò)或駁回時(shí)寫(xiě)一句話(huà)原因即可。調(diào)度器根據(jù)人工結(jié)論決定繼續(xù)走流程還是終止重跑。5. Agent變多之后這些坑我基本都踩過(guò)5.1 調(diào)度器自己成為性能瓶頸調(diào)度器設(shè)計(jì)不好第一個(gè)坑就是它自己變成瓶頸。我在項(xiàng)目X早期所有任務(wù)都走同步調(diào)用調(diào)度器同時(shí)收到大量請(qǐng)求時(shí)響應(yīng)時(shí)間呈指數(shù)級(jí)上升。排查以后發(fā)現(xiàn)問(wèn)題非常簡(jiǎn)單每個(gè)請(qǐng)求都在等下游 Agent 返回而每個(gè)下游 Agent 的處理耗時(shí)要好幾秒積壓到一定數(shù)量調(diào)度器線(xiàn)程池直接被占滿(mǎn)新請(qǐng)求全部排隊(duì)。解法是把同步鏈路改成異步鏈路調(diào)度器收到外部請(qǐng)求后立刻返回“任務(wù)已受理task_id 為 xxx”后面的執(zhí)行全部在后臺(tái)推進(jìn)前端通過(guò)輪詢(xún)或回調(diào)拿最終結(jié)果。再把調(diào)度器的狀態(tài)存儲(chǔ)從數(shù)據(jù)庫(kù)切換成內(nèi)存緩存加異步落盤(pán)讓狀態(tài)讀寫(xiě)在主鏈路里保持極低的延遲。做這一步之前調(diào)度器的 P95 延遲經(jīng)常飆到十幾秒改完以后P95 穩(wěn)定在幾十毫秒以?xún)?nèi)。調(diào)度器必須輕這是硬道理。5.2 Agent上下文串臺(tái)第二個(gè)我踩過(guò)的大坑是上下文串臺(tái)。最初 my design 太“慷慨”了把所有 Agent 可能用到的資料都塞到一個(gè)共享上下文里每個(gè) Agent 都能讀取全局信息。結(jié)果就是 Agent A 在處理客戶(hù) A 時(shí)不知怎么回事引用了客戶(hù) B 的備注信息Agent B 在處理某合同條款時(shí)參考的是另一個(gè)項(xiàng)目的背景說(shuō)明。排查后發(fā)現(xiàn)是共享上下文的 key 設(shè)計(jì)得太寬泛多個(gè)任務(wù)都在寫(xiě)同一個(gè)緩存鍵后寫(xiě)的覆蓋了先寫(xiě)的。改法很直接把共享上下文改成分任務(wù)切片。每個(gè)任務(wù)只攜帶和它相關(guān)的 payload 片段如果不確定是否需要就給一個(gè) context_uri讓 Agent 按需讀取而不是把整個(gè)數(shù)據(jù)庫(kù)都塞給它。同時(shí)所有上下文寫(xiě)入都必須帶 task_id 前綴確保不同任務(wù)之間物理隔離。這個(gè)改動(dòng)很基礎(chǔ)但它徹底解決了串臺(tái)問(wèn)題。5.3 死鎖和任務(wù)循環(huán)死鎖在任務(wù)依賴(lài)復(fù)雜之后一定會(huì)出現(xiàn)。我在項(xiàng)目里遇到過(guò)一次任務(wù) A 依賴(lài) BB 依賴(lài) CC 又依賴(lài) A鐵三角。三個(gè)任務(wù)在 pending 隊(duì)列里互相等待誰(shuí)也不會(huì)被執(zhí)行整條鏈路直接靜止。最麻煩的是這種死鎖不會(huì)報(bào)錯(cuò)看起來(lái)只是“系統(tǒng)很慢”或者“任務(wù)一直沒(méi)有進(jìn)展”。我后來(lái)在調(diào)度器里加了兩個(gè)機(jī)制。第一個(gè)是提交任務(wù)時(shí)對(duì)整張依賴(lài)圖做環(huán)檢測(cè)。發(fā)現(xiàn)有環(huán)直接拒絕提交并返回錯(cuò)誤。第二個(gè)是為每個(gè)任務(wù)設(shè)置最大等待時(shí)間。一個(gè)任務(wù)在 pending 隊(duì)列里等待超過(guò)閾值就自動(dòng)喚起檢查邏輯判斷是“依賴(lài)還沒(méi)完成”還是“形成了環(huán)”。另外我嚴(yán)格控制了 Agent 的權(quán)限不允許 Agent 在任務(wù)完成后修改自己的依賴(lài)關(guān)系所有依賴(lài)變更只能由調(diào)度器發(fā)起。這個(gè)紀(jì)律讓任務(wù)循環(huán)的概率大幅下降。5.4 不可觀測(cè)才是最大的隱患加調(diào)度器不是為了“加一個(gè)黑盒”而是要讓系統(tǒng)變得可觀測(cè)。因?yàn)樗腥蝿?wù)都從調(diào)度器經(jīng)過(guò)調(diào)度器天然擁有全鏈路信息。如果不好好利用這些信息等于守著金礦不挖。我在項(xiàng)目X里為每個(gè)任務(wù)生成了一個(gè)全局唯一的 task_id并強(qiáng)制所有日志、所有 Agent 的調(diào)用記錄、所有回調(diào)事件都帶上這個(gè) ID。出現(xiàn)任何問(wèn)題輸入 task_id就能拉出一條完整的任務(wù)時(shí)間線(xiàn)什么時(shí)候創(chuàng)建、什么時(shí)候進(jìn)入隊(duì)列、分給了哪個(gè) Agent、Agent 返回了什么摘要、下一步去了哪里。沒(méi)有這套鏈路追蹤排查多 Agent 問(wèn)題基本上靠猜猜一次兩次還行猜多了就會(huì)漏真實(shí)原因。我還做了一個(gè)簡(jiǎn)單的統(tǒng)計(jì)分析按 Agent 維度統(tǒng)計(jì)成功率、平均處理時(shí)長(zhǎng)、平均置信度。每周看一眼這個(gè)表哪個(gè) Agent 能力退化了一眼就能發(fā)現(xiàn)。曾經(jīng)有一個(gè) Agent 因?yàn)橥獠拷涌诟陌娉晒β蕪?0.95 掉到 0.6就是靠這張表發(fā)現(xiàn)的省去了很多用戶(hù)投訴才發(fā)現(xiàn)的尷尬。5.5 狀態(tài)管理的取舍集中狀態(tài) vs 分散狀態(tài)最后一個(gè)經(jīng)常討論的問(wèn)題狀態(tài)應(yīng)該放在調(diào)度器里還是分散在各自 Agent 里我的實(shí)踐經(jīng)驗(yàn)是以調(diào)度器狀態(tài)為唯一事實(shí)來(lái)源。Agent 可以保留自己的內(nèi)部狀態(tài)但那些狀態(tài)不會(huì)被當(dāng)作權(quán)威依據(jù)。任務(wù)是否完成、結(jié)果是否合法、下一步是什么都只能看調(diào)度器里存的狀態(tài)。這樣能保證全局視圖一致。當(dāng)然集中狀態(tài)也有自己的問(wèn)題比如存儲(chǔ)壓力。但多智能體系統(tǒng)的任務(wù)數(shù)量通常遠(yuǎn)沒(méi)有想象中的大幾十個(gè)任務(wù)并發(fā)已經(jīng)是中等規(guī)模了。用一張?jiān)O(shè)計(jì)良好的表或者緩存來(lái)維護(hù)狀態(tài)完全不是問(wèn)題。真正需要警惕的是“兩邊都寫(xiě)狀態(tài)然后互相覆蓋”。我見(jiàn)過(guò)的最嚴(yán)重的狀態(tài)事故就是 Agent 自己把任務(wù)改成“已完成”而調(diào)度器還認(rèn)為它在“運(yùn)行中”導(dǎo)致外部看到兩個(gè)矛盾的狀態(tài)。后來(lái)我在協(xié)議里明確規(guī)定Agent 不能寫(xiě)全局狀態(tài)只能上報(bào)結(jié)果最終狀態(tài)更新必須由調(diào)度器執(zhí)行。寧可多一次網(wǎng)絡(luò)調(diào)用也不能讓狀態(tài)多源寫(xiě)入。收尾最后再分享一點(diǎn)實(shí)際體會(huì)做了這么久的多智能體系統(tǒng)我最大的體會(huì)是總調(diào)度不是給 Agent 戴上枷鎖而是讓每個(gè) Agent 可以安心只做自己擅長(zhǎng)的事。在沒(méi)有調(diào)度器的系統(tǒng)里每個(gè) Agent 都像會(huì)議桌上同時(shí)發(fā)言的人所有人都很聰明但沒(méi)有人聽(tīng)得清完整議題。加了總調(diào)度之后會(huì)場(chǎng)里多了一個(gè)主持人有人負(fù)責(zé)議題拆分有人負(fù)責(zé)控制發(fā)言順序有人負(fù)責(zé)確認(rèn)結(jié)論一致沖突發(fā)生時(shí)還有一套明確的三方裁決機(jī)制。整個(gè)系統(tǒng)從“聰明人開(kāi)混亂會(huì)議”變成了“有主持人的高效工作坊”。如果你現(xiàn)在正被多 Agent 的混亂狀態(tài)困擾我的建議是不要一步到位。先把任務(wù)入口統(tǒng)一引入一個(gè)簡(jiǎn)單的隊(duì)列和路由模塊觀察一周再看哪里的協(xié)作問(wèn)題最突出。穩(wěn)定之后再逐步加入依賴(lài)編排、沖突仲裁、人工復(fù)核通道。一次只加一個(gè)機(jī)制驗(yàn)證井井有條之后再繼續(xù)比一次上一整套調(diào)度平臺(tái)要穩(wěn)妥得多。這套思路救過(guò)我的項(xiàng)目也希望它能幫你少踩幾個(gè)坑。