代理與多任務(wù)代理:LLM智能體架構(gòu)選型全解析)
做AI智能體有一段時間的人應(yīng)該都有過這種體驗同樣是基于LLM做出來的東西有的又準(zhǔn)又穩(wěn)就像一把趁手的扳手說擰哪顆螺絲就擰哪顆有的則是上來就問你“您需要什么幫助”然后一通操作猛如虎最后還答非所問。問題在哪很多時候不在模型能力而在于你沒有把“任務(wù)邊界”這件事想清楚。今天這篇我想圍繞LLM智能體的兩種典型形態(tài)——單任務(wù)代理與多任務(wù)代理把它們的結(jié)構(gòu)差異、適用場景和取舍邏輯攤開聊一聊。如果你正在設(shè)計自己的第一個AI智能體或者已經(jīng)做了一個但又覺得哪里不對勁這篇文章應(yīng)該能幫你找到一個明確的判斷框架。我先把結(jié)論放在前面單任務(wù)代理和多任務(wù)代理的區(qū)別不僅僅是你給系統(tǒng)指派了“一件事”還是“很多件事”而是整個系統(tǒng)在決策權(quán)歸屬、任務(wù)編排方式、狀態(tài)管理邏輯這三個層面都發(fā)生了根本變化。理解不了這層你可能會做出一個看起來很強(qiáng)大、用起來卻很崩潰的“偽多任務(wù)”系統(tǒng)。1. 從“單個LLM”到“單任務(wù)代理”一個專注型執(zhí)行器是如何構(gòu)建的在很多人的理解里給一個LLM寫一段提示詞讓它專門做某件事這就叫單任務(wù)代理。其實這個理解不算錯但只說對了一半。真正的單任務(wù)代理要求的是單一目標(biāo)貫穿整個運(yùn)行生命周期從接收輸入到調(diào)用外部工具再到生成最終輸出中間不做任何橫向發(fā)散。1.1 單任務(wù)代理的核心運(yùn)行邏輯一個標(biāo)準(zhǔn)的單任務(wù)代理內(nèi)部通常只有一條固定鏈路接收用戶請求 → 解析請求中的結(jié)構(gòu)化字段 → 判斷是否調(diào)用工具 → 拿到工具結(jié)果 → 生成最終回答。鏈路很短而且每一步的觸發(fā)條件都非常明確。舉個例子。我做過一個專門處理“商品庫存查詢”的小型代理輸入是“某某商品還有貨嗎”輸出是“有/無 預(yù)計補(bǔ)貨時間”。這個代理的內(nèi)部實現(xiàn)里L(fēng)LM只負(fù)責(zé)兩件事第一從用戶話術(shù)中抽取商品名和查詢意圖第二把工具返回的庫存數(shù)字翻譯成人話。其他的一切比如閑聊、推薦商品、解釋售后政策都被系統(tǒng)提示詞明確禁止了。# 一個典型單任務(wù)代理的結(jié)構(gòu)示意 class InventoryAgent: def __init__(self, llm): self.llm llm self.tools {query_stock: query_stock_api} self.system_prompt 你是一個庫存查詢助手。只處理庫存相關(guān)查詢其他內(nèi)容一律拒絕回答。 def run(self, user_input): intent self.llm.extract(user_input, schema[product_name, intent]) if intent[intent] ! stock_query: return 抱歉我只負(fù)責(zé)庫存查詢。 stock_info self.tools[query_stock](intent[product_name]) return self.llm.generate_answer(stock_info)這段代碼去掉了各種復(fù)雜的外部依賴但核心鏈路就長這樣。你可以看到每一步的輸入輸出都是被定義死的LLM沒有任何自由發(fā)揮的空間。對于“把一件事做極致”的需求來說這種結(jié)構(gòu)幾乎是最好的——準(zhǔn)確率高、響應(yīng)快、成本低且?guī)缀鯖]有失控風(fēng)險。1.2 為什么單任務(wù)代理容易給人“很蠢”的感覺但單任務(wù)代理也有一個天生缺陷它的能力邊界非常僵硬。一旦用戶的需求繞過了那道邊界哪怕是一句簡單的“幫我順便看看這款商品的評價”代理也會直接拒絕或者報錯。于是很多人開始覺得這玩意兒“太笨了”接著就想往里面塞更多能力。一個典型誤區(qū)是多塞幾個工具副本把不同任務(wù)塞進(jìn)同一個提示詞里就認(rèn)為它變成了多任務(wù)代理。實際上不是。“既能查庫存、又能查物流、又能查退換貨政策”的代理如果內(nèi)部沒有真正的任務(wù)分發(fā)邏輯而只是把所有工具的說明都寫進(jìn)提示詞讓LLM自己選那它是一個擁有多個工具的單任務(wù)代理——因為它同時還是沒有任務(wù)邊界還是憑模型“臨場感覺”決定該干什么。這種結(jié)構(gòu)的最大問題在于LLM的工具選擇往往會有隨機(jī)性尤其在工具列表超過五個之后選錯工具的概率會明顯上浮。這也是我們在項目里反復(fù)踩過的一個坑。2. 多任務(wù)代理的本質(zhì)不是“會的多”而是“編排好”理解了單任務(wù)代理再看多任務(wù)代理就順理成章了。多任務(wù)代理的關(guān)鍵詞不是“多”而是編排。它要對一系列子任務(wù)進(jìn)行規(guī)劃、路由、執(zhí)行和結(jié)果合并最終給用戶一個統(tǒng)一完整的響應(yīng)。2.1 多任務(wù)代理的兩種主流實現(xiàn)形態(tài)我平時接觸到的多任務(wù)代理大致可以分為兩類下面分別說明。一類是單體多任務(wù)。整個系統(tǒng)還是一個代理內(nèi)部有多個任務(wù)處理器Handler業(yè)務(wù)流程通過一個路由器做分發(fā)。比如你輸入“把這份文檔翻譯成英文然后提取里面的三個關(guān)鍵觀點(diǎn)”代理會先調(diào)用翻譯Handler等翻譯完成后再把結(jié)果喂給觀點(diǎn)提取Handler最后把兩個結(jié)果合并輸出。這類代理的好處是全局狀態(tài)統(tǒng)一管理用戶感知是和一個“人”在對話劣勢在于任務(wù)流水線一旦變長上下文會被反復(fù)注入Token消耗和新任務(wù)的干擾都會明顯上升。另一類是多智能體協(xié)作。每個子任務(wù)由一個獨(dú)立的代理負(fù)責(zé)代理之間通過消息或共享狀態(tài)互相通信。還是上面翻譯加提取的場景這里會有一個調(diào)度代理把任務(wù)拆開分發(fā)給一個翻譯代理和一個提取代理再回收各自的結(jié)果排序輸出。這類形態(tài)隔離性好可以單獨(dú)升級某個子代理而不影響其他模塊調(diào)試起來非常直觀但代價是你得額外處理代理之間的通信協(xié)議、時間同步和數(shù)據(jù)一致性問題。在需要十幾個子任務(wù)協(xié)作的復(fù)雜場景里這類“分布式”的調(diào)試成本會成倍增加。2.2 一個常見的誤導(dǎo)性說法“用越大越聰明的模型多任務(wù)效果就越好”這個說法部分成立但不全對。大模型的能力確實能提升單步任務(wù)的完成質(zhì)量但多任務(wù)系統(tǒng)的整體效果更多取決于任務(wù)拆解的合理性和數(shù)據(jù)流轉(zhuǎn)的完整性。我曾經(jīng)把一個四任務(wù)代理的LLM從普通規(guī)模的模型換到頂級規(guī)模的模型結(jié)果整體效果只提升了大約7%倒是成本翻了近十倍。后來我重新調(diào)整了子任務(wù)的先后順序把原本混亂的數(shù)據(jù)依賴?yán)眄槢]有換模型整體正確率卻提升了近20%。這給我的觸動特別深多任務(wù)代理的瓶頸往往不在“模型智商”而在“架構(gòu)設(shè)計”。3. 同樣的客服場景單任務(wù)和多任務(wù)的實現(xiàn)差異究竟有多大抽象概念說再多都不如拿一個具體的業(yè)務(wù)場景來對照。我選大部分人都有感知的“售前咨詢智能體”作為例子。同樣是一個客服入口用單任務(wù)代理怎么做用多任務(wù)代理怎么做我實際對比過。單任務(wù)代理的做法很直接設(shè)置一個主題——售前產(chǎn)品介紹。工具只有商品信息庫提示詞明確要求只回答產(chǎn)品規(guī)格、價格、優(yōu)惠信息這三類問題。一旦用戶問“你們有什么優(yōu)惠嗎”之外的任何問題比如“我的訂單到哪里了”單任務(wù)代理就只會機(jī)械地回復(fù)“我只負(fù)責(zé)產(chǎn)品介紹”??雌饋眢w驗很糟糕但它的優(yōu)點(diǎn)也極其鮮明響應(yīng)速度穩(wěn)定在0.8秒左右準(zhǔn)確率幾乎可以達(dá)到99%不會出現(xiàn)自說自話亂回答的情況而且運(yùn)維成本約等于零出了問題也極其好排查因為路徑是固定的。對于企業(yè)只需要解決某一個特定問題的場景單任務(wù)代理這種“偏科”反而是一種優(yōu)勢。多任務(wù)代理的做法完全不同。它內(nèi)部會有這樣一個結(jié)構(gòu)路由層先把用戶輸入歸入N個入口之一——產(chǎn)品介紹、訂單查詢、物流跟蹤、售后政策、人工轉(zhuǎn)接然后分發(fā)到各自對應(yīng)的任務(wù)處理器每個處理器完成后結(jié)果匯總層再統(tǒng)一整理語氣和排版輸出給用戶。這個系統(tǒng)光是路由器就需要單獨(dú)調(diào)優(yōu)更不用說五個處理器各自的提示詞、工具配置和邊界條件。我實測算下來一個完整的五任務(wù)客服代理首版調(diào)試周期大概是單任務(wù)代理的三到五倍響應(yīng)時長通常會從0.8秒漲到2秒甚至更多。那為什么還要做多任務(wù)因為用戶滿意度數(shù)據(jù)完全不一樣。單任務(wù)代理雖然快但“答非所問”的體驗會讓用戶迅速流失多任務(wù)代理會繞路但至少每個問題都能被正確分流和響應(yīng)用戶不用在不同入口之間反復(fù)跳轉(zhuǎn)。這個取舍本身沒有絕對的對錯取決于你的業(yè)務(wù)更看重單點(diǎn)效率還是綜合體驗。4. 多任務(wù)代理內(nèi)部必現(xiàn)的三個關(guān)鍵機(jī)制如果你已經(jīng)決定要做一個多任務(wù)代理那么有三個機(jī)制是你繞不開的路由機(jī)制、上下文窗口策略、記憶與狀態(tài)共享。這三個點(diǎn)處理好了系統(tǒng)的穩(wěn)定性和可擴(kuò)展性才會起來。4.1 路由機(jī)制決定“誰來做”的第一道關(guān)路由層是多任務(wù)代理最基礎(chǔ)、也最容易被低估的部分。很多人圖省事直接讓LLM自己去判斷“用戶這句話屬于哪個任務(wù)”好一點(diǎn)的加一句“如果都不屬于回復(fù)無法處理”。但實際運(yùn)行中尤其是存在語義相近的任務(wù)時這種自由判斷會出現(xiàn)系統(tǒng)性偏差——比如將“退貨怎么申請”判到“售后政策”而不是“退貨處理”將“還沒發(fā)貨”判到“物流查詢”而不是“訂單狀態(tài)”。比較穩(wěn)妥的做法是對每個任務(wù)定義一個分類器先做一次規(guī)則匹配再做一次向量召回。常用策略如下規(guī)則優(yōu)先先匹配關(guān)鍵詞、實體、正則等強(qiáng)規(guī)則命中就不用走模型向量召回把用戶輸入和每個任務(wù)的示例問法做向量相似度計算優(yōu)先返回相似度最高的前K個LLM兜底前面兩步都不確定的才交給LLM做最終判斷且要求返回JSON格式的分流結(jié)果。我個人的經(jīng)驗是這樣疊加之后路由的準(zhǔn)確率能做到95%以上而且其中LLM要處理的流量可能只有20%左右成本優(yōu)勢也很明顯。你可以看這樣一個簡單路由表用戶輸入示例規(guī)則匹配向量召回最終路由“怎么退貨”命中“退貨”關(guān)鍵詞退貨處理退貨處理“衣服小了能換嗎”無強(qiáng)規(guī)則換貨 / 退貨處理換貨若配置“你們周末上班嗎”無強(qiáng)規(guī)則售后政策 / 人工人工轉(zhuǎn)接或兜底路由表本身是可以不斷迭代的。我建議每個新增的任務(wù)都提前準(zhǔn)備10條以上示例問法這樣向量召回的效果才會穩(wěn)定。4.2 上下文窗口策略如何避免多個任務(wù)互相“污染”多任務(wù)代理最常見的翻車場景是上下文污染。舉例來說用戶在查詢訂單之后又追問了另一個產(chǎn)品的問題如果系統(tǒng)直接把上一輪的訂單信息帶進(jìn)新的產(chǎn)品查詢里L(fēng)LM很可能把訂單號誤當(dāng)成產(chǎn)品編號輸出一段完全不著調(diào)的內(nèi)容。多任務(wù)代理在設(shè)計上下文時最需要關(guān)注的不是總長度而是隔離性。我習(xí)慣的做法是全局上下文只保留用戶級基本信息如用戶ID、會話ID每個子任務(wù)維護(hù)一個獨(dú)立的任務(wù)上下文只存儲該任務(wù)相關(guān)的歷史信息任務(wù)切換后新任務(wù)不會讀取上一個任務(wù)的細(xì)節(jié)除非顯式聲明需要。同時任務(wù)結(jié)果合并階段要把不同子任務(wù)輸出放在一個結(jié)構(gòu)化的容器里并且用模板限定合并規(guī)則。你完全可以這樣理解單任務(wù)代理是只有一頁紙的記事本多任務(wù)代理則是帶標(biāo)簽的文件夾——每類任務(wù)有自己的子文件夾必要的時候才歸檔到一起。具體到實現(xiàn)上這個“隔離”就是你在調(diào)用LLM時對不同的Handler傳入不同的prompt和history片段而不是永遠(yuǎn)傳同一個session數(shù)組。當(dāng)然隔離也不是絕對的長期記憶數(shù)據(jù)比如用戶的偏好標(biāo)簽、歷史訂單摘要是允許被多個任務(wù)共享的那屬于“狀態(tài)共享”層面和“上下文隔離”不能混為一談。4.3 記憶與狀態(tài)共享共享什么、不共享什么要有明確清單多任務(wù)代理越做越大記憶管理就會變成最纏人的活。共享狀態(tài)里面到底該放什么我建議只放跨任務(wù)都需要的“事實型數(shù)據(jù)”比如用戶名、會員等級、訂單編號列表而不是放“上一輪的任務(wù)過程和中間推理”。后者通常是性能殺手而且容易造成任務(wù)間干擾。有一版我做的多任務(wù)客服代理第一次上線時就把所有子任務(wù)的中間結(jié)果都放進(jìn)共享狀態(tài)里結(jié)果用戶多輪對話一多整個系統(tǒng)的召回準(zhǔn)確率就往下掉。后來把所有中間過程全部改成私有上下文只保留最終的結(jié)論數(shù)據(jù)在共享狀態(tài)問題立刻消失了。共享狀態(tài)這里寧可多隔離也不要貪多。5. 成本、延遲和調(diào)試體驗多任務(wù)代理被低估的三筆代價說實話多任務(wù)代理在業(yè)務(wù)側(cè)的誘惑力很大因為它顯得“靈活、全能”。但在工程落地的過程中有幾筆賬經(jīng)常被低估我建議每個準(zhǔn)備選型的人都先算清楚。成本方面同樣是十個問題單任務(wù)代理調(diào)用LLM的次數(shù)通常等于問題數(shù)多任務(wù)代理可能每個問題都要調(diào)用路由層加子任務(wù)處理層再加上結(jié)果匯總層。如果你做了二次分類或者重試機(jī)制一次用戶請求背后可能是三四次甚至更多的LLM調(diào)用。這不是危言聳聽實測下來同等量級下多任務(wù)代理的Token成本往往是單任務(wù)代理的2到4倍。延遲方面更復(fù)雜的是延遲。多任務(wù)代理如果存在串行依賴比如必須先識別意圖再查庫存最后生成回答那總延遲就是各步驟延遲之和。我在測試中見過一個串聯(lián)了五個子任務(wù)的代理單次全鏈路延遲輕松超過8秒用戶早跑了。解決思路無非兩條能把獨(dú)立任務(wù)并行的就并行調(diào)用減少串行鏈路或者給路由器一個超時預(yù)算超過指定時間先輸出部分結(jié)果避免“干等”。這兩條建議大家可以優(yōu)先考慮。調(diào)試體驗方面單任務(wù)代理的排查路徑非常簡單報錯了基本就是提示詞問題、工具問題或輸入格式問題三選一多任務(wù)代理的報錯則是“跨模塊聯(lián)調(diào)”你得先確認(rèn)路由是否正確再確認(rèn)數(shù)據(jù)有沒有正確傳遞再確認(rèn)是哪個Handler的問題最后還得確認(rèn)匯總層的格式?jīng)_突。很多時候明明答案是對的匯總層卻因為JSON格式解析失敗導(dǎo)致整個回復(fù)被攔截。這一類問題在真實項目中非常常見。下面放一個簡單的對比表方便你快速評估對比維度單任務(wù)代理多任務(wù)代理單次響應(yīng)延遲較低鏈路短偏慢鏈路疊加Token成本低高常有額外路由開銷準(zhǔn)確性上限極高領(lǐng)域受限中等依賴路由與編排擴(kuò)展新能力需要重寫可增量添加調(diào)試難度簡單復(fù)雜跨模塊定位難適合場景工具型、問題單一客服、助手型、綜合入口6. 我的選型建議不要為了“多任務(wù)”而上多任務(wù)寫了這么多最后聊一點(diǎn)實際的體會。很多人在設(shè)計智能體時第一反應(yīng)是“多任務(wù)更高級”所以從一開始就奔著多任務(wù)去。但如果你仔細(xì)復(fù)盤業(yè)務(wù)需求可能會發(fā)現(xiàn)其中80%的請求都屬于同一類固定問題那這時候上多任務(wù)代理就是在給自己的工程和成本增加不必要的復(fù)雜度。我個人的一個判斷標(biāo)準(zhǔn)是當(dāng)用戶的輸入意圖類型只有1到2種時毫不猶豫選單任務(wù)當(dāng)意圖類型在3到5種時可以先做一個帶清晰路由的多任務(wù)單體只有當(dāng)意圖類型超過5種而且不同任務(wù)之間存在復(fù)雜的依賴關(guān)系時才值得引入多智能體協(xié)作結(jié)構(gòu)。另一個判斷依據(jù)是如果你的產(chǎn)品天然需要用戶在同一段對話里平滑切換多個主題比如綜合購物助手那么多任務(wù)代理幾乎是唯一的正確選項——這時候就算延遲高一點(diǎn)、成本貴一點(diǎn)也只能接受因為單任務(wù)根本兜不住這種體驗。最后再分享一個我調(diào)試多任務(wù)代理的習(xí)慣每增加一個子任務(wù)我都會單獨(dú)測試它的路由準(zhǔn)確率至少要穩(wěn)定超過95%才放行進(jìn)入主流程同時我會為每個子任務(wù)準(zhǔn)備一組“負(fù)面測試用例”專門用來確認(rèn)它不會搶走不該屬于它的請求。這樣做至少能避免那種幾個子任務(wù)互相打架、用戶輸入被反復(fù)路由到錯誤模塊的尷尬情況。我踩過很多次坑之后才意識到很多多任務(wù)代理不是輸在模型不夠聰明而是輸在沒人認(rèn)真管理“分診”這件事。如果你正在做類似的系統(tǒng)不妨也從路由和狀態(tài)隔離這兩處入手把基礎(chǔ)打穩(wěn)再談能力擴(kuò)張。