作實(shí)戰(zhàn):從架構(gòu)設(shè)計(jì)到Handoff機(jī)制與Skill實(shí)現(xiàn))
1. 多 Agent 協(xié)作到底在解決什么問(wèn)題1.1 從單兵作戰(zhàn)到團(tuán)隊(duì)配合的必然轉(zhuǎn)變先說(shuō)一個(gè)我自己的真實(shí)經(jīng)歷。去年我接手了一個(gè)需求要在一周內(nèi)完成一個(gè)包含數(shù)據(jù)清洗、特征工程、模型訓(xùn)練、報(bào)告生成和可視化看板的完整項(xiàng)目。如果按傳統(tǒng)方式我一個(gè)人從頭寫到尾光是調(diào)試數(shù)據(jù)管道就能耗掉三天。后來(lái)我嘗試把這套流程拆成四個(gè)獨(dú)立的 Agent 來(lái)跑——一個(gè)專門負(fù)責(zé)數(shù)據(jù)清洗一個(gè)負(fù)責(zé)特征工程一個(gè)負(fù)責(zé)模型訓(xùn)練和評(píng)估最后一個(gè)負(fù)責(zé)生成報(bào)告和圖表。結(jié)果三天就交付了而且每個(gè)環(huán)節(jié)的質(zhì)量比我一個(gè)人硬扛還要穩(wěn)定。這就是多 Agent 協(xié)作最樸素的價(jià)值把復(fù)雜任務(wù)拆解成多個(gè)獨(dú)立但互相配合的執(zhí)行單元每個(gè)單元專注做好一件事通過(guò)明確的交接協(xié)議串聯(lián)起來(lái)。很多人第一次聽(tīng)到“多 Agent 協(xié)作”會(huì)覺(jué)得這是個(gè)很玄的概念其實(shí)你完全可以把它理解成一個(gè)小型軟件團(tuán)隊(duì)。團(tuán)隊(duì)里有前端、后端、測(cè)試、產(chǎn)品每個(gè)人有自己的職責(zé)邊界有明確的輸入和輸出有約定的溝通方式。多 Agent 系統(tǒng)也是一樣的道理只不過(guò)團(tuán)隊(duì)成員從人變成了 AI 實(shí)例。1.2 什么場(chǎng)景下真的需要多 Agent不是所有任務(wù)都值得上多 Agent。我踩過(guò)的坑告訴我下面這幾類場(chǎng)景才是多 Agent 真正能發(fā)揮價(jià)值的地方任務(wù)鏈路長(zhǎng)且環(huán)節(jié)異構(gòu)比如從原始數(shù)據(jù)到最終報(bào)告中間要經(jīng)過(guò)清洗、分析、建模、寫作等多個(gè)性質(zhì)完全不同的階段。用一個(gè) Agent 從頭做到尾它很容易在某個(gè)環(huán)節(jié)“忘記”前面的約束或者在風(fēng)格上前后不一致。需要多視角交叉驗(yàn)證比如代碼審查場(chǎng)景一個(gè) Agent 寫代碼另一個(gè) Agent 專門挑毛病第三個(gè) Agent 負(fù)責(zé)跑測(cè)試。這種“對(duì)抗式”協(xié)作能顯著降低錯(cuò)誤率。單次上下文窗口不夠用當(dāng)任務(wù)涉及大量文檔、代碼庫(kù)或數(shù)據(jù)集時(shí)單個(gè) Agent 的上下文很容易被撐爆。拆成多個(gè) Agent 后每個(gè) Agent 只加載自己需要的那部分信息效率反而更高。需要并行加速有些子任務(wù)之間沒(méi)有依賴關(guān)系比如同時(shí)生成多個(gè)模塊的文檔、同時(shí)測(cè)試多個(gè)接口。多 Agent 并行跑時(shí)間能壓縮到原來(lái)的幾分之一。反過(guò)來(lái)如果你的任務(wù)就是“幫我寫一段正則表達(dá)式”或者“解釋一下這個(gè)報(bào)錯(cuò)”那完全沒(méi)必要上多 Agent單個(gè) Agent 甚至直接問(wèn)搜索引擎更快。工具選型的第一原則永遠(yuǎn)是夠用就好別為了炫技而過(guò)度設(shè)計(jì)。1.3 多 Agent 協(xié)作的核心挑戰(zhàn)多 Agent 聽(tīng)起來(lái)很美但真正落地時(shí)會(huì)遇到幾個(gè)非?,F(xiàn)實(shí)的問(wèn)題第一個(gè)是上下文傳遞。Agent A 做完數(shù)據(jù)清洗后怎么把結(jié)果和必要的元信息傳給 Agent B如果傳得太多B 的上下文被撐爆如果傳得太少B 缺少關(guān)鍵信息導(dǎo)致輸出質(zhì)量下降。這個(gè)平衡點(diǎn)需要反復(fù)調(diào)試。第二個(gè)是職責(zé)邊界模糊。我見(jiàn)過(guò)很多失敗的多 Agent 項(xiàng)目根本原因就是兩個(gè) Agent 的職責(zé)有重疊導(dǎo)致互相“踢皮球”或者重復(fù)勞動(dòng)。比如一個(gè) Agent 負(fù)責(zé)“分析數(shù)據(jù)”另一個(gè)負(fù)責(zé)“生成洞察”這兩個(gè)職責(zé)在實(shí)際操作中很難劃清界限。第三個(gè)是錯(cuò)誤傳播。如果 Agent A 的輸出有錯(cuò)誤Agent B 基于錯(cuò)誤輸入繼續(xù)工作錯(cuò)誤會(huì)被逐級(jí)放大到最后你拿到一份看起來(lái)完整但完全不可信的結(jié)果。所以多 Agent 系統(tǒng)里必須有校驗(yàn)和回滾機(jī)制。第四個(gè)是協(xié)調(diào)開(kāi)銷。Agent 之間通信本身也要消耗資源和時(shí)間。如果拆得太細(xì)協(xié)調(diào)開(kāi)銷可能超過(guò)任務(wù)本身的收益。我一般建議初次嘗試時(shí)控制在 3 到 5 個(gè) Agent 之間跑通后再根據(jù)實(shí)際瓶頸決定是否繼續(xù)拆分。理解了這些挑戰(zhàn)接下來(lái)我們進(jìn)入具體的方案設(shè)計(jì)。2. 多 Agent 協(xié)作的整體架構(gòu)設(shè)計(jì)2.1 三種主流協(xié)作模式及選型依據(jù)在實(shí)際項(xiàng)目中我總結(jié)出三種最常用的多 Agent 協(xié)作模式每種模式適合不同的任務(wù)類型。第一種是流水線模式Pipeline。Agent 按順序排列前一個(gè)的輸出是后一個(gè)的輸入像工廠流水線一樣。這種模式最適合任務(wù)鏈路清晰、階段劃分明確的場(chǎng)景比如“數(shù)據(jù)清洗 → 特征工程 → 模型訓(xùn)練 → 報(bào)告生成”。優(yōu)點(diǎn)是邏輯簡(jiǎn)單、易于調(diào)試缺點(diǎn)是如果中間某個(gè)環(huán)節(jié)出錯(cuò)整個(gè)鏈路都要重跑。第二種是主從模式Orchestrator-Worker。有一個(gè)“主 Agent”負(fù)責(zé)拆解任務(wù)、分配工作、匯總結(jié)果多個(gè)“從 Agent”各自執(zhí)行子任務(wù)。這種模式適合任務(wù)可以并行拆分的場(chǎng)景比如同時(shí)生成多個(gè)模塊的代碼。主 Agent 相當(dāng)于項(xiàng)目經(jīng)理從 Agent 相當(dāng)于執(zhí)行者。優(yōu)點(diǎn)是并行效率高缺點(diǎn)是主 Agent 的調(diào)度邏輯需要精心設(shè)計(jì)否則容易成為瓶頸。第三種是辯論模式Debate。多個(gè) Agent 對(duì)同一個(gè)問(wèn)題給出各自的答案然后通過(guò)交叉評(píng)審或投票選出最優(yōu)解。這種模式適合需要高質(zhì)量決策的場(chǎng)景比如代碼審查、方案評(píng)審。優(yōu)點(diǎn)是能顯著降低單點(diǎn)錯(cuò)誤缺點(diǎn)是資源消耗成倍增加。我個(gè)人的選型經(jīng)驗(yàn)是這樣的模式適合場(chǎng)景資源消耗實(shí)現(xiàn)難度推薦指數(shù)流水線階段清晰的線性任務(wù)中等低五星主從可并行拆分的任務(wù)較高中四星辯論高質(zhì)量決策場(chǎng)景高高三星對(duì)于大多數(shù)初次嘗試多 Agent 的團(tuán)隊(duì)我強(qiáng)烈建議從流水線模式開(kāi)始。它的心智負(fù)擔(dān)最小調(diào)試起來(lái)最直觀而且能覆蓋大部分實(shí)際需求。2.2 為什么我選擇 Handoff 作為核心交接機(jī)制在多 Agent 協(xié)作中Agent 之間的“交接”是最關(guān)鍵的環(huán)節(jié)。我試過(guò)幾種不同的交接方式最后穩(wěn)定在Handoff機(jī)制上。Handoff 的核心思想很簡(jiǎn)單當(dāng)前 Agent 完成自己的任務(wù)后不是直接把原始輸出丟給下一個(gè) Agent而是生成一份結(jié)構(gòu)化的“交接文檔”包含任務(wù)摘要、關(guān)鍵決策、未解決問(wèn)題和下一步建議。下一個(gè) Agent 拿到這份文檔后能快速理解上下文而不需要重新閱讀所有原始材料。我舉個(gè)例子說(shuō)明為什么 Handoff 比直接傳遞原始輸出更好。假設(shè) Agent A 負(fù)責(zé)數(shù)據(jù)清洗它處理了 10 萬(wàn)條數(shù)據(jù)刪除了 3000 條異常值填充了 500 個(gè)缺失值。如果直接把清洗后的數(shù)據(jù)丟給 Agent BB 完全不知道中間發(fā)生了什么可能會(huì)對(duì)某些數(shù)據(jù)分布感到困惑。但如果 A 生成一份 Handoff 文檔寫明“刪除了 3000 條異常值原因是超出 3 倍標(biāo)準(zhǔn)差填充了 500 個(gè)缺失值使用中位數(shù)填充”B 就能在理解數(shù)據(jù)來(lái)源的基礎(chǔ)上繼續(xù)工作。Handoff 文檔我一般要求包含以下幾個(gè)字段任務(wù)摘要用兩三句話說(shuō)明這個(gè)環(huán)節(jié)做了什么。關(guān)鍵決策列出所有影響后續(xù)環(huán)節(jié)的重要選擇以及選擇理由。輸出物清單明確列出傳遞給下一個(gè) Agent 的文件、數(shù)據(jù)或代碼。未解決問(wèn)題如果有遺留問(wèn)題明確標(biāo)注出來(lái)提醒下游 Agent 注意。下一步建議基于當(dāng)前進(jìn)展給下一個(gè) Agent 提供行動(dòng)建議。這套機(jī)制看起來(lái)增加了額外工作但實(shí)際跑下來(lái)它節(jié)省的溝通成本遠(yuǎn)遠(yuǎn)超過(guò)生成文檔的成本。尤其是在多輪迭代中Handoff 文檔就是整個(gè)系統(tǒng)的“記憶”能有效防止上下文丟失。2.3 AGENTS.md讓協(xié)作規(guī)則可配置、可復(fù)用多 Agent 系統(tǒng)跑起來(lái)后最大的痛點(diǎn)之一是規(guī)則散落在各個(gè) Agent 的提示詞里改一處要改好幾處而且容易漏改。后來(lái)我引入了AGENTS.md文件來(lái)集中管理協(xié)作規(guī)則。AGENTS.md本質(zhì)上是一個(gè)配置文件里面定義了每個(gè) Agent 的角色、職責(zé)、輸入輸出格式、交接規(guī)則和約束條件。所有 Agent 在啟動(dòng)時(shí)都會(huì)讀取這個(gè)文件確保大家對(duì)規(guī)則的理解是一致的。我通常把AGENTS.md分成幾個(gè)區(qū)塊# AGENTS.md ## 全局規(guī)則 - 所有 Agent 輸出必須使用 Markdown 格式 - 所有 Agent 必須在輸出末尾附上 Handoff 文檔 - 任何 Agent 發(fā)現(xiàn)上游輸入有問(wèn)題必須立即中止并報(bào)告 ## Agent 定義 ### Agent A: 數(shù)據(jù)清洗 - 職責(zé)讀取原始數(shù)據(jù)處理缺失值、異常值和重復(fù)值 - 輸入raw_data.csv - 輸出cleaned_data.csv handoff_a.md - 約束不得修改原始數(shù)據(jù)文件 ### Agent B: 特征工程 - 職責(zé)基于清洗后的數(shù)據(jù)生成特征 - 輸入cleaned_data.csv handoff_a.md - 輸出features.csv handoff_b.md - 約束必須記錄每個(gè)特征的生成邏輯 ## 交接規(guī)則 - 上游 Agent 必須在 Handoff 文檔中明確標(biāo)注輸出物的路徑和格式 - 下游 Agent 在開(kāi)始工作前必須驗(yàn)證輸入物的完整性和格式 - 如果驗(yàn)證失敗下游 Agent 必須回退給上游 Agent 并說(shuō)明原因有了這個(gè)文件整個(gè)系統(tǒng)的規(guī)則就變得透明且可維護(hù)。新增一個(gè) Agent 時(shí)只需要在AGENTS.md里加一段定義其他 Agent 不需要做任何修改。這比把規(guī)則硬編碼在每個(gè) Agent 的提示詞里要優(yōu)雅得多。2.4 上下文變量的設(shè)計(jì)與傳遞多 Agent 協(xié)作中上下文變量的設(shè)計(jì)直接決定了系統(tǒng)的穩(wěn)定性和效率。我一般把上下文變量分成三類第一類是全局變量比如項(xiàng)目名稱、目標(biāo)描述、輸出目錄、時(shí)間戳。這些變量在所有 Agent 之間共享每個(gè) Agent 都能讀取但只有主 Agent 有權(quán)限修改。第二類是階段變量比如當(dāng)前處理的數(shù)據(jù)文件路徑、上一步的統(tǒng)計(jì)摘要、中間產(chǎn)物的版本號(hào)。這些變量隨著任務(wù)推進(jìn)而更新每個(gè) Agent 完成工作后負(fù)責(zé)更新自己相關(guān)的部分。第三類是局部變量只在單個(gè) Agent 內(nèi)部使用比如臨時(shí)文件路徑、調(diào)試信息、中間計(jì)算結(jié)果。這些變量不參與交接任務(wù)完成后自動(dòng)清理。我踩過(guò)的一個(gè)坑是早期我把所有變量都放在一個(gè)全局字典里結(jié)果 Agent 之間互相覆蓋導(dǎo)致數(shù)據(jù)錯(cuò)亂。后來(lái)改成分類管理后問(wèn)題就消失了。上下文變量管理的核心原則是誰(shuí)產(chǎn)生誰(shuí)負(fù)責(zé)誰(shuí)修改誰(shuí)記錄。3. 核心 Skill 的設(shè)計(jì)與實(shí)現(xiàn)細(xì)節(jié)3.1 什么是 Skill為什么它比普通提示詞更強(qiáng)在多 Agent 系統(tǒng)里Skill 是我用來(lái)封裝“可復(fù)用能力”的基本單元。你可以把它理解成一個(gè)函數(shù)有明確的輸入、有確定的處理邏輯、有規(guī)范的輸出。和普通提示詞相比Skill 有幾個(gè)顯著優(yōu)勢(shì)可復(fù)用同一個(gè) Skill 可以被多個(gè) Agent 調(diào)用不需要重復(fù)編寫提示詞??蓽y(cè)試Skill 的輸入輸出是明確的可以單獨(dú)寫測(cè)試用例驗(yàn)證??山M合多個(gè) Skill 可以串聯(lián)或并聯(lián)形成更復(fù)雜的能力??砂姹竟芾鞸kill 可以像代碼一樣進(jìn)行版本控制方便追蹤變更。我目前維護(hù)的 Skill 庫(kù)里有幾十個(gè)常用 Skill覆蓋了數(shù)據(jù)讀取、格式轉(zhuǎn)換、代碼生成、質(zhì)量檢查、報(bào)告撰寫等常見(jiàn)需求。每次啟動(dòng)新項(xiàng)目時(shí)我只需要從庫(kù)里挑選合適的 Skill 組合起來(lái)就能快速搭建出一個(gè)可用的多 Agent 系統(tǒng)。3.2 一個(gè)強(qiáng)大協(xié)作 Skill 的完整結(jié)構(gòu)下面我以一個(gè)實(shí)際在用的“協(xié)作調(diào)度 Skill”為例拆解它的完整結(jié)構(gòu)。這個(gè) Skill 的作用是接收一個(gè)任務(wù)描述自動(dòng)拆解成子任務(wù)分配給對(duì)應(yīng)的 Agent并管理整個(gè)執(zhí)行流程。name: collaboration-orchestrator version: 2.3.0 description: 多 Agent 協(xié)作調(diào)度 Skill負(fù)責(zé)任務(wù)拆解、分配、監(jiān)控和結(jié)果匯總 inputs: - name: task_description type: string required: true description: 待完成的任務(wù)描述 - name: available_agents type: list required: true description: 可用 Agent 列表及其能力描述 - name: max_rounds type: integer default: 5 description: 最大迭代輪數(shù) outputs: - name: final_result type: string description: 最終匯總結(jié)果 - name: execution_log type: object description: 完整執(zhí)行日志包含每輪的任務(wù)分配和結(jié)果 steps: - name: analyze_task action: 分析任務(wù)描述識(shí)別關(guān)鍵環(huán)節(jié)和依賴關(guān)系 - name: decompose action: 將任務(wù)拆解成子任務(wù)標(biāo)注每個(gè)子任務(wù)的輸入輸出 - name: assign action: 根據(jù) Agent 能力匹配子任務(wù) - name: execute action: 按依賴順序執(zhí)行子任務(wù)收集結(jié)果 - name: validate action: 校驗(yàn)每個(gè)子任務(wù)的輸出質(zhì)量 - name: aggregate action: 匯總所有子任務(wù)結(jié)果生成最終輸出 constraints: - 每個(gè)子任務(wù)必須有明確的驗(yàn)收標(biāo)準(zhǔn) - 如果某個(gè)子任務(wù)失敗最多重試 2 次 - 如果重試后仍失敗記錄問(wèn)題并繼續(xù)執(zhí)行不依賴該子任務(wù)的部分這個(gè) Skill 的設(shè)計(jì)有幾個(gè)關(guān)鍵點(diǎn)值得說(shuō)明第一輸入輸出明確。每個(gè)字段都有類型和描述調(diào)用方不需要猜測(cè)怎么傳參。第二步驟可追蹤。每個(gè)步驟都有名字和動(dòng)作描述執(zhí)行過(guò)程中可以精確知道當(dāng)前進(jìn)行到哪一步。第三約束條件清晰。什么情況下重試、什么情況下跳過(guò)、什么情況下中止都有明確規(guī)定。第四版本化管理。version字段讓我能追蹤 Skill 的演進(jìn)歷史出問(wèn)題時(shí)可以快速回滾到上一個(gè)穩(wěn)定版本。3.3 Skill 的注冊(cè)、發(fā)現(xiàn)與調(diào)用機(jī)制Skill 寫好后需要一套機(jī)制讓 Agent 能夠發(fā)現(xiàn)并調(diào)用它。我采用的是“注冊(cè)中心 按需加載”的方案。注冊(cè)中心本質(zhì)上是一個(gè)索引文件記錄了所有可用 Skill 的名稱、版本、描述和入口路徑。Agent 啟動(dòng)時(shí)先讀取注冊(cè)中心了解當(dāng)前有哪些 Skill 可用。當(dāng) Agent 需要某個(gè)能力時(shí)根據(jù)描述匹配到對(duì)應(yīng)的 Skill然后加載并調(diào)用。{ skills: [ { name: collaboration-orchestrator, version: 2.3.0, path: ./skills/orchestrator, tags: [協(xié)作, 調(diào)度, 任務(wù)拆解] }, { name: data-cleaner, version: 1.5.2, path: ./skills/data-cleaner, tags: [數(shù)據(jù), 清洗, 預(yù)處理] }, { name: report-generator, version: 3.1.0, path: ./skills/report-generator, tags: [報(bào)告, 寫作, 匯總] } ] }這種設(shè)計(jì)的好處是解耦。Agent 不需要硬編碼任何 Skill 的路徑只需要根據(jù)標(biāo)簽或描述來(lái)匹配。新增 Skill 時(shí)只需要在注冊(cè)中心加一條記錄所有 Agent 都能立即發(fā)現(xiàn)并使用它。我踩過(guò)的一個(gè)坑是早期我把 Skill 的調(diào)用邏輯直接寫在 Agent 的提示詞里結(jié)果每次新增 Skill 都要修改所有 Agent 的提示詞維護(hù)成本極高。改成注冊(cè)中心機(jī)制后這個(gè)問(wèn)題徹底解決了。3.4 協(xié)作 Skill 中的錯(cuò)誤處理與重試策略多 Agent 系統(tǒng)跑起來(lái)后錯(cuò)誤是常態(tài)而不是例外。我的協(xié)作 Skill 里內(nèi)置了一套分層的錯(cuò)誤處理策略第一層是輸入校驗(yàn)。每個(gè) Skill 在執(zhí)行前先校驗(yàn)輸入是否符合預(yù)期格式。如果不符合立即返回錯(cuò)誤不進(jìn)入實(shí)際處理邏輯。這能攔截掉大部分低級(jí)錯(cuò)誤。第二層是執(zhí)行監(jiān)控。Skill 執(zhí)行過(guò)程中記錄關(guān)鍵節(jié)點(diǎn)的狀態(tài)。如果某個(gè)步驟超時(shí)或返回異常立即中止并記錄現(xiàn)場(chǎng)信息。第三層是重試機(jī)制。對(duì)于可恢復(fù)的錯(cuò)誤比如網(wǎng)絡(luò)超時(shí)、臨時(shí)資源不足自動(dòng)重試最多 2 次。重試時(shí)適當(dāng)調(diào)整參數(shù)比如增加超時(shí)時(shí)間或降低并發(fā)數(shù)。第四層是降級(jí)處理。如果重試后仍然失敗根據(jù)預(yù)設(shè)的降級(jí)策略處理。比如某個(gè)數(shù)據(jù)源不可用就使用緩存數(shù)據(jù)某個(gè) Agent 不可用就把它的任務(wù)分配給備用 Agent。第五層是人工介入。如果所有自動(dòng)處理都失敗系統(tǒng)會(huì)生成一份詳細(xì)的錯(cuò)誤報(bào)告包含失敗環(huán)節(jié)、錯(cuò)誤信息、已嘗試的解決方案和建議的人工處理步驟。這套分層策略的核心思想是能自動(dòng)恢復(fù)的自動(dòng)恢復(fù)不能自動(dòng)恢復(fù)的優(yōu)雅降級(jí)實(shí)在不行才找人。實(shí)際跑下來(lái)90% 以上的錯(cuò)誤都能在前三層解決需要人工介入的情況很少。4. 完整實(shí)操流程從零搭建一個(gè)多 Agent 協(xié)作系統(tǒng)4.1 環(huán)境準(zhǔn)備與目錄結(jié)構(gòu)規(guī)劃在開(kāi)始搭建之前先把目錄結(jié)構(gòu)規(guī)劃好。我一般用這樣的結(jié)構(gòu)project/ ├── AGENTS.md # 協(xié)作規(guī)則配置 ├── skills/ # Skill 庫(kù) │ ├── registry.json # Skill 注冊(cè)中心 │ ├── orchestrator/ # 協(xié)作調(diào)度 Skill │ ├──># Agent A: 數(shù)據(jù)準(zhǔn)備者 ## 角色 你是一個(gè)數(shù)據(jù)準(zhǔn)備專家負(fù)責(zé)將原始數(shù)據(jù)轉(zhuǎn)化為可供分析使用的干凈數(shù)據(jù)集。 ## 職責(zé) - 讀取原始數(shù)據(jù)文件 - 處理缺失值、異常值和重復(fù)值 - 統(tǒng)一數(shù)據(jù)格式和編碼 - 生成數(shù)據(jù)質(zhì)量報(bào)告 ## 輸入 - 原始數(shù)據(jù)文件路徑 - 數(shù)據(jù)字典如果有 ## 輸出 - 清洗后的數(shù)據(jù)文件 - 數(shù)據(jù)質(zhì)量報(bào)告 - Handoff 文檔 ## 約束 - 不得修改原始數(shù)據(jù)文件 - 所有清洗操作必須記錄在 Handoff 文檔中 - 如果數(shù)據(jù)質(zhì)量問(wèn)題超過(guò)閾值必須中止并報(bào)告 ## 交接規(guī)則 完成工作后生成 handoff_a.md包含 - 任務(wù)摘要 - 關(guān)鍵決策及理由 - 輸出物清單 - 未解決問(wèn)題 - 對(duì) Agent B 的建議這種定義方式的好處是邊界清晰。每個(gè) Agent 知道自己該做什么、不該做什么、做到什么程度算完成。實(shí)際跑下來(lái)職責(zé)邊界清晰的系統(tǒng)出錯(cuò)率比模糊定義的系統(tǒng)低很多。4.3 編寫協(xié)作 Skill 的完整代碼下面是一個(gè)簡(jiǎn)化版的協(xié)作調(diào)度 Skill 的核心代碼用 Python 實(shí)現(xiàn)import json import yaml from pathlib import Path from datetime import datetime class CollaborationOrchestrator: def __init__(self, config_path, registry_path): self.config yaml.safe_load(Path(config_path).read_text()) self.registry json.loads(Path(registry_path).read_text()) self.execution_log [] self.handoffs {} def analyze_task(self, task_description): 分析任務(wù)識(shí)別關(guān)鍵環(huán)節(jié) # 實(shí)際實(shí)現(xiàn)中這里會(huì)調(diào)用 LLM 做任務(wù)分析 # 簡(jiǎn)化版根據(jù)關(guān)鍵詞匹配 stages [] if 數(shù)據(jù) in task_description or 清洗 in task_description: stages.append(data_preparation) if 分析 in task_description or 統(tǒng)計(jì) in task_description: stages.append(analysis) if 報(bào)告 in task_description or 匯總 in task_description: stages.append(reporting) return stages def decompose(self, task_description, stages): 將任務(wù)拆解成子任務(wù) subtasks [] for i, stage in enumerate(stages): subtask { id: ftask_{i1}, stage: stage, description: f執(zhí)行 {stage} 階段的工作, depends_on: [ftask_{i}] if i 0 else [], status: pending } subtasks.append(subtask) return subtasks def assign(self, subtasks): 根據(jù) Agent 能力匹配子任務(wù) agent_mapping { data_preparation: agent_a, analysis: agent_b, reporting: agent_c } for subtask in subtasks: subtask[assigned_to] agent_mapping.get(subtask[stage], unknown) return subtasks def execute(self, subtasks): 按依賴順序執(zhí)行子任務(wù) completed set() max_rounds self.config.get(max_rounds, 5) for round_num in range(max_rounds): progress False for subtask in subtasks: if subtask[status] ! pending: continue if not all(dep in completed for dep in subtask[depends_on]): continue # 執(zhí)行子任務(wù) result self._run_subtask(subtask) subtask[status] completed if result[success] else failed subtask[result] result if result[success]: completed.add(subtask[id]) self.handoffs[subtask[id]] result.get(handoff, {}) else: # 重試邏輯 if subtask.get(retry_count, 0) 2: subtask[retry_count] subtask.get(retry_count, 0) 1 subtask[status] pending progress True self._log(subtask) if not progress: break return subtasks def _run_subtask(self, subtask): 實(shí)際執(zhí)行子任務(wù)這里需要接入具體的 Agent 調(diào)用 # 簡(jiǎn)化版返回模擬結(jié)果 return { success: True, output: f{subtask[stage]} 完成, handoff: { task_id: subtask[id], summary: f完成 {subtask[stage]} 階段, timestamp: datetime.now().isoformat() } } def validate(self, subtasks): 校驗(yàn)子任務(wù)輸出質(zhì)量 issues [] for subtask in subtasks: if subtask[status] ! completed: issues.append(f{subtask[id]} 未完成) elif not subtask.get(result, {}).get(output): issues.append(f{subtask[id]} 輸出為空) return issues def aggregate(self, subtasks): 匯總所有子任務(wù)結(jié)果 final_result { task_summary: 多 Agent 協(xié)作任務(wù)完成, subtask_results: [ { id: s[id], stage: s[stage], status: s[status], output: s.get(result, {}).get(output, ) } for s in subtasks ], handoffs: self.handoffs, execution_log: self.execution_log } return final_result def _log(self, subtask): 記錄執(zhí)行日志 self.execution_log.append({ timestamp: datetime.now().isoformat(), task_id: subtask[id], stage: subtask[stage], status: subtask[status], assigned_to: subtask.get(assigned_to) }) def run(self, task_description): 完整執(zhí)行流程 stages self.analyze_task(task_description) subtasks self.decompose(task_description, stages) subtasks self.assign(subtasks) subtasks self.execute(subtasks) issues self.validate(subtasks) result self.aggregate(subtasks) result[issues] issues return result這段代碼的核心邏輯是分析 → 拆解 → 分配 → 執(zhí)行 → 校驗(yàn) → 匯總。每一步都有明確的輸入輸出方便調(diào)試和擴(kuò)展。實(shí)際使用時(shí)_run_subtask方法需要接入真實(shí)的 Agent 調(diào)用邏輯。我一般會(huì)在這里調(diào)用 LLM API把 Agent 的提示詞和當(dāng)前上下文傳進(jìn)去拿到輸出后再解析成結(jié)構(gòu)化結(jié)果。4.4 運(yùn)行、監(jiān)控與結(jié)果驗(yàn)證系統(tǒng)跑起來(lái)后監(jiān)控是必不可少的。我一般關(guān)注幾個(gè)關(guān)鍵指標(biāo)每個(gè)子任務(wù)的執(zhí)行時(shí)間如果某個(gè)子任務(wù)耗時(shí)異常說(shuō)明可能遇到了問(wèn)題。重試次數(shù)重試次數(shù)過(guò)多說(shuō)明輸入質(zhì)量或 Skill 邏輯有問(wèn)題。Handoff 文檔的完整性如果 Handoff 文檔缺少關(guān)鍵字段下游 Agent 會(huì)受影響。最終輸出的質(zhì)量這是最直觀的指標(biāo)可以通過(guò)人工抽檢或自動(dòng)校驗(yàn)來(lái)評(píng)估。我通常會(huì)在logs/目錄下生成一份詳細(xì)的執(zhí)行日志格式如下{ run_id: 20250115_143022, task: 生成一份銷售數(shù)據(jù)分析報(bào)告, start_time: 2025-01-15T14:30:22, end_time: 2025-01-15T14:35:47, total_duration_seconds: 325, subtasks: [ { id: task_1, stage: data_preparation, status: completed, duration_seconds: 120, retry_count: 0 }, { id: task_2, stage: analysis, status: completed, duration_seconds: 150, retry_count: 1 }, { id: task_3, stage: reporting, status: completed, duration_seconds: 55, retry_count: 0 } ], issues: [] }有了這份日志出問(wèn)題時(shí)可以快速定位到具體環(huán)節(jié)。比如上面這個(gè)例子task_2重試了一次說(shuō)明分析階段可能遇到了數(shù)據(jù)格式問(wèn)題下次可以針對(duì)性優(yōu)化。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄5.1 Agent 之間上下文丟失怎么辦這是多 Agent 系統(tǒng)里最常見(jiàn)的問(wèn)題。表現(xiàn)是下游 Agent 的輸出明顯偏離了上游的意圖或者重復(fù)問(wèn)了上游已經(jīng)解決的問(wèn)題。根本原因通常是 Handoff 文檔寫得太簡(jiǎn)略或者關(guān)鍵信息沒(méi)有結(jié)構(gòu)化地傳遞。我踩過(guò)的一個(gè)典型坑是Agent A 在清洗數(shù)據(jù)時(shí)刪除了某列但沒(méi)有在 Handoff 文檔里說(shuō)明結(jié)果 Agent B 在分析時(shí)找不到這列直接報(bào)錯(cuò)。解決方案是強(qiáng)制要求 Handoff 文檔包含“變更清單”字段明確列出所有對(duì)數(shù)據(jù)的修改操作。同時(shí)下游 Agent 在開(kāi)始工作前必須先校驗(yàn)輸入物是否符合預(yù)期如果不符合立即回退并說(shuō)明原因。我現(xiàn)在的做法是在AGENTS.md里加一條硬性規(guī)則任何 Agent 在修改輸入數(shù)據(jù)后必須在 Handoff 文檔的“變更清單”中逐條記錄修改內(nèi)容、修改原因和影響范圍。下游 Agent 在開(kāi)始工作前必須核對(duì)變更清單確認(rèn)無(wú)誤后才能繼續(xù)。這條規(guī)則加上后上下文丟失的問(wèn)題減少了 80% 以上。5.2 任務(wù)拆解粒度怎么把握拆得太粗單個(gè) Agent 負(fù)擔(dān)過(guò)重容易出錯(cuò)拆得太細(xì)協(xié)調(diào)開(kāi)銷超過(guò)任務(wù)本身。我的一般原則是每個(gè)子任務(wù)的執(zhí)行時(shí)間控制在 1 到 5 分鐘之間。太短說(shuō)明拆得過(guò)細(xì)太長(zhǎng)說(shuō)明還可以繼續(xù)拆。每個(gè)子任務(wù)有明確的驗(yàn)收標(biāo)準(zhǔn)。如果說(shuō)不清楚“做到什么程度算完成”說(shuō)明拆解還不夠清晰。子任務(wù)之間的依賴關(guān)系盡量簡(jiǎn)單。如果依賴關(guān)系復(fù)雜到需要畫圖才能理清說(shuō)明拆解方式有問(wèn)題應(yīng)該重新設(shè)計(jì)。我通常先用粗粒度拆解跑一遍觀察哪個(gè)環(huán)節(jié)耗時(shí)最長(zhǎng)或出錯(cuò)最多然后針對(duì)性地細(xì)化那個(gè)環(huán)節(jié)。這種“先跑通再優(yōu)化”的方式比一開(kāi)始就追求完美拆解要高效得多。5.3 Skill 調(diào)用失敗的排查思路Skill 調(diào)用失敗時(shí)我一般按這個(gè)順序排查第一步檢查輸入格式。90% 的失敗都是輸入格式不對(duì)導(dǎo)致的。用jsonschema之類的工具做嚴(yán)格校驗(yàn)?zāi)軘r截掉大部分問(wèn)題。第二步檢查依賴資源。Skill 依賴的文件、API、數(shù)據(jù)庫(kù)是否可用我遇到過(guò)好幾次因?yàn)榕R時(shí)文件被清理導(dǎo)致 Skill 失敗的情況后來(lái)加了資源檢查步驟就解決了。第三步檢查權(quán)限。Skill 是否有權(quán)限讀寫目標(biāo)文件是否有權(quán)限調(diào)用外部服務(wù)權(quán)限問(wèn)題在多 Agent 系統(tǒng)里很常見(jiàn)因?yàn)椴煌?Agent 可能運(yùn)行在不同的權(quán)限上下文中。第四步查看詳細(xì)日志。如果前三步都沒(méi)問(wèn)題就需要看 Skill 內(nèi)部的執(zhí)行日志了。我一般會(huì)在 Skill 的關(guān)鍵節(jié)點(diǎn)打日志方便定位問(wèn)題。下面是我整理的一份常見(jiàn)問(wèn)題速查表問(wèn)題現(xiàn)象可能原因排查方法解決方案Skill 返回空結(jié)果輸入格式錯(cuò)誤檢查輸入 schema修正輸入格式Skill 執(zhí)行超時(shí)依賴資源不可用檢查文件/API 狀態(tài)恢復(fù)資源或使用備用方案Skill 報(bào)權(quán)限錯(cuò)誤權(quán)限配置不當(dāng)檢查文件/服務(wù)權(quán)限調(diào)整權(quán)限配置Skill 輸出不符合預(yù)期提示詞不清晰檢查 Skill 定義優(yōu)化提示詞和約束條件Skill 頻繁重試輸入質(zhì)量差檢查上游輸出優(yōu)化上游 Agent 的輸出質(zhì)量5.4 多 Agent 系統(tǒng)的性能優(yōu)化經(jīng)驗(yàn)系統(tǒng)跑通后下一步就是優(yōu)化性能。我總結(jié)了幾條實(shí)用的優(yōu)化經(jīng)驗(yàn)第一并行化無(wú)依賴的子任務(wù)。如果兩個(gè)子任務(wù)之間沒(méi)有依賴關(guān)系就讓它們并行跑。我用asyncio實(shí)現(xiàn)并行調(diào)度實(shí)測(cè)下來(lái)能把總耗時(shí)壓縮 40% 左右。第二緩存重復(fù)計(jì)算的結(jié)果。有些 Skill 的輸出是確定性的同樣的輸入總是得到同樣的輸出。這類 Skill 的結(jié)果可以緩存起來(lái)下次遇到相同輸入時(shí)直接返回緩存結(jié)果。第三精簡(jiǎn) Handoff 文檔。Handoff 文檔不是越詳細(xì)越好關(guān)鍵是傳遞“下游需要知道的信息”。我一般控制在 500 字以內(nèi)超過(guò)這個(gè)長(zhǎng)度就說(shuō)明可能包含了冗余信息。第四合理設(shè)置超時(shí)時(shí)間。超時(shí)時(shí)間太短會(huì)導(dǎo)致正常任務(wù)被誤殺太長(zhǎng)會(huì)導(dǎo)致問(wèn)題任務(wù)拖慢整個(gè)系統(tǒng)。我一般根據(jù)歷史執(zhí)行時(shí)間的 P95 值來(lái)設(shè)置留出 20% 的余量。第五定期清理中間產(chǎn)物。多 Agent 系統(tǒng)跑久了workspace/intermediate/目錄會(huì)積累大量臨時(shí)文件。我一般設(shè)置一個(gè)定時(shí)任務(wù)每天清理超過(guò) 7 天的中間產(chǎn)物避免磁盤空間被占滿。5.5 從單 Agent 遷移到多 Agent 的注意事項(xiàng)如果你現(xiàn)在用的是單 Agent想遷移到多 Agent我建議按這個(gè)順序來(lái)第一步先梳理現(xiàn)有流程。把單 Agent 做的事情拆解成清晰的步驟標(biāo)注每步的輸入輸出。這一步不需要寫代碼用紙筆或者流程圖工具就行。第二步識(shí)別可獨(dú)立拆分的環(huán)節(jié)。哪些環(huán)節(jié)是相對(duì)獨(dú)立的哪些環(huán)節(jié)之間有強(qiáng)依賴優(yōu)先拆分獨(dú)立環(huán)節(jié)。第三步先拆一個(gè)環(huán)節(jié)試試。不要一次性全拆先拆一個(gè)環(huán)節(jié)跑通后再拆下一個(gè)。這樣風(fēng)險(xiǎn)可控出問(wèn)題也容易回滾。第四步建立 Handoff 機(jī)制。在拆分之前先把 Handoff 文檔的格式和規(guī)則定好。這是多 Agent 協(xié)作的基礎(chǔ)設(shè)施必須先建好。第五步逐步替換。每次替換一個(gè)環(huán)節(jié)觀察一段時(shí)間確認(rèn)穩(wěn)定后再替換下一個(gè)。全部替換完成后再考慮優(yōu)化整體性能。我自己的經(jīng)驗(yàn)是從單 Agent 遷移到多 Agent最大的挑戰(zhàn)不是技術(shù)而是思維方式的轉(zhuǎn)變。你需要從“一個(gè) Agent 做所有事”轉(zhuǎn)變?yōu)椤岸鄠€(gè) Agent 各司其職、互相配合”。這個(gè)轉(zhuǎn)變需要時(shí)間但只要跑通第一個(gè)多 Agent 項(xiàng)目后面的路就順了。6. 多 Agent 協(xié)作的擴(kuò)展方向與個(gè)人體會(huì)6.1 從固定流程到動(dòng)態(tài)編排目前我用的多 Agent 系統(tǒng)還是以固定流程為主任務(wù)拆解和 Agent 分配都是預(yù)先定義好的。下一步我想嘗試的是動(dòng)態(tài)編排根據(jù)任務(wù)的實(shí)際特點(diǎn)自動(dòng)決定拆解方式和 Agent 組合。比如同樣是數(shù)據(jù)分析任務(wù)如果數(shù)據(jù)量小可能只需要兩個(gè) Agent如果數(shù)據(jù)量大且復(fù)雜可能需要五個(gè) Agent。動(dòng)態(tài)編排的核心是讓系統(tǒng)具備“元認(rèn)知”能力能夠評(píng)估任務(wù)難度并做出相應(yīng)的資源分配決策。我目前的想法是引入一個(gè)“評(píng)估 Agent”專門負(fù)責(zé)任務(wù)難度評(píng)估和資源規(guī)劃。它不直接執(zhí)行任務(wù)而是為其他 Agent 提供調(diào)度建議。這個(gè)思路還在驗(yàn)證中等跑通了再單獨(dú)寫一篇分享。6.2 多 Agent 系統(tǒng)的可觀測(cè)性建設(shè)系統(tǒng)越復(fù)雜可觀測(cè)性越重要。我現(xiàn)在正在完善的是多 Agent 系統(tǒng)的監(jiān)控面板希望能實(shí)時(shí)看到每個(gè) Agent 的狀態(tài)、每個(gè)子任務(wù)的進(jìn)度、每個(gè) Skill 的調(diào)用情況??捎^測(cè)性建設(shè)我分三個(gè)層次日志層記錄所有關(guān)鍵事件包括 Agent 啟動(dòng)、任務(wù)分配、Skill 調(diào)用、錯(cuò)誤發(fā)生等。指標(biāo)層統(tǒng)計(jì)關(guān)鍵指標(biāo)比如任務(wù)完成率、平均執(zhí)行時(shí)間、重試率、錯(cuò)誤率等。追蹤層追蹤單個(gè)任務(wù)的完整執(zhí)行鏈路從任務(wù)創(chuàng)建到最終輸出中間經(jīng)過(guò)了哪些 Agent、哪些 Skill、哪些決策。這三個(gè)層次建好后排查問(wèn)題會(huì)變得非常高效。以前需要翻半天日志才能定位的問(wèn)題現(xiàn)在在面板上掃一眼就能發(fā)現(xiàn)異常。6.3 我踩過(guò)的三個(gè)大坑第一個(gè)坑是過(guò)度設(shè)計(jì)。剛開(kāi)始做多 Agent 時(shí)我設(shè)計(jì)了七個(gè) Agent每個(gè) Agent 負(fù)責(zé)一個(gè)非常細(xì)的環(huán)節(jié)。結(jié)果協(xié)調(diào)開(kāi)銷巨大系統(tǒng)跑起來(lái)比單 Agent 還慢。后來(lái)砍到三個(gè) Agent效率反而提升了。教訓(xùn)是Agent 數(shù)量不是越多越好夠用就行。第二個(gè)坑是忽視 Handoff 文檔的質(zhì)量。早期我覺(jué)得 Handoff 文檔就是走個(gè)形式隨便寫寫就行。結(jié)果下游 Agent 經(jīng)常因?yàn)槿鄙訇P(guān)鍵信息而輸出錯(cuò)誤結(jié)果。后來(lái)我把 Handoff 文檔的質(zhì)量納入驗(yàn)收標(biāo)準(zhǔn)問(wèn)題才解決。教訓(xùn)是Handoff 文檔是多 Agent 系統(tǒng)的生命線必須認(rèn)真對(duì)待。第三個(gè)坑是沒(méi)有回滾機(jī)制。有一次 Agent B 的輸出有問(wèn)題但系統(tǒng)沒(méi)有檢測(cè)到繼續(xù)往下跑最后生成了一份完全錯(cuò)誤的報(bào)告。后來(lái)我加了校驗(yàn)和回滾機(jī)制任何環(huán)節(jié)發(fā)現(xiàn)問(wèn)題都能立即中止并回退到上一個(gè)穩(wěn)定狀態(tài)。教訓(xùn)是多 Agent 系統(tǒng)必須有容錯(cuò)和回滾能力否則錯(cuò)誤會(huì)逐級(jí)放大。6.4 給初次嘗試者的實(shí)用建議如果你正準(zhǔn)備嘗試多 Agent 協(xié)作我最后分享幾條實(shí)用建議從簡(jiǎn)單任務(wù)開(kāi)始。不要一上來(lái)就挑戰(zhàn)復(fù)雜項(xiàng)目先找一個(gè)兩三個(gè)環(huán)節(jié)的小任務(wù)跑通流程。跑通后再逐步增加復(fù)雜度。先把 Handoff 機(jī)制建好。這是多 Agent 協(xié)作的基礎(chǔ)設(shè)施不要等到出問(wèn)題了才想起來(lái)補(bǔ)。我一般建議在寫第一個(gè) Agent 之前就把 Handoff 文檔的模板和規(guī)則定好??刂?Agent 數(shù)量。初次嘗試建議控制在 3 個(gè)以內(nèi)跑通后再根據(jù)實(shí)際需要增加。Agent 越多協(xié)調(diào)開(kāi)銷越大出問(wèn)題的概率也越高。重視日志和監(jiān)控。多 Agent 系統(tǒng)的調(diào)試比單 Agent 復(fù)雜得多沒(méi)有完善的日志和監(jiān)控排查問(wèn)題會(huì)非常痛苦。保持耐心。多 Agent 協(xié)作不是一蹴而就的需要反復(fù)調(diào)試和優(yōu)化。我自己的第一個(gè)多 Agent 項(xiàng)目跑了整整兩周才穩(wěn)定下來(lái)但穩(wěn)定之后效率提升是實(shí)實(shí)在在的。這套多 Agent 協(xié)作方案我目前已經(jīng)在三個(gè)實(shí)際項(xiàng)目中落地使用最長(zhǎng)的跑了半年多整體穩(wěn)定性不錯(cuò)。當(dāng)然它肯定不是唯一正確的方案不同團(tuán)隊(duì)、不同場(chǎng)景可能需要不同的設(shè)計(jì)。關(guān)鍵是理解背后的核心原理然后根據(jù)自己的實(shí)際情況靈活調(diào)整。