的智能體網(wǎng)關(guān)實(shí)踐)
上個(gè)月凌晨兩點(diǎn)我被生產(chǎn)環(huán)境的告警電話叫醒。一個(gè)面向內(nèi)部運(yùn)營團(tuán)隊(duì)的客服智能體突然對(duì)超過三成的用戶請(qǐng)求沉默——不是模型沒推理而是消息根本沒能送達(dá)到那個(gè)Agent實(shí)例。排查了一小時(shí)發(fā)現(xiàn)是路由層配置里一個(gè)很不起眼的超時(shí)參數(shù)被改小了Agent側(cè)明明已經(jīng)處理完回復(fù)卻因?yàn)槌瑫r(shí)被網(wǎng)關(guān)當(dāng)作失敗丟棄。那一刻我意識(shí)到當(dāng)Agent從一個(gè)孤立的聊天機(jī)器人變成一群需要互相協(xié)作、由不同團(tuán)隊(duì)維護(hù)、跑在不同環(huán)境里的分布式單元時(shí)怎么把請(qǐng)求可靠地送到正確的Agent手里這件事已經(jīng)比怎么訓(xùn)練一個(gè)更好的提示詞重要得多。Agent-Reach這個(gè)項(xiàng)目就是在這種背景下被我認(rèn)真做起來的。Agent-Reach是一個(gè)智能體觸達(dá)網(wǎng)關(guān)解決的核心問題是當(dāng)你有一套或很多套Agent服務(wù)時(shí)外部請(qǐng)求應(yīng)該如何穩(wěn)定、可路由、可觀測地分發(fā)到正確的Agent實(shí)例上并把結(jié)果可靠地返回。它不負(fù)責(zé)Agent的推理邏輯只負(fù)責(zé)觸達(dá)這件事——誰該被觸達(dá)、以什么協(xié)議觸達(dá)、觸達(dá)失敗怎么辦、整個(gè)鏈路有沒有被完整記錄。標(biāo)題里的Reach其實(shí)是雙關(guān)一個(gè)意思是覆蓋即任何類型的Agent都能接入另一個(gè)意思是觸達(dá)即請(qǐng)求真正落到Agent手里并拿到響應(yīng)。這篇文章我會(huì)從最初的設(shè)計(jì)動(dòng)機(jī)講起把協(xié)議選型、路由策略、可觀測性建設(shè)以及上線后被真實(shí)流量教育過的幾個(gè)坑全部攤開說。1. 從一次凌晨的生產(chǎn)事故說起Agent觸達(dá)為什么會(huì)失效1.1 事故復(fù)盤問題不在模型而在連接那天的故障表象是客服Agent不回復(fù)但翻到Gateway的日志就發(fā)現(xiàn)所有請(qǐng)求其實(shí)都成功推給了Agent側(cè)的消息隊(duì)列Agent也確實(shí)消費(fèi)并產(chǎn)出了回復(fù)。問題出在回程鏈路上Agent通過HTTP回調(diào)把結(jié)果送回網(wǎng)關(guān)因?yàn)榛卣{(diào)超時(shí)閾值被某位同事從5秒收緊到3秒導(dǎo)致大量晚到的回復(fù)被網(wǎng)關(guān)直接丟棄。用戶看到的自然就是石沉大海。這件事讓我重新審視了團(tuán)隊(duì)里所有Agent的集成方式。當(dāng)時(shí)每個(gè)Agent都是各自為政有的是通過WebSocket長連維持一個(gè)常駐會(huì)話有的只暴露REST API由調(diào)用方同步等待有的是異步任務(wù)型提交后靠輪詢拿結(jié)果。調(diào)用方要同時(shí)處理三種協(xié)議、兩套鑒權(quán)體系加上每個(gè)Agent的超時(shí)策略還不一樣——線下跑通很容易線上一起抖動(dòng)就各種花式超時(shí)、重放、丟消息。當(dāng)時(shí)我們自嘲說這不是在調(diào)Agent是在調(diào)一套手工拼裝的分布式消息系統(tǒng)。1.2 Reach的雙關(guān)覆蓋面和響應(yīng)力的失衡這件事背后其實(shí)是一個(gè)更普遍的問題單Agent時(shí)代你只需要關(guān)注人機(jī)對(duì)話鏈路多Agent協(xié)作時(shí)代流程被切碎成了大量跨服務(wù)調(diào)用任何一個(gè)跳點(diǎn)都可能成為信號(hào)盲區(qū)。我做Agent-Reach時(shí)首先想清楚的就是網(wǎng)關(guān)不應(yīng)該是一個(gè)聰明的路由器而應(yīng)該是一個(gè)保證送達(dá)的中間人——它關(guān)心的不是Agent怎么思考而是Agent值不值得被信任地調(diào)用。所以Reach被我拆成兩個(gè)指標(biāo)來定義覆蓋率Coverage系統(tǒng)里有哪幾種Agent接入方式網(wǎng)關(guān)都能不能接住觸達(dá)成功率Reachability請(qǐng)求從入網(wǎng)到出網(wǎng)端到端的成功比例。故障發(fā)生后我復(fù)盤出的結(jié)論是覆蓋率再高只要觸達(dá)成功率不是99.9%以上企業(yè)場景里就沒人敢用。這也是Agent-Reach后續(xù)一切設(shè)計(jì)的原點(diǎn)和驗(yàn)收標(biāo)準(zhǔn)。2. Agent-Reach要解決的核心問題把觸達(dá)能力從業(yè)務(wù)代碼里抽出來2.1 拆解前的集成痛點(diǎn)如果你稍微調(diào)研一圈企業(yè)內(nèi)部Agent落地情況會(huì)發(fā)現(xiàn)一個(gè)普遍規(guī)律業(yè)務(wù)系統(tǒng)直接調(diào)用Agent API時(shí)代碼里藏著大量和智能體無關(guān)的臟活。一個(gè)典型的調(diào)用場景大概是這樣的def call_agent(agent_name, payload): # 誰知道這個(gè)Agent用的是http還是ws先查配置 endpoint registry.get_endpoint(agent_name) if endpoint.protocol http: resp requests.post(endpoint.url, jsonpayload, timeout3) elif endpoint.protocol ws: # 又得維護(hù)一個(gè)WebSocket連接池還得處理重連... # 調(diào)用完之后還要手動(dòng)打日志、手動(dòng)重試、手動(dòng)判斷是不是消息重復(fù)...這種代碼最大的問題不是難看而是每個(gè)業(yè)務(wù)團(tuán)隊(duì)都在重復(fù)實(shí)現(xiàn)同樣的觸達(dá)邏輯而且實(shí)現(xiàn)得都不完整。有人忘了重試有人重試導(dǎo)致Agent側(cè)重復(fù)執(zhí)行了危險(xiǎn)操作有人把超時(shí)設(shè)成10秒讓用戶干等有人壓根沒接入鏈路追蹤。一個(gè)Agent要在N個(gè)業(yè)務(wù)系統(tǒng)里被調(diào)用就有N個(gè)版本的殘次品集成層。2.2 網(wǎng)關(guān)模式的決定為什么不是SDK也不是全托管平臺(tái)當(dāng)時(shí)擺在我面前有三條路做一套標(biāo)準(zhǔn)SDK讓所有業(yè)務(wù)方通過SDK調(diào)用Agent做一個(gè)完全托管的Agent編排平臺(tái)把Agent注冊(cè)、調(diào)度、編排全做進(jìn)去做一個(gè)輕量觸達(dá)網(wǎng)關(guān)只負(fù)責(zé)接入、路由、分發(fā)、可靠性。我最終選擇3有一個(gè)很現(xiàn)實(shí)的原因團(tuán)隊(duì)Agent的技術(shù)棧各異、部署形態(tài)各異有的在Kubernetes里跑有的還在舊虛擬機(jī)環(huán)境有的甚至是以腳本形式周期執(zhí)行的。SDK需要改動(dòng)每個(gè)業(yè)務(wù)方的代碼推廣成本極高全托管平臺(tái)看著美但要把存量Agent全部改造遷移基本等于做一個(gè)新項(xiàng)目。網(wǎng)關(guān)則是在所有人中間站一個(gè)公共節(jié)點(diǎn)業(yè)務(wù)方只需要把請(qǐng)求發(fā)給網(wǎng)關(guān)網(wǎng)關(guān)負(fù)責(zé)搞定背后的一切對(duì)存量的侵入最小。注意這里說的網(wǎng)關(guān)不是API Gateway那種HTTP反向代理它本質(zhì)上是一個(gè)帶狀態(tài)的消息路由層。API Gateway關(guān)注請(qǐng)求轉(zhuǎn)發(fā)、鑒權(quán)、限流Agent觸達(dá)網(wǎng)關(guān)還必須關(guān)注異步確認(rèn)、會(huì)話狀態(tài)、重試策略、Agent存活感知——這些才是讓Agent真的能被業(yè)務(wù)信任的關(guān)鍵。2.3 目錄式的Agent注冊(cè)讓每個(gè)智能體都有名字Agent-Reach做起來的第一件事不是畫架構(gòu)圖而是設(shè)計(jì)Agent注冊(cè)目錄。我給Agent定了幾個(gè)最小元數(shù)據(jù)注冊(cè)上去才能被路由agent_id: code-review-agent display_name: 代碼評(píng)審Agent version: 2.4.1 protocol: v1.hybrid endpoints: - type: task_submit url: https://svc.internal/v2/async/task - type: status_query url: https://svc.internal/v2/async/status transport: - websocket - http-callback capabilities: - review_pull_request - detect_security_vulnerability - suggest_refactoring routing_tags: team: platform-engineering model_profile: gpt-4o-mini latency_sla: medium這套注冊(cè)表的價(jià)值后來被驗(yàn)證得很充分它讓路由不再靠寫死的if-else而是變成對(duì)注冊(cè)數(shù)據(jù)的查詢。新Agent接入不必改網(wǎng)關(guān)代碼只需要提交一份這樣的注冊(cè)信息。這直接推高了覆蓋率——第一個(gè)月就有十一個(gè)不同類型的Agent接入其中三個(gè)完全沒有經(jīng)過我手自己看著文檔就注冊(cè)成功了。3. 協(xié)議與消息模型讓不同技術(shù)棧的Agent能說上話3.1 統(tǒng)一Envelope的設(shè)計(jì)取舍Agent之間的通信最煩的一點(diǎn)是不同Agent的說法不一樣。有的Agent把用戶問題和上下文一起放在body里的message字段有的把上下文放到meta里還有的接受JSON純字符串。如果網(wǎng)關(guān)不做統(tǒng)一封裝那么路由、重試、追蹤全都無從談起——你連哪個(gè)字段代表這次請(qǐng)求的唯一ID都找不出來。Agent-Reach定義了一套輕量的Envelope協(xié)議所有進(jìn)出網(wǎng)關(guān)的消息都被包一層統(tǒng)一的信封{ envelope: { api_version: 1.0, trace_id: c4a2f1e7-9d1b-4a2e-8c5a-1f9e3b2d7c01, message_id: msg_01HZ9KZ5T2M8VQ4B, agent_id: code-review-agent, session_id: sess_8f61, timestamp: 2025-06-12T14:23:1108:00, timeout_hint: 30 }, payload: {} }有幾個(gè)點(diǎn)值得多說一句trace_id是每次用戶請(qǐng)求鏈路全局唯一的所有Agent和網(wǎng)關(guān)日志都必須帶它message_id是網(wǎng)關(guān)發(fā)的Agent測回執(zhí)時(shí)要帶上它保證哪些消息已經(jīng)被確認(rèn)可以對(duì)齊timeout_hint是網(wǎng)關(guān)建議Agent在多少秒內(nèi)完成避免不同Agent默認(rèn)響應(yīng)時(shí)間不一致。要說明的是這個(gè)設(shè)計(jì)不是為了規(guī)定Agent內(nèi)部怎么寫代碼而是給觸達(dá)過程找一個(gè)公共坐標(biāo)系。Agent收到Envelope后可以把payload解析成自己的內(nèi)部結(jié)構(gòu)但回執(zhí)和日志必須遵循Envelope否則網(wǎng)關(guān)只管送到后續(xù)有沒有處理就抓瞎了。3.2 多通道適配WebSocket、消息隊(duì)列、HTTP回調(diào)協(xié)議統(tǒng)一之后真正麻煩的是通道適配?,F(xiàn)實(shí)世界里Agent可觸達(dá)的方式五花八門。Agent-Reach里我做了四個(gè)適配器適配器之間用同一個(gè)內(nèi)部事件總線連接這樣新通道可以只實(shí)現(xiàn)統(tǒng)一接口就接進(jìn)來。通道類型適用場景關(guān)鍵問題HTTP同步調(diào)用Agent處理快、結(jié)果即時(shí)返回超時(shí)設(shè)置、重試安全性HTTP異步回調(diào)長耗時(shí)Agent先受理后回傳回調(diào)地址暴露、回調(diào)鑒權(quán)WebSocket長連接常駐內(nèi)存、實(shí)時(shí)對(duì)話型Agent連接?;?、消息Fragment消息隊(duì)列如Redis Stream、Kafka高吞吐任務(wù)分發(fā)消費(fèi)確認(rèn)、消息堆積這么多適配器里最容易翻車的是異步回調(diào)。因?yàn)锳gent完成任務(wù)后要主動(dòng)把結(jié)果推給網(wǎng)關(guān)這要求Agent配置網(wǎng)關(guān)的回調(diào)地址。生產(chǎn)環(huán)境里我曾經(jīng)遇到Agent側(cè)把回調(diào)地址里一個(gè)斜杠寫錯(cuò)結(jié)果所有完成的請(qǐng)求都靜默丟失。后來我在網(wǎng)關(guān)上做了一個(gè)補(bǔ)償查詢?cè)O(shè)計(jì)如果一個(gè)message_id超過預(yù)期時(shí)間仍未收到回調(diào)網(wǎng)關(guān)會(huì)主動(dòng)向Agent的status_query端點(diǎn)發(fā)起一次狀態(tài)查詢。這個(gè)設(shè)計(jì)相當(dāng)于給單向回調(diào)裝了一個(gè)反向巡檢把很多靜默失敗變成了可發(fā)現(xiàn)、可恢復(fù)的失敗。3.3 超時(shí)與重試分布式系統(tǒng)里唯一確定的事在分布式環(huán)境里幽靈消息和重復(fù)投遞是繞不開的。我把超時(shí)和重試策略分成兩層傳輸層網(wǎng)關(guān)到Agent的HTTP/WS傳輸短超時(shí)如5秒失敗后做有限次數(shù)重試業(yè)務(wù)層Agent從受理到產(chǎn)出結(jié)果的整體時(shí)長長超時(shí)如30秒到2分鐘超時(shí)后發(fā)起狀態(tài)查詢而不是盲目重發(fā)。重試最危險(xiǎn)的是非冪等Agent。我曾經(jīng)遇到一個(gè)生成圖片的Agent因?yàn)榫W(wǎng)關(guān)重試機(jī)制設(shè)置不當(dāng)同一條生成請(qǐng)求被連續(xù)執(zhí)行了三次給用戶賬戶扣了三次費(fèi)用。事后我在注冊(cè)表里加了idempotent: true/false字段——冪等的Agent允許自動(dòng)重試非冪等的Agent在超時(shí)后只能置為待人工確認(rèn)狀態(tài)由調(diào)用方?jīng)Q定是否重發(fā)。這個(gè)小改動(dòng)直接杜絕了后續(xù)的惡性重復(fù)扣費(fèi)問題。4. 路由分發(fā)與負(fù)載調(diào)度從輪詢走向按需觸達(dá)4.1 基于標(biāo)簽的路由能力描述比模型名稱更可靠做路由的時(shí)候我第一個(gè)念頭是按模型名路由比如所有GPT-4o的請(qǐng)求都去A組。后來發(fā)現(xiàn)這是個(gè)誤區(qū)業(yè)務(wù)方真正關(guān)心的是這個(gè)請(qǐng)求有沒有代碼審查能力而不是它背地里是哪個(gè)模型。同一個(gè)能力可能由不同模型實(shí)現(xiàn)同一個(gè)模型也在不斷換代按模型名路由會(huì)讓客戶端邏輯跟著模型升級(jí)一起改非常脆弱。Agent-Reach的做法是標(biāo)簽路由。注冊(cè)Agent時(shí)聲明capabilities和routing_tags調(diào)用方只描述自己需要什么能力網(wǎng)關(guān)從注冊(cè)目錄里篩選滿足條件的Agent集合candidates [ agent for agent in registry.all() if review_pull_request in agent.capabilities and agent.routing_tags.get(team) platform-engineering ]能力完全一樣但由不同團(tuán)隊(duì)維護(hù)的Agent之間再用權(quán)重分配流量——這為同一個(gè)能力有多個(gè)實(shí)現(xiàn)留了一手后面灰度測試新Agent時(shí)特別好用。4.2 優(yōu)先級(jí)與成本水位讓1%的貴模型干最關(guān)鍵的事Agent-Reach上線后的一個(gè)意外收獲是它順手解決了成本控制問題。不同Agent背后模型的成本可能差出幾十倍如果一視同仁輪詢財(cái)務(wù)報(bào)表會(huì)非常難看。我在路由規(guī)則里加了cost_profile標(biāo)簽并給請(qǐng)求設(shè)置了成本閾值。舉個(gè)例子代碼評(píng)審Agent有兩個(gè)版本一個(gè)用旗艦?zāi)P鸵粋€(gè)用輕量模型。如果一個(gè)Pull Request只是改了幾行注釋網(wǎng)關(guān)會(huì)直接路由給輕量版Agent只有涉及核心邏輯變更、具備一定復(fù)雜度信號(hào)時(shí)才走高成本通道。實(shí)測下來高成本模型調(diào)用量下降了約38%但用戶對(duì)評(píng)審質(zhì)量的滿意度幾乎沒降——這說明大部分場景其實(shí)不需要火力全開路由層的成本感知能力被嚴(yán)重低估了。4.3 會(huì)話親和性別讓用戶覺得對(duì)面的Agent失憶多Agent系統(tǒng)的另一個(gè)隱形坑是會(huì)話狀態(tài)??头鼍袄镉脩艉虯gent聊了十輪狀態(tài)都保存在A實(shí)例內(nèi)存里下一輪請(qǐng)求網(wǎng)關(guān)隨機(jī)路由到B實(shí)例B對(duì)之前聊了什么一頭霧水用戶會(huì)覺得Agent突然變傻了。Agent-Reach的默認(rèn)策略是會(huì)話親和性同一個(gè)session_id的連續(xù)請(qǐng)求優(yōu)先路由到上次處理它的Agent實(shí)例除非該實(shí)例不健康或負(fù)載超過閾值。親和性需要網(wǎng)關(guān)側(cè)維護(hù)一份會(huì)話與實(shí)例的映射緩存還要給映射設(shè)置TTL防止長期霸占。這個(gè)設(shè)計(jì)沒什么技術(shù)含量但對(duì)于用戶體驗(yàn)的改善立竿見影——很多用戶根本說不清哪句話讓AI不夠聰明其實(shí)只是狀態(tài)丟了。不過要注意親和性不能無腦開啟。有些Agent本身是無狀態(tài)的強(qiáng)制親和反而會(huì)影響負(fù)載均衡。所以我把親和性做成Agent級(jí)別可配置有狀態(tài)Agent默認(rèn)親和無狀態(tài)Agent直接輪詢。5. 可觀測性建設(shè)你沒法調(diào)試一個(gè)看不見的Agent5.1 Trace ID貫穿從用戶請(qǐng)求到Agent回復(fù)的整條鏈路Agent系統(tǒng)調(diào)試之所以難是因?yàn)殒溌房缭教鄠€(gè)進(jìn)程用戶HTTP請(qǐng)求先到網(wǎng)關(guān)網(wǎng)關(guān)推送消息隊(duì)列Agent消費(fèi)Agent再調(diào)用外部模型API最后回調(diào)網(wǎng)關(guān)再返回給用戶。任意一跳慢了或丟了都很難定位。Agent-Reach把鏈路追蹤作為基礎(chǔ)設(shè)施來建設(shè)而不是事后加個(gè)日志。網(wǎng)關(guān)在入口就生成trace_id通過Envelope傳給Agent。每個(gè)適配器、每個(gè)路由決策、每次重試都必須把trace_id打進(jìn)結(jié)構(gòu)化日志和指標(biāo)里。接入了日志平臺(tái)后查一個(gè)問題只需要輸入一個(gè)ID整條鏈路里所有跳點(diǎn)的時(shí)間消耗、狀態(tài)碼、重試次數(shù)全部浮現(xiàn)出來。舉個(gè)真實(shí)案例有一次用戶反饋Agent回答特別慢我輸入trace_id查鏈路發(fā)現(xiàn)耗時(shí)大頭根本不在模型而在一個(gè)外部知識(shí)庫API的DNS解析上——因?yàn)锳gent所在的舊環(huán)境DNS緩存不斷失效。如果沒有鏈路追蹤這種跨系統(tǒng)的性能問題幾乎不可能靠猜定位。5.2 觸達(dá)率與覆蓋率度量兩個(gè)容易被混淆的指標(biāo)接入了可觀測性之后Agent-Reach在監(jiān)控面板上展示四個(gè)核心指標(biāo)。我強(qiáng)烈建議任何做Agent網(wǎng)關(guān)的團(tuán)隊(duì)至少先盯住這四個(gè)指標(biāo)含義健康標(biāo)準(zhǔn)觸達(dá)成功率請(qǐng)求成功送達(dá)Agent并拿到回執(zhí)的比例≥99.9%路由覆蓋率有匹配Agent的請(qǐng)求數(shù) / 總請(qǐng)求數(shù)≥100%沒有就屬于配置缺陷平均觸達(dá)延遲從入網(wǎng)到Agent回執(zhí)確認(rèn)的耗時(shí)P95視Agent類型而定重試觸發(fā)率需要網(wǎng)關(guān)重試的消息占比≤5%這里我要特別說下觸達(dá)成功率和覆蓋率的關(guān)系。覆蓋率低的時(shí)候觸達(dá)成功率再高也沒用因?yàn)槟惴艞壛艘徊糠终?qǐng)求覆蓋率100%但觸達(dá)成功率99%同樣糟糕因?yàn)槊?00個(gè)請(qǐng)求就有1個(gè)靜默丟失。必須兩個(gè)一起看才算是Agent觸達(dá)質(zhì)量的完整畫面。5.3 離線依賴治理模型服務(wù)宕機(jī)時(shí)網(wǎng)關(guān)該做什么Agent網(wǎng)關(guān)本質(zhì)上是個(gè)中介它最怕的不是自己掛而是上游模型服務(wù)掛了之后下游所有請(qǐng)求堆積、超時(shí)、雪崩。我在Agent-Reach里做了一個(gè)Agent健康度探測模塊定期向各Agent發(fā)送輕量ping一個(gè)不消耗模型調(diào)用的存活探測如果Agent連續(xù)N次無響應(yīng)就在注冊(cè)目錄里把它標(biāo)記為unhealthy路由時(shí)自動(dòng)摘除。摘除后請(qǐng)求不會(huì)發(fā)到一個(gè)已經(jīng)沒有生還希望的Agent上而是進(jìn)入故障降級(jí)策略——比如直接返回該能力暫不可用的友好提示或者路由到備用的降級(jí)Agent。這個(gè)設(shè)計(jì)和負(fù)載均衡里的健康檢查是一個(gè)道理但在Agent場景下更要謹(jǐn)慎因?yàn)楹芏郃gent的存活并不能代表它的模型依賴沒有故障。后來我還加了一個(gè)更細(xì)的依賴探針Agent可以上報(bào)自己依賴的上游比如指定模型API網(wǎng)關(guān)根據(jù)模型API的公開狀態(tài)自動(dòng)調(diào)整Agent的負(fù)載系數(shù)——模型不穩(wěn)定時(shí)自動(dòng)降低給該Agent的流量。6. 上線后的實(shí)戰(zhàn)糾偏我被真實(shí)流量教育過的幾個(gè)設(shè)計(jì)6.1 取消萬能Agent意圖分流比我想象的更復(fù)雜Agent-Reach起初一直想把整個(gè)客服功能收歸到一個(gè)萬能Agent里以為能力集中管理路由邏輯就能簡化。但真實(shí)流量上來后發(fā)現(xiàn)越是面向各種問題的萬能Agent越容易在邊界場景里表現(xiàn)平庸——一會(huì)兒要處理退款糾紛一會(huì)兒要回答產(chǎn)品配置一會(huì)兒又要做情感安撫單個(gè)提示詞工程根本罩不住。后來我把萬能Agent拆成三個(gè)垂直Agent路由層增加一道很薄的意圖分類步驟根據(jù)用戶請(qǐng)求的語義粗粒度分到對(duì)應(yīng)的垂直Agent。這道意圖分流不一定非要用大模型做用一組精確關(guān)鍵詞模型、甚至一個(gè)輕量分類器就能跑得很好。實(shí)測下來整體回復(fù)準(zhǔn)確率上升了約12%重度Agent的負(fù)載還下降了。拆Agent聽起來像產(chǎn)品決策實(shí)際上沒有網(wǎng)關(guān)的路由能力支撐根本不敢拆——因?yàn)椴痖_之后怎樣把用戶請(qǐng)求準(zhǔn)確送過去就成了第一道坎。6.2 消息積壓與背壓控制異步回調(diào)模式上線后遇到過一個(gè)小時(shí)級(jí)的抖動(dòng)某Agent因?yàn)樯嫌文P虯PI變慢消費(fèi)速度跟不上消息隊(duì)列積壓了幾萬條任務(wù)而網(wǎng)關(guān)還在源源不斷往里推。如果沒有背壓控制積壓只會(huì)越來越深最后老任務(wù)全部超時(shí)新任務(wù)也被卡住。Agent-Reach里加的方案是網(wǎng)關(guān)和Agent之間有一個(gè)信用額度機(jī)制每個(gè)Agent實(shí)例維護(hù)一個(gè)當(dāng)前未完成任務(wù)數(shù)的指標(biāo)當(dāng)未完成任務(wù)數(shù)超過閾值網(wǎng)關(guān)就不再向該Agent分發(fā)新任務(wù)而是進(jìn)入排隊(duì)狀態(tài)。這其實(shí)就是分布式系統(tǒng)里最常見的流控思路但放在Agent場景里特別容易忽略——因?yàn)榇蠹叶加X得Agent會(huì)自己消化任務(wù)忽略了Agent背后的模型服務(wù)同樣有吞吐上限。6.3 灰度發(fā)布讓新Agent先接10%的流量Agent升級(jí)比普通服務(wù)升級(jí)更讓人緊張因?yàn)槟P托袨槭歉怕市缘哪銢]法保證新版本在所有輸入上都比舊版本好。Agent-ReACH幫我做了一件很有價(jià)值的事支持同一Agent ID下注冊(cè)多個(gè)版本路由時(shí)按權(quán)重分配流量。灰度策略具體是新版本Agent以version: 2.5.0注冊(cè)初始權(quán)重10%網(wǎng)關(guān)自動(dòng)把10%的能力請(qǐng)求路由到新版本其余90%繼續(xù)走舊版本觀察關(guān)鍵指標(biāo)觸達(dá)成功率、平均延遲、用戶投訴率、上下文切換時(shí)長指標(biāo)穩(wěn)定后提升權(quán)重到30%、50%最后100%時(shí)把舊版本摘除。這個(gè)機(jī)制成本很低但對(duì)Agent迭代的信心提升很大。以前每次升級(jí)Agent團(tuán)隊(duì)都提心吊膽現(xiàn)在新版本上線就是一次普通的灰度發(fā)布。6.4 兼容性策略給Agent升級(jí)留出雙重注冊(cè)窗口最后一個(gè)坑是關(guān)于版本過渡的。Agent內(nèi)部依賴的模型或數(shù)據(jù)格式變了之后新舊Agent可能無法處理彼此的請(qǐng)求。如果網(wǎng)關(guān)的注冊(cè)目錄里舊版本一摘除所有在途消息和持久化會(huì)話馬上就會(huì)出兼容性問題。Agent-Reach最后保留了一個(gè)很實(shí)用的小設(shè)計(jì)新舊版本共存窗口。摘除舊版本前網(wǎng)關(guān)會(huì)把舊版本標(biāo)記為draining狀態(tài)不再分配新請(qǐng)求但允許已經(jīng)發(fā)給它的在途請(qǐng)求繼續(xù)處理和回執(zhí)。只有等舊版本的在途任務(wù)數(shù)降為0才真正從目錄里移除。這個(gè)優(yōu)雅下線窗口的時(shí)長可配置通常設(shè)置15到30分鐘足夠讓異步任務(wù)清空又不至于讓舊版本一直占用資源。最后再分享一點(diǎn)個(gè)人體會(huì)吧。Agent-Reach這個(gè)項(xiàng)目做下來我最大的感受是大家聊Agent時(shí)都喜歡盯著模型、提示詞、RAG這些聰明的部分但真正讓Agent在業(yè)務(wù)環(huán)境里跑得穩(wěn)、跑得久的恰恰是一堆看起來不太聰明的工程活——消息不丟、超時(shí)合理、路由可預(yù)期、出了問題查得到。這些活本來不該每個(gè)團(tuán)隊(duì)都重新發(fā)明一遍網(wǎng)關(guān)類基礎(chǔ)設(shè)施的價(jià)值就在這里。如果你也正在做多Agent應(yīng)用我建議不要急著寫業(yè)務(wù)邏輯先問問自己請(qǐng)求到Agent之間的這段路是不是可靠、可路由、可追蹤的如果答案是否定的那你可能也需要一個(gè)屬于自己的Reach。