用架構(gòu)設(shè)計(jì)實(shí)戰(zhàn):模型網(wǎng)關(guān)、Agent編排與上下文工程全拆解)
最近在做AI應(yīng)用架構(gòu)設(shè)計(jì)評(píng)審時(shí)我發(fā)現(xiàn)一個(gè)特別普遍的現(xiàn)象很多團(tuán)隊(duì)把大模型應(yīng)用想得過于簡(jiǎn)單覺得只要封裝一個(gè)API、把Prompt拼好、把返回結(jié)果丟給前端就算做完了??梢坏┯脩袅可蟻砘蛘邩I(yè)務(wù)需要接入多個(gè)模型、引入Agent編排、處理長(zhǎng)對(duì)話記憶原本一個(gè)接口一把梭的代碼就會(huì)變成一團(tuán)亂麻。真正成熟的AI應(yīng)用從來不是調(diào)用大模型這一個(gè)動(dòng)作而是從入口到數(shù)據(jù)再到模型之間的一系列架構(gòu)決策。這篇文章我想用畫圖的思路帶你把AI應(yīng)用架構(gòu)設(shè)計(jì)拆開揉碎。會(huì)先講清楚AI應(yīng)用到底在架構(gòu)什么再逐個(gè)分析模型網(wǎng)關(guān)、向量庫、Agent編排這些核心組件接著聊并發(fā)流量怎么扛上下文工程怎么做最后從單Agent走向多Agent協(xié)作時(shí)架構(gòu)會(huì)發(fā)生什么變化。無論你是剛開始做AI應(yīng)用開發(fā)還是正在負(fù)責(zé)技術(shù)選型這篇都能給到你一份可以直接落地的參考框架。1. 從調(diào)API到建架構(gòu)AI應(yīng)用到底在架構(gòu)什么1.1 一次最簡(jiǎn)單的調(diào)用背后藏著哪些模塊我們先看一個(gè)最樸素的大模型聊天機(jī)器人。用戶在網(wǎng)頁里敲了一句幫我總結(jié)這份合同前端把這句話發(fā)給后端后端往大模型API里一丟模型返回總結(jié)頁面渲染出來。就這么一個(gè)流程看起來五步搞定但真正到了生產(chǎn)環(huán)境你至少還需要考慮這五件事之外的十幾個(gè)隱藏模塊。我在剛?cè)胄袝r(shí)踩過一個(gè)坑第一個(gè)AI應(yīng)用上線后服務(wù)端突然收到一堆重復(fù)請(qǐng)求因?yàn)榍岸俗隽酥卦嚭蠖擞譀]有做冪等結(jié)果同一條用戶消息被模型處理了兩遍用戶收到了兩條重復(fù)回復(fù)。這就是典型的架構(gòu)缺失——沒有請(qǐng)求去重沒有超時(shí)控制。一個(gè)完整的AI應(yīng)用調(diào)用鏈路在業(yè)務(wù)邏輯之前應(yīng)該先有API網(wǎng)關(guān)、身份認(rèn)證、限流、審計(jì)日志、內(nèi)容安全審核、Prompt模板管理在業(yè)務(wù)邏輯之后還要有結(jié)果緩存、成本統(tǒng)計(jì)、可觀測(cè)性埋點(diǎn)。如果你把這條鏈路畫成一張時(shí)序圖會(huì)發(fā)現(xiàn)用戶和模型之間隔著一大堆中間層。這些中間層不是可有可無的裝飾而是讓AI應(yīng)用具備生產(chǎn)可用性的骨架。早期很多團(tuán)隊(duì)直接讓前端調(diào)模型API省事是省事但密鑰會(huì)暴露成本失控模型一限流整個(gè)系統(tǒng)全掛。所以架構(gòu)的第一步就是把這些看不見的模塊顯式化。1.2 用一張圖拆開AI應(yīng)用的四層結(jié)構(gòu)我平時(shí)習(xí)慣把AI應(yīng)用架構(gòu)畫成四層自上而下分別是接入層、編排層、模型層、數(shù)據(jù)層。下面用表格列出每層的職責(zé)和典型組件層級(jí)核心職責(zé)典型組件/技術(shù)接入層對(duì)外暴露接口處理認(rèn)證、限流、安全、協(xié)議轉(zhuǎn)換API Gateway、Nginx、Auth Service編排層組裝Prompt、決定調(diào)用順序、管理Agent循環(huán)、處理工具調(diào)用LangGraph、CrewAI、自研Orchestrator模型層對(duì)接一個(gè)或多個(gè)大模型控制路由、降級(jí)、緩存OpenAI兼容網(wǎng)關(guān)、vLLM、TensorRT-LLM數(shù)據(jù)層提供外部記憶、檢索增強(qiáng)、業(yè)務(wù)數(shù)據(jù)庫訪問向量庫、Redis、PostgreSQL、對(duì)象存儲(chǔ)為什么要分成四層核心目的是隔離變化。模型層是最容易變的地方你可能今天用A模型明天因?yàn)槌杀緭Q成B模型如果業(yè)務(wù)代碼里到處是from openai import OpenAI換模型就成了一場(chǎng)災(zāi)難。有了模型網(wǎng)關(guān)上層只面對(duì)一個(gè)統(tǒng)一接口模型怎么換是下面的事。數(shù)據(jù)層也一樣今天用向量庫做RAG明天想換成圖數(shù)據(jù)庫增強(qiáng)關(guān)系推理只要編排層通過數(shù)據(jù)服務(wù)接口訪問底層替換就不會(huì)炸到業(yè)務(wù)邏輯。畫完這張圖你還能直觀看出每一層之間的接口定義。比如編排層和模型層之間到底傳遞的是純文本還是結(jié)構(gòu)化的消息數(shù)組數(shù)據(jù)層返回的檢索片段是直接塞進(jìn)Prompt還是先經(jīng)過一個(gè)重排模塊這些問題都屬于架構(gòu)設(shè)計(jì)的核心決策圖一畫出來哪里模糊哪里缺接口一目了然。2. 核心組件選型模型網(wǎng)關(guān)、向量庫和Agent編排2.1 為什么不能繞過模型網(wǎng)關(guān)很多中小項(xiàng)目一開始只接一家模型廠商覺得模型網(wǎng)關(guān)是過度設(shè)計(jì)。我的看法恰恰相反模型網(wǎng)關(guān)不是可有可無的中間層而是AI應(yīng)用架構(gòu)里的斷路器。它至少承擔(dān)四件關(guān)鍵事統(tǒng)一接口、密鑰托管、負(fù)載均衡和質(zhì)量開關(guān)。統(tǒng)一接口很好理解無論你接的是字節(jié)的模型還是阿里的網(wǎng)關(guān)都把它包裝成一個(gè)標(biāo)準(zhǔn)的Completion接口業(yè)務(wù)側(cè)不感知廠商差異。密鑰托管則解決安全問題直接在前端調(diào)用模型接口最大的風(fēng)險(xiǎn)是密鑰泄漏網(wǎng)關(guān)把密鑰鎖在后端前端只跟網(wǎng)關(guān)打交道。負(fù)載均衡更實(shí)在同一個(gè)模型請(qǐng)求可以按權(quán)重打到不同廠商的同級(jí)別模型上或者按用戶維度做路由。我印象最深的一個(gè)案例是某家做客服助手的團(tuán)隊(duì)把模型網(wǎng)關(guān)配成了主備模式主用旗艦?zāi)P彤?dāng)旗艦?zāi)P鸵蛳蘖鞣祷?29時(shí)網(wǎng)關(guān)自動(dòng)把請(qǐng)求降級(jí)到備用的成本更低的模型。結(jié)果某天晚高峰主模型排隊(duì)嚴(yán)重他們的系統(tǒng)靠著網(wǎng)關(guān)自動(dòng)降級(jí)硬是撐住了兩個(gè)小時(shí)的流量高峰業(yè)務(wù)成功率只下降了不到3%。沒有網(wǎng)關(guān)這種容災(zāi)幾乎不可能一個(gè)接口全局實(shí)現(xiàn)。2.2 向量數(shù)據(jù)庫不是可選項(xiàng)取決于場(chǎng)景AI應(yīng)用一定要上RAGRAG一定要上向量庫這是我在社區(qū)里聽到最多的錯(cuò)誤直覺。實(shí)際上向量庫是否必要取決于你的應(yīng)用是否需要語義相似度檢索這種能力。如果你的AI應(yīng)用只是做純生成、總結(jié)、翻譯不依賴私有知識(shí)庫那引入一個(gè)獨(dú)立的向量數(shù)據(jù)庫大概率是給自己找運(yùn)維負(fù)擔(dān)。但一旦你遇到這些場(chǎng)景——讓AI基于企業(yè)內(nèi)部文檔回答、讓AI從幾千條聊天記錄里找到相似問題、給用戶做語義搜索——向量庫就是不可繞過的組件。選型時(shí)我習(xí)慣先把需求摁到兩種類型里嵌入式向量索引比如FAISS適合單機(jī)數(shù)據(jù)量小、離線索引可接受、不需要復(fù)雜過濾的場(chǎng)景。優(yōu)點(diǎn)是部署簡(jiǎn)單丟進(jìn)應(yīng)用進(jìn)程里就能跑缺點(diǎn)是數(shù)據(jù)量上來后內(nèi)存壓力大多副本同步也麻煩。獨(dú)立向量數(shù)據(jù)庫比如Milvus、Qdrant、pgvector適合數(shù)據(jù)量大、需要實(shí)時(shí)寫入、需要按業(yè)務(wù)字段過濾、需要高并發(fā)查詢的場(chǎng)景。好處是彈性擴(kuò)展、帶持久化和權(quán)限控制缺點(diǎn)是代價(jià)是一個(gè)額外的分布式系統(tǒng)需要監(jiān)控運(yùn)維。我曾經(jīng)在一個(gè)項(xiàng)目里先用了FAISS后來業(yè)務(wù)要按用戶ID過濾結(jié)果還要支持每天百萬級(jí)記錄更新FAISS單機(jī)內(nèi)存完全扛不住才不得不遷到獨(dú)立向量庫。如果前期就畫清楚數(shù)據(jù)流的圖這個(gè)返工完全可以避免。數(shù)據(jù)量、過濾條件、更新頻率三大要素決定了向量庫選型的走向。2.3 Agent編排決定應(yīng)用具備多少自主性Agent是當(dāng)前AI應(yīng)用架構(gòu)里熱度最高的詞但很多團(tuán)隊(duì)把Agent等同于多輪對(duì)話。真正的Agent編排核心是讓模型在一個(gè)循環(huán)里自主決定下一步動(dòng)作當(dāng)前輸入要不要調(diào)用工具調(diào)用哪個(gè)工具需要什么樣的參數(shù)如果工具返回異常是不是該換一條路徑重試把這個(gè)循環(huán)畫出來就是經(jīng)典的ReAct模式模型觀察用戶請(qǐng)求結(jié)合當(dāng)前狀態(tài)推理決定采取動(dòng)作執(zhí)行工具工具返回結(jié)果模型再觀察直到得出最終答案。這個(gè)循環(huán)必須由編排層控制而不是讓模型自己無止境地跑下去。所以編排層至少要維護(hù)兩個(gè)東西一個(gè)是狀態(tài)記錄當(dāng)前Agent走到了哪一步、已經(jīng)收集了哪些信息另一個(gè)是路由表定義什么條件下該用哪個(gè)工具、什么條件下該結(jié)束循環(huán)。市面上LenangGraph、CrewAI這些框架本質(zhì)上都是幫你管理節(jié)點(diǎn)、狀態(tài)和路由的。但我的經(jīng)驗(yàn)是框架可以解決80%的通用編排問題剩下的20%比如工具返回異常后的重試策略、Agent步驟的持久化、超時(shí)后的降級(jí)應(yīng)答往往還是要自研。架構(gòu)設(shè)計(jì)時(shí)不能只畫一個(gè)Agent框就完事要把這個(gè)框內(nèi)部的狀態(tài)機(jī)畫出來才能準(zhǔn)確評(píng)估復(fù)雜度和風(fēng)險(xiǎn)。3. 架構(gòu)中的流量與并發(fā)Agent怎么扛住真實(shí)壓力3.1 請(qǐng)求鏈路中的每個(gè)環(huán)節(jié)都可能成為瓶頸在大模型應(yīng)用里一個(gè)用戶請(qǐng)求往往不只是調(diào)用一次模型。尤其Agent場(chǎng)景可能先做一次意圖識(shí)別然后檢索向量庫再調(diào)用一次外部工具最后再讓模型匯總答案。整條鏈路下來可能觸發(fā)三到五次模型調(diào)用。這意味著你看到的在線用戶數(shù)和背后模型API的實(shí)際調(diào)用量中間可能隔著好幾倍的系數(shù)。我自己畫鏈路圖時(shí)會(huì)給每個(gè)節(jié)點(diǎn)標(biāo)注它可能出現(xiàn)的瓶頸。用戶一多最先扛不住的往往不是模型API而是前面這些看似輕量的環(huán)節(jié)環(huán)節(jié)可能瓶頸常用應(yīng)對(duì)手段API網(wǎng)關(guān)連接數(shù)上限、限流誤傷水平擴(kuò)容、按用戶/按IP分級(jí)限流會(huì)話存儲(chǔ)Redis連接/內(nèi)存瓶頸集群化、冷熱分層Prompt組裝模板渲染耗時(shí)緩存編譯后的模板模型調(diào)用API限流、排隊(duì)延遲并發(fā)池、隊(duì)列削峰、多路降級(jí)熱點(diǎn)數(shù)據(jù)緩存緩存失效擊穿本地緩存分布式鎖外部工具第三方API限流熔斷、退避重試這些瓶頸不是等線上報(bào)警了才去加而是在畫架構(gòu)圖時(shí)就要標(biāo)出來。我習(xí)慣在每條鏈路旁邊寫一行假設(shè)模型響應(yīng)3秒Agent最多調(diào)用5次則用戶最長(zhǎng)體驗(yàn)是15秒如果這個(gè)數(shù)字超過產(chǎn)品預(yù)期就要考慮并行調(diào)用工具、提前預(yù)取檢索結(jié)果甚至改異步交互模式。3.2 狀態(tài)管理無狀態(tài)化與外部化會(huì)話Agent應(yīng)用最容易被忽視的架構(gòu)問題就是狀態(tài)放哪。如果你把對(duì)話歷史、Agent的中間思考、工具調(diào)用結(jié)果都放在服務(wù)進(jìn)程的內(nèi)存里那么一旦服務(wù)實(shí)例重啟、擴(kuò)容或縮容用戶會(huì)話就全丟了。更要命的是負(fù)載均衡很難做——同一用戶的請(qǐng)求必須一直打回同一個(gè)實(shí)例。解決辦法是讓服務(wù)無狀態(tài)把狀態(tài)全部外部化。最常見的手段是用Redis存會(huì)話狀態(tài)鍵通常是session:{userId}值是一個(gè)對(duì)象包含消息列表、Agent當(dāng)前階段、已調(diào)用工具的結(jié)果、剩余步數(shù)等。每次請(qǐng)求進(jìn)來編排層從Redis讀取狀態(tài)執(zhí)行完一步再把新的狀態(tài)寫回去。這里的細(xì)節(jié)是狀態(tài)粒度。粒度太粗整個(gè)對(duì)話歷史塞成一個(gè)對(duì)象更新頻繁時(shí)Redis網(wǎng)絡(luò)開銷很大粒度太細(xì)每次要串行讀好幾份Key反而變慢。我的經(jīng)驗(yàn)是把高頻變化的部分比如當(dāng)前step、pending tool call和低頻變化的部分比如消息列表分開存或者用Hash結(jié)構(gòu)一個(gè)Key下多個(gè)Field按需更新。架構(gòu)圖上要明確標(biāo)出狀態(tài)讀寫路徑和狀態(tài)失效策略不然代碼寫著寫著就會(huì)變成內(nèi)存緩存和Redis之間互相打架。3.3 隊(duì)列與批處理從同步到異步的取舍并非所有AI應(yīng)用請(qǐng)求都必須實(shí)時(shí)同步返回。如果你讓用戶在一個(gè)界面里等待Agent跑完五輪工具調(diào)用體驗(yàn)大概率是崩潰的。架構(gòu)上一個(gè)經(jīng)典解法是引入任務(wù)隊(duì)列把重計(jì)算和輕響應(yīng)分離開??梢赃@樣想象同步鏈路只負(fù)責(zé)接收用戶請(qǐng)求、創(chuàng)建任務(wù)、立刻返回一個(gè)任務(wù)ID然后由后臺(tái)Worker異步處理Agent循環(huán)處理完成后通過WebSocket或輪詢通知前端。這種模式特別適合分析報(bào)告生成、批量文檔審核、自動(dòng)化工作流這類耗時(shí)任務(wù)。但在做異步化之前要分清場(chǎng)景。用戶和機(jī)器人聊天這種強(qiáng)交互場(chǎng)景異步會(huì)破壞對(duì)話連續(xù)性但如果任務(wù)本身就要跑幾十秒異步幾乎是唯一選擇。我的取舍原則是預(yù)期耗時(shí)大于5秒就考慮異步化大于30秒必須異步化需要用戶等待且可能排隊(duì)就上隊(duì)列加優(yōu)先級(jí)。畫架構(gòu)圖時(shí)我會(huì)在接入層和編排層之間加一個(gè)任務(wù)分發(fā)器再在編排層旁邊畫一個(gè)結(jié)果存儲(chǔ)這就是異步化的標(biāo)準(zhǔn)畫法。3.4 彈性伸縮模型推理的并發(fā)控制即便你做好了網(wǎng)關(guān)和隊(duì)列模型本身的并發(fā)能力仍然是致命的約束。大模型推理不像普通HTTP接口它有時(shí)間很長(zhǎng)的占用過程GPU顯存和算力有限并發(fā)一旦超過閾值排隊(duì)時(shí)間指數(shù)上升最終表現(xiàn)為整體服務(wù)的P99延遲變得不可接受。這里有三個(gè)詞大家容易混淆并發(fā)請(qǐng)求數(shù)、吞吐量和響應(yīng)時(shí)間。模型服務(wù)能承載的并發(fā)是有限的假設(shè)它每秒鐘能完整推理4個(gè)請(qǐng)求平均耗時(shí)2秒并不意味著同時(shí)并發(fā)8個(gè)請(qǐng)求也沒問題——因?yàn)槟P屯评硎欠峙某龅恼?qǐng)求會(huì)在隊(duì)列里等待可能從2秒飆到4秒。所以在接入層和模型網(wǎng)關(guān)之間一定要有一層并發(fā)控制用信號(hào)量限制同時(shí)發(fā)給模型服務(wù)的請(qǐng)求數(shù)寧可讓請(qǐng)求在隊(duì)列里等也不要把后端打爆。如果你自建模型服務(wù)還可以用連續(xù)批處理continuous batching和動(dòng)態(tài)批大小來提高吞吐。如果是調(diào)用外部API沒有這個(gè)控制權(quán)就只能在網(wǎng)關(guān)層做請(qǐng)求合并、多級(jí)緩存和主動(dòng)退避。架構(gòu)圖上要給并發(fā)控制器一個(gè)獨(dú)立的位置并寫明最大并發(fā)數(shù)和隊(duì)列長(zhǎng)度這些參數(shù)必須經(jīng)過壓測(cè)不能拍腦袋。4. 數(shù)據(jù)流與上下文工程喂給模型的內(nèi)容決定天花板4.1 上下文窗口是硬約束架構(gòu)要為它服務(wù)大模型的能力邊界和上下文窗口強(qiáng)相關(guān)。哪怕最新的模型支持超長(zhǎng)上下文你也不可能把整個(gè)業(yè)務(wù)數(shù)據(jù)庫都塞進(jìn)一次請(qǐng)求里。上下文就是AI應(yīng)用架構(gòu)中的數(shù)據(jù)總線什么數(shù)據(jù)能進(jìn)入Prompt以什么順序進(jìn)入如何控制token預(yù)算直接決定了模型輸出的質(zhì)量。在架構(gòu)設(shè)計(jì)時(shí)我需要一個(gè)專門的上下文組裝器模塊。它負(fù)責(zé)三件事從外部存儲(chǔ)取回會(huì)話歷史通過RAG檢索取回相關(guān)知識(shí)片段把當(dāng)前用戶意圖和候選工具定義拼裝成最終發(fā)送給模型的Prompt。這個(gè)模塊要能動(dòng)態(tài)裁剪比如歷史太長(zhǎng)時(shí)自動(dòng)保留最近的幾輪再加一個(gè)壓縮后的摘要知識(shí)片段太多時(shí)按相關(guān)性排序后只取Top K。很多人忽略的一點(diǎn)是上下文組裝器是純邏輯模塊但它必須緩存。模型調(diào)用結(jié)果、檢索結(jié)果、Prompt模板的編譯結(jié)果都可以緩存避免同一份數(shù)據(jù)反復(fù)去做向量檢索也避免重復(fù)調(diào)用模型。畫架構(gòu)圖時(shí)我會(huì)把上下文組裝器畫在編排層和模型層之間并在它內(nèi)部標(biāo)注輸入過濾器和輸出解析器兩個(gè)子模塊一個(gè)防止臟數(shù)據(jù)進(jìn)Prompt一個(gè)防止非JSON結(jié)果崩掉業(yè)務(wù)解析。4.2 RAG檢索增強(qiáng)從參數(shù)記憶到外部記憶大模型本身就像一個(gè)壓縮過的記憶體參數(shù)里存了海量知識(shí)但它是靜態(tài)的不知道你最新的產(chǎn)品文檔、客戶溝通記錄和內(nèi)部政策。RAG檢索增強(qiáng)生成就是用外部數(shù)據(jù)源給模型補(bǔ)充臨時(shí)記憶讓它在回答時(shí)能基于最新資料。RAG架構(gòu)畫出來并不復(fù)雜離線環(huán)節(jié)把文檔切塊、向量化、寫入向量庫在線環(huán)節(jié)把用戶問題轉(zhuǎn)成向量去向量庫召回相關(guān)片段再拼進(jìn)Prompt。但真正考架構(gòu)經(jīng)驗(yàn)的是細(xì)節(jié)。文檔切分chunk尤其折磨人切太碎語義不完整切太大召回噪音高。切好后還要做清洗、去重、權(quán)限過濾否則模型可能把不該透露的內(nèi)部信息回答給用戶。我建議在數(shù)據(jù)層里增加一個(gè)文檔處理管道它不是一個(gè)簡(jiǎn)單的腳本而是一個(gè)可重放、可追蹤的任務(wù)隊(duì)列。原始文檔進(jìn)來經(jīng)過去重、切分、向量化、寫庫每一步都要記錄狀態(tài)這樣文檔重復(fù)上傳也能增量更新。檢索端也不要只用一個(gè)向量相似度可以加上關(guān)鍵詞權(quán)重、業(yè)務(wù)過濾條件、時(shí)間排序甚至再接一個(gè)重排模型做二次精排。這些都叫架構(gòu)不只是調(diào)一個(gè)向量庫的API。4.3 上下文管理策略截?cái)?、壓縮與摘要記憶長(zhǎng)對(duì)話是AI應(yīng)用最常見的場(chǎng)景但聊著聊著歷史越長(zhǎng)成本越高響應(yīng)也越慢模型還可能被遙遠(yuǎn)的早期信息干擾。架構(gòu)上最常見的三種策略是截?cái)?、壓縮和摘要記憶。截?cái)嘧詈?jiǎn)單保留最近N輪對(duì)話超過的部分直接丟棄。代價(jià)是模型可能忘掉開頭用戶說過的關(guān)鍵需求。壓縮是讓模型把舊對(duì)話改寫成更精簡(jiǎn)的表達(dá)保留關(guān)鍵信息的同時(shí)降低token占用。摘要記憶更進(jìn)一步維護(hù)一個(gè)長(zhǎng)期摘要每次對(duì)話結(jié)束就把新信息合并進(jìn)摘要下次請(qǐng)求時(shí)把摘要放在對(duì)話最前面后面跟隨最近幾輪原始消息。我實(shí)際做過的方案是滾動(dòng)窗口加摘要混合模式系統(tǒng)維護(hù)一個(gè)全局摘要始終放進(jìn)Prompt再維護(hù)最近十輪原始消息按時(shí)間正序排列如果近十輪的信息量和摘要沖突以原始消息為準(zhǔn)。這個(gè)模式在多數(shù)客服、助手類應(yīng)用里表現(xiàn)相當(dāng)穩(wěn)定。而且摘要本身是異步更新的不需要每輪對(duì)話都重新生成可以等用戶停頓幾秒后再觸發(fā)一次后臺(tái)摘要更新避免用戶等待時(shí)間翻倍。4.4 工具調(diào)用后的數(shù)據(jù)回寫閉環(huán)當(dāng)AI應(yīng)用開始調(diào)用外部工具數(shù)據(jù)流就從一個(gè)簡(jiǎn)單的人→模型→人變成了人→模型→工具→模型→人的閉環(huán)。工具返回的數(shù)據(jù)往往不能原樣塞進(jìn)上下文。一個(gè)查詢金融數(shù)據(jù)庫的工具可能返回幾千條記錄直接塞進(jìn)Prompttoken瞬間爆炸且模型會(huì)被無關(guān)字段干擾。架構(gòu)上應(yīng)在工具調(diào)用服務(wù)和上下文組裝器之間加一層結(jié)果處理器它的任務(wù)是按業(yè)務(wù)規(guī)則裁剪字段只保留模型需要的結(jié)果把結(jié)構(gòu)化數(shù)據(jù)轉(zhuǎn)成自然語言摘要如果結(jié)果太多再做一級(jí)聚合統(tǒng)計(jì)。比如查銷售訂單不返回300行明細(xì)而是返回總訂單數(shù)、總金額、TOP3客戶、同比變化這樣的精簡(jiǎn)摘要。工具調(diào)用的另一個(gè)坑是冪等與重試。很多外部工具不支持天然冪等你重試一次可能就下了兩個(gè)訂單。AI Agent在工具超時(shí)時(shí)很容易下意識(shí)重試架構(gòu)上必須給每次工具調(diào)用生成一個(gè)唯一的traceId并且在調(diào)外部接口時(shí)把traceId透?jìng)鬟^去配合外部系統(tǒng)的冪等鍵。這個(gè)細(xì)節(jié)不畫在架構(gòu)圖上等到線上出了重復(fù)扣款再回頭補(bǔ)就晚了。5. 從單Agent到多Agent協(xié)作架構(gòu)復(fù)雜度的躍遷5.1 單Agent架構(gòu)的簡(jiǎn)化模型我們先看看單個(gè)Agent的架構(gòu)是什么樣子。畫成狀態(tài)圖它就是一個(gè)循環(huán)初始狀態(tài)接收用戶輸入 → 推理階段決定下一步動(dòng)作 → 如果動(dòng)作是調(diào)用工具執(zhí)行工具并返回結(jié)果 → 更新上下文 → 重新推理 → 如果動(dòng)作是生成最終回答結(jié)束循環(huán)。這個(gè)模型能覆蓋很多業(yè)務(wù)比如客服助手、文檔問答、代碼生成助手。單Agent的關(guān)鍵優(yōu)勢(shì)是鏈路短問題定位簡(jiǎn)單資源消耗可控。我在項(xiàng)目里有一個(gè)原則能用單Agent解決的絕不輕易上多Agent。因?yàn)槎郃gent不是免費(fèi)的性能升級(jí)而是實(shí)打?qū)嵉募軜?gòu)復(fù)雜度。但單Agent有一個(gè)天然上限一個(gè)模型循環(huán)里的工具選擇、判斷條件、狀態(tài)控制都堆在一起業(yè)務(wù)規(guī)則稍微復(fù)雜一點(diǎn)Prompt就變得臃腫模型經(jīng)常在多個(gè)工具之間猶豫甚至把不該調(diào)的工具調(diào)了。當(dāng)你發(fā)現(xiàn)單個(gè)Agent的角色太多任務(wù)類型差異太大一個(gè)循環(huán)已經(jīng)難以穩(wěn)定控制時(shí)就該考慮拆分。5.2 多Agent協(xié)作模式與通信協(xié)議多Agent協(xié)作本質(zhì)上是在AI應(yīng)用里引入了多角色和消息傳遞。我見過最樸素的做法是讓幾個(gè)Agent函數(shù)互相調(diào)用最后把結(jié)果拼到一個(gè)主Prompt里。這種假多Agent做得多了會(huì)發(fā)現(xiàn)一個(gè)嚴(yán)重問題沒有統(tǒng)一的Agent間通信協(xié)議任務(wù)狀態(tài)、錯(cuò)誤處理、超時(shí)全部靠參數(shù)硬傳代碼根本不可維護(hù)。真正要做多Agent第一步是定義Agent之間的消息結(jié)構(gòu)。我的建議是每條消息至少包含任務(wù)ID、源Agent、目標(biāo)Agent、任務(wù)類型、Payload、狀態(tài)、錯(cuò)誤信息、時(shí)間戳。目標(biāo)Agent是可以路由過去的如果采用訂閱或事件驅(qū)動(dòng)還要有事件主題。協(xié)議定清楚之后Agent之間就不再是函數(shù)調(diào)用而更像服務(wù)之間發(fā)送消息這也讓日志追蹤變得可行。另一個(gè)問題是任務(wù)分配和結(jié)果回收。主管Agent分下去的任務(wù)執(zhí)行Agent完成后結(jié)果要按任務(wù)ID回收到正確的位置一旦某個(gè)子任務(wù)失敗主管要決定是重試還是換一種路徑。這背后是有狀態(tài)的狀態(tài)機(jī)管理建議放在編排層統(tǒng)一維護(hù)不要讓每個(gè)Agent各自維護(hù)我是誰、我該找誰。5.3 編排者-工作者、管道、圖譜三種拓?fù)涠郃gent協(xié)作不是只有一個(gè)模式畫圖時(shí)我常用三種拓?fù)渚幣耪?工作者Orchestrator-Workers一個(gè)主導(dǎo)Agent負(fù)責(zé)分析整體目標(biāo)、拆分任務(wù)、派發(fā)給多個(gè)工作Agent再收集結(jié)果并匯總成最終輸出。適合需要拆解多個(gè)獨(dú)立子任務(wù)的場(chǎng)景比如寫一份行業(yè)分析報(bào)告可以拆成數(shù)據(jù)收集、政策解讀、競(jìng)品分析、圖表生成等多個(gè)子任務(wù)。優(yōu)點(diǎn)是控制集中劣勢(shì)是主導(dǎo)Agent可能成為瓶頸如果任務(wù)拆得太多編排者自己就亂了。管道PipelineAgent按固定順序執(zhí)行前一個(gè)的輸出是后一個(gè)的輸入。比如先做意圖識(shí)別再做實(shí)體抽取再生成回復(fù)。這種拓?fù)溥m合流水線式的固定流程延遲可控但靈活性差無法應(yīng)對(duì)分叉和回溯。圖譜Graph把各個(gè)Agent節(jié)點(diǎn)按條件路由連接起來允許分支、循環(huán)、并行而且支持條件判斷。LangGraph就是這種思路。它最靈活也最復(fù)雜需要單獨(dú)的運(yùn)行時(shí)和狀態(tài)管理。拓?fù)鋬?yōu)點(diǎn)缺點(diǎn)適用場(chǎng)景編排者-工作者控制集中、易于審計(jì)編排者易成瓶頸、任務(wù)拆分難度大子任務(wù)相互獨(dú)立的復(fù)雜任務(wù)管道簡(jiǎn)單、延遲低固定流程、難擴(kuò)展處理步驟固定且順序確定圖譜高度靈活、支持分支循環(huán)狀態(tài)管理復(fù)雜、調(diào)試門檻高決策路徑多且條件多變的業(yè)務(wù)我用得比較多的組合是管道 圖譜主流程用明確的鏈路但鏈路在某個(gè)關(guān)鍵節(jié)點(diǎn)上分叉用圖譜的條件路由選出不同分支。純圖譜模式對(duì)于大部分中小團(tuán)隊(duì)來說維護(hù)成本太高容易畫得好看落地上卻變成一團(tuán)亂麻。5.4 多Agent場(chǎng)景下的可觀測(cè)性與容錯(cuò)多Agent系統(tǒng)最怕的是什么不是某個(gè)Agent答得不好而是整條鏈路黑盒。用戶說我要退款主管Agent分給客服Agent客服Agent調(diào)了訂單系統(tǒng)結(jié)果訂單系統(tǒng)超時(shí)客服Agent又嘗試了一次最后主管Agent匯總了一個(gè)錯(cuò)誤的結(jié)論說退款已發(fā)起。如果沒有鏈路追蹤你根本不知道是哪一步出了問題??捎^測(cè)性在多Agent架構(gòu)里不是可選項(xiàng)而是基礎(chǔ)設(shè)施。我給每個(gè)Agent調(diào)用鏈都設(shè)計(jì)一個(gè)統(tǒng)一的traceId貫穿用戶請(qǐng)求進(jìn)入、編排器決策、工作Agent執(zhí)行、工具調(diào)用、模型返回的每一個(gè)環(huán)節(jié)。每個(gè)環(huán)節(jié)記錄輸入輸出摘要、token消耗、延遲、狀態(tài)碼。這套東西可以用OpenTelemetry標(biāo)準(zhǔn)做但真正重要的是日志里要有語義化的字段能支持你回答這個(gè)Agent當(dāng)時(shí)為什么調(diào)用那個(gè)工具。容錯(cuò)機(jī)制同樣要前置。在架構(gòu)圖上我會(huì)給每個(gè)Agent節(jié)點(diǎn)周圍畫上重試、超時(shí)、熔斷、降級(jí)四道保險(xiǎn)。比如子Agent連續(xù)失敗兩次就不要再盲目重試而是讓主管Agent換一種表達(dá)或換一個(gè)工具路徑整體鏈路超時(shí)就返回一個(gè)預(yù)設(shè)的兜底回答而不是讓用戶無限等待。沒有這些保險(xiǎn)多Agent系統(tǒng)上線后大概率每天都要靠人工背鍋。6. 架構(gòu)落地時(shí)的隱藏成本與決策清單6.1 延遲、成本、準(zhǔn)確率的三難權(quán)衡AI應(yīng)用架構(gòu)到最后很多決策都不是能不能做而是值不值得做。在架構(gòu)評(píng)審時(shí)我最常拋出的三難問題是延遲低、成本低、準(zhǔn)確率高你要哪個(gè)答案往往是全都要但現(xiàn)實(shí)必須取舍。一個(gè)典型場(chǎng)景是RAG檢索。多加兩路檢索、再過一個(gè)重排模型準(zhǔn)確率大概率上升但延遲會(huì)增加200到500毫秒成本也會(huì)增加。另一個(gè)典型場(chǎng)景是模型選型旗艦?zāi)P托Ч詈玫F輕量模型便宜但復(fù)雜推理容易翻車。架構(gòu)設(shè)計(jì)可以引入模型路由來緩解簡(jiǎn)單意圖走輕量模型復(fù)雜推理走旗艦?zāi)P?。但模型路由本身也要?jì)算成本你需要一個(gè)統(tǒng)計(jì)平臺(tái)來估算不同策略的總體成本。我做得最多的一件事就是對(duì)線上請(qǐng)求做標(biāo)簽化分析。把所有請(qǐng)求按業(yè)務(wù)類型、模型消耗、token數(shù)量、響應(yīng)延遲打上標(biāo)簽定期復(fù)盤哪些請(qǐng)求其實(shí)不需要那么大模型、哪些檢索可以加緩存。架構(gòu)不是靜態(tài)圖它應(yīng)該是一個(gè)會(huì)根據(jù)數(shù)據(jù)持續(xù)演化的動(dòng)態(tài)系統(tǒng)。6.2 評(píng)測(cè)體系沒有指標(biāo)架構(gòu)就無從迭代很多團(tuán)隊(duì)在AI應(yīng)用架構(gòu)上折騰了半天最后連效果變好了還是變壞了都說不清。沒有評(píng)測(cè)體系的架構(gòu)設(shè)計(jì)就像沒有測(cè)試的代碼重構(gòu)隨時(shí)可能倒退。所以我建議在架構(gòu)設(shè)計(jì)一開始就搭一套離線評(píng)測(cè)集。把典型用戶問題、期望回答、各類邊界場(chǎng)景整理成幾十到幾百條測(cè)試用例每次架構(gòu)調(diào)整后跑一遍評(píng)測(cè)對(duì)比通過率和輸出質(zhì)量。更進(jìn)一步還要有在線監(jiān)控統(tǒng)計(jì)用戶點(diǎn)贊、點(diǎn)踩、對(duì)話放棄率、回答被修改率。沒有這些指標(biāo)你真不知道該把成本投入在更復(fù)雜的Agent編排還是更優(yōu)秀的Prompt。在評(píng)測(cè)集里我特別強(qiáng)調(diào)對(duì)抗樣本。比如用戶故意問和知識(shí)庫無關(guān)的問題、給出模棱兩可的指令、或者要求模型執(zhí)行超出權(quán)限的動(dòng)作。這類樣本在架構(gòu)評(píng)審時(shí)能暴露很多設(shè)計(jì)缺陷。一個(gè)Agent架構(gòu)如果連對(duì)抗樣本都過不了上線之后必然被真實(shí)用戶折磨。6.3 一張架構(gòu)決策檢查清單最后分享一張我常用的架構(gòu)決策檢查清單每做一個(gè)AI應(yīng)用我都會(huì)對(duì)著過一遍決策點(diǎn)檢查問題關(guān)鍵考量接入方式用戶請(qǐng)求如何進(jìn)系統(tǒng)是否有統(tǒng)一API網(wǎng)關(guān)認(rèn)證、限流、審計(jì)、冪等模型接入是否通過模型網(wǎng)關(guān)統(tǒng)一接多個(gè)模型密鑰管理、模型路由、降級(jí)會(huì)話狀態(tài)狀態(tài)放在服務(wù)內(nèi)存還是外部存儲(chǔ)擴(kuò)展性、容災(zāi)、跨實(shí)例一致性上下文管理是否有獨(dú)立的上下文組裝器token預(yù)算、歷史截?cái)?、摘要策略外部記憶是否需要RAG用向量庫還是普通數(shù)據(jù)庫數(shù)據(jù)規(guī)模、過濾需求、更新頻率Agent編排單Agent夠用還是需要多Agent用哪種拓?fù)淙蝿?wù)復(fù)雜度、調(diào)試成本、可觀測(cè)性并發(fā)控制是否限制了模型層并發(fā)有沒有隊(duì)列削峰延遲SLA、API限流、成本容錯(cuò)機(jī)制超時(shí)、重試、熔斷、降級(jí)是否都到位錯(cuò)誤恢復(fù)、用戶體驗(yàn)評(píng)測(cè)監(jiān)控是否有離線評(píng)測(cè)集和在線監(jiān)控效果可度量、回歸可發(fā)現(xiàn)這張清單不一定覆蓋所有業(yè)務(wù)但至少能幫你把架構(gòu)圖里的空白補(bǔ)齊。每你對(duì)著它畫一遍通常就能發(fā)現(xiàn)一兩個(gè)之前沒考慮到的風(fēng)險(xiǎn)點(diǎn)。我個(gè)人的體會(huì)是AI應(yīng)用架構(gòu)設(shè)計(jì)最大的難點(diǎn)不是技術(shù)選型多酷而是能不能在復(fù)雜度和業(yè)務(wù)價(jià)值之間找到平衡。一張架構(gòu)畫得好不好不在于線條多漂亮而在于它能不能讓你一眼看出系統(tǒng)的薄弱環(huán)節(jié)在哪。從模型網(wǎng)關(guān)到上下文管理從單Agent到多Agent每一步都是取舍。先把圖畫清楚再動(dòng)手寫代碼這個(gè)習(xí)慣幫我省過太多了線上救火的時(shí)間。