化實(shí)戰(zhàn):實(shí)時(shí)數(shù)據(jù)智能與異步Agent架構(gòu)落地)
AI 應(yīng)用從 Demo 走向生產(chǎn)環(huán)境最容易被低估的一環(huán)不是模型能力而是數(shù)據(jù)流轉(zhuǎn)的實(shí)時(shí)性。過(guò)去兩年大家拼的是能不能跑通現(xiàn)在拼的是跑得穩(wěn)不穩(wěn)、快不快、準(zhǔn)不準(zhǔn)。我所在的團(tuán)隊(duì)最近半年一直在做 AI 應(yīng)用的生產(chǎn)化改造踩過(guò)的坑幾乎都集中在實(shí)時(shí)數(shù)據(jù)智能這一塊——不是模型不行而是數(shù)據(jù)到得不夠快、不夠?qū)?、不夠全。這篇文章就把我們趟出來(lái)的經(jīng)驗(yàn)完整拆開(kāi)講從架構(gòu)選型到異步通信從 Agent 編排到云原生部署盡量把每個(gè)決策背后的為什么說(shuō)清楚。1. 為什么實(shí)時(shí)數(shù)據(jù)智能成了 AI 生產(chǎn)化的分水嶺1.1 從能回答到答得對(duì)的鴻溝早期做 AI 應(yīng)用大家關(guān)注的是模型能不能理解問(wèn)題、能不能生成像樣的回答。這個(gè)階段用離線(xiàn)數(shù)據(jù)、批量灌入知識(shí)庫(kù)就能應(yīng)付用戶(hù)問(wèn)一個(gè)問(wèn)題系統(tǒng)去向量庫(kù)里檢索幾段文本拼進(jìn) Prompt 里讓模型生成效果看起來(lái)還不錯(cuò)。但一旦進(jìn)入真實(shí)生產(chǎn)場(chǎng)景問(wèn)題就暴露了用戶(hù)問(wèn)的是現(xiàn)在庫(kù)存還有多少這個(gè)訂單當(dāng)前狀態(tài)是什么剛才那筆交易有沒(méi)有異常這些問(wèn)題的答案每秒鐘都在變離線(xiàn)數(shù)據(jù)根本喂不上。我們內(nèi)部做過(guò)一個(gè)統(tǒng)計(jì)在客服場(chǎng)景里超過(guò)六成的用戶(hù)問(wèn)題涉及實(shí)時(shí)狀態(tài)查詢(xún)。如果 AI 回答的是十分鐘前的數(shù)據(jù)用戶(hù)第一次可能覺(jué)得還行第二次就會(huì)直接找人工。這不是模型能力問(wèn)題是數(shù)據(jù)鏈路問(wèn)題。實(shí)時(shí)數(shù)據(jù)智能要解決的核心矛盾就是模型推理是秒級(jí)的但數(shù)據(jù)供給如果還是分鐘級(jí)甚至小時(shí)級(jí)整個(gè)系統(tǒng)的價(jià)值就會(huì)大打折扣。1.2 實(shí)時(shí)性帶來(lái)的連鎖反應(yīng)實(shí)時(shí)數(shù)據(jù)一旦接入整個(gè)系統(tǒng)的復(fù)雜度會(huì)指數(shù)級(jí)上升。離線(xiàn)場(chǎng)景下你可以容忍數(shù)據(jù)延遲、可以批量重跑、可以事后修正。但實(shí)時(shí)場(chǎng)景下數(shù)據(jù)是流式的、連續(xù)的、有時(shí)序的任何一個(gè)環(huán)節(jié)的抖動(dòng)都會(huì)傳導(dǎo)到最終回答上。我們最初的做法是讓 AI 應(yīng)用直接查業(yè)務(wù)數(shù)據(jù)庫(kù)簡(jiǎn)單粗暴但很快就遇到了三個(gè)問(wèn)題一是高頻查詢(xún)把業(yè)務(wù)庫(kù)壓得喘不過(guò)氣二是數(shù)據(jù)庫(kù)的 schema 是面向事務(wù)設(shè)計(jì)的不是面向檢索的查詢(xún)效率很低三是多個(gè) Agent 并發(fā)查詢(xún)時(shí)連接池瞬間打滿(mǎn)。這三個(gè)問(wèn)題逼著我們?nèi)ブ匦略O(shè)計(jì)數(shù)據(jù)層。后來(lái)我們的思路是業(yè)務(wù)庫(kù)不動(dòng)在它和 AI 應(yīng)用之間加一層實(shí)時(shí)數(shù)據(jù)管道用變更數(shù)據(jù)捕獲CDC把業(yè)務(wù)庫(kù)的變更實(shí)時(shí)同步到一個(gè)專(zhuān)門(mén)面向檢索的存儲(chǔ)里AI 應(yīng)用只查這一層。這個(gè)改動(dòng)看起來(lái)簡(jiǎn)單但它是整個(gè)實(shí)時(shí)數(shù)據(jù)智能架構(gòu)的基石。1.3 什么樣的場(chǎng)景真正需要實(shí)時(shí)數(shù)據(jù)智能不是所有 AI 應(yīng)用都需要實(shí)時(shí)數(shù)據(jù)。我見(jiàn)過(guò)不少團(tuán)隊(duì)一上來(lái)就追求全實(shí)時(shí)結(jié)果架構(gòu)復(fù)雜度飆升收益卻不明顯。判斷標(biāo)準(zhǔn)其實(shí)很簡(jiǎn)單如果數(shù)據(jù)的時(shí)效性直接影響用戶(hù)的決策或體驗(yàn)?zāi)蔷托枰獙?shí)時(shí)如果數(shù)據(jù)晚幾分鐘甚至幾小時(shí)對(duì)結(jié)果沒(méi)影響那就沒(méi)必要上實(shí)時(shí)鏈路。具體來(lái)說(shuō)以下幾類(lèi)場(chǎng)景對(duì)實(shí)時(shí)性的要求最高交易風(fēng)控類(lèi)數(shù)據(jù)延遲直接意味著資金風(fēng)險(xiǎn)智能客服類(lèi)用戶(hù)問(wèn)的是當(dāng)前狀態(tài)答錯(cuò)會(huì)直接導(dǎo)致投訴運(yùn)維監(jiān)控類(lèi)異常檢測(cè)需要秒級(jí)響應(yīng)供應(yīng)鏈調(diào)度類(lèi)庫(kù)存和物流狀態(tài)變化頻繁調(diào)度決策依賴(lài)最新數(shù)據(jù)。反過(guò)來(lái)像知識(shí)問(wèn)答、內(nèi)容生成、代碼輔助這類(lèi)場(chǎng)景對(duì)實(shí)時(shí)性的要求就低得多用離線(xiàn)知識(shí)庫(kù)加定期更新完全夠用。2. 實(shí)時(shí)數(shù)據(jù)管道的搭建從 CDC 到檢索層的完整鏈路2.1 變更數(shù)據(jù)捕獲的選型與取舍實(shí)時(shí)數(shù)據(jù)管道的第一步是把業(yè)務(wù)庫(kù)的變更捕獲出來(lái)。市面上主流的方案有三種基于數(shù)據(jù)庫(kù)日志的 CDC、基于觸發(fā)器的 CDC、基于應(yīng)用雙寫(xiě)的 CDC。我們最終選了基于日志的方案具體來(lái)說(shuō)是解析數(shù)據(jù)庫(kù)的 binlog。原因很直接對(duì)業(yè)務(wù)庫(kù)侵入最小不需要改表結(jié)構(gòu)不需要加觸發(fā)器性能損耗可以控制在百分之幾以?xún)?nèi)?;谟|發(fā)器的方案我們?cè)缙谠囘^(guò)問(wèn)題是每次寫(xiě)操作都要額外觸發(fā)一次寫(xiě)入高并發(fā)下延遲明顯而且觸發(fā)器邏輯一旦出問(wèn)題很難排查。應(yīng)用雙寫(xiě)的方案更不可取它要求業(yè)務(wù)代碼同時(shí)寫(xiě)兩個(gè)地方一致性完全靠應(yīng)用層保證一旦有一邊寫(xiě)失敗就會(huì)出現(xiàn)數(shù)據(jù)不一致而且對(duì)業(yè)務(wù)代碼的侵入太大?;谌罩镜姆桨敢膊皇菦](méi)有坑。最大的坑是 schema 變更。業(yè)務(wù)庫(kù)加個(gè)字段、改個(gè)類(lèi)型CDC 管道如果沒(méi)同步處理就會(huì)解析失敗或者丟數(shù)據(jù)。我們的做法是在 CDC 層加一個(gè) schema 注冊(cè)中心所有 schema 變更必須先注冊(cè)再上線(xiàn)管道根據(jù)注冊(cè)信息動(dòng)態(tài)適配。這個(gè)機(jī)制上線(xiàn)后因?yàn)?schema 變更導(dǎo)致的數(shù)據(jù)問(wèn)題基本歸零。2.2 消息隊(duì)列在管道中的角色CDC 捕獲到的變更不能直接寫(xiě)進(jìn)檢索層中間需要一個(gè)緩沖和分發(fā)層這就是消息隊(duì)列的作用。我們用的是 Kafka核心考慮是三點(diǎn)高吞吐、可持久化、支持多消費(fèi)者。高吞吐不用多說(shuō)業(yè)務(wù)高峰期每秒幾萬(wàn)條變更很常見(jiàn)可持久化是為了防止下游故障時(shí)數(shù)據(jù)丟失Kafka 可以把消息保留幾天甚至幾周下游恢復(fù)了再消費(fèi)多消費(fèi)者是為了讓同一份變更數(shù)據(jù)能同時(shí)供給多個(gè)下游比如一個(gè)消費(fèi)者寫(xiě)檢索層一個(gè)消費(fèi)者做實(shí)時(shí)特征計(jì)算一個(gè)消費(fèi)者做審計(jì)歸檔。這里有個(gè)經(jīng)驗(yàn)值得分享Kafka 的 topic 分區(qū)數(shù)不是越多越好。我們一開(kāi)始為了追求并行度把分區(qū)數(shù)設(shè)得很大結(jié)果發(fā)現(xiàn)消費(fèi)者端的 rebalance 變得非常頻繁每次 rebalance 都會(huì)導(dǎo)致短暫的消費(fèi)停頓。后來(lái)我們把分區(qū)數(shù)控制在消費(fèi)者數(shù)量的兩到三倍rebalance 頻率明顯下降整體吞吐反而更穩(wěn)定。分區(qū)數(shù)的設(shè)置要結(jié)合消費(fèi)者數(shù)量和單條消息的處理耗時(shí)來(lái)算不能拍腦袋。2.3 檢索層的設(shè)計(jì)為什么不用向量庫(kù)直接扛很多人一提到 AI 應(yīng)用的檢索層第一反應(yīng)就是向量數(shù)據(jù)庫(kù)。但實(shí)時(shí)數(shù)據(jù)智能場(chǎng)景下純向量庫(kù)是不夠的。原因在于實(shí)時(shí)數(shù)據(jù)查詢(xún)往往是結(jié)構(gòu)化條件加語(yǔ)義檢索的混合查詢(xún)。比如找出過(guò)去一小時(shí)內(nèi)在華東地區(qū)發(fā)生的、金額超過(guò)一萬(wàn)的、且描述類(lèi)似退款糾紛的訂單這里面既有時(shí)間范圍、地區(qū)、金額這些結(jié)構(gòu)化條件又有語(yǔ)義相似度匹配。我們的做法是分層存儲(chǔ)結(jié)構(gòu)化條件走倒排索引或列式存儲(chǔ)語(yǔ)義檢索走向量索引查詢(xún)時(shí)先做結(jié)構(gòu)化過(guò)濾縮小候選集再在候選集上做向量檢索。這樣既保證了召回率又控制了延遲。如果直接用向量庫(kù)扛全部查詢(xún)結(jié)構(gòu)化過(guò)濾只能在向量檢索之后做候選集太大會(huì)導(dǎo)致延遲飆升。實(shí)測(cè)下來(lái)分層方案在千萬(wàn)級(jí)數(shù)據(jù)量下P99 延遲能控制在兩百毫秒以?xún)?nèi)而純向量方案在同樣數(shù)據(jù)量下經(jīng)常超過(guò)一秒。3. Agent 編排中的異步通信別讓同步調(diào)用拖垮整個(gè)系統(tǒng)3.1 同步調(diào)用的隱性成本Agent 架構(gòu)剛流行的時(shí)候大家的做法很樸素一個(gè)主 Agent 接到任務(wù)依次調(diào)用工具 Agent、檢索 Agent、生成 Agent每一步都是同步等待。這種模式在 Demo 階段沒(méi)問(wèn)題但生產(chǎn)環(huán)境下問(wèn)題很大。假設(shè)一個(gè)任務(wù)需要調(diào)用五個(gè)子 Agent每個(gè)子 Agent 平均耗時(shí)五百毫秒同步模式下總耗時(shí)就是兩秒半。如果其中某個(gè)子 Agent 因?yàn)橄掠我蕾?lài)抖動(dòng)變成兩秒整個(gè)任務(wù)就變成四秒。用戶(hù)等四秒才看到第一個(gè)字體驗(yàn)直接崩掉。更嚴(yán)重的是資源占用。同步調(diào)用意味著主 Agent 的線(xiàn)程在整個(gè)等待期間都被占著不能處理其他請(qǐng)求。并發(fā)一上來(lái)線(xiàn)程池瞬間打滿(mǎn)新請(qǐng)求只能排隊(duì)。我們壓測(cè)時(shí)發(fā)現(xiàn)同步模式下單實(shí)例并發(fā)超過(guò)五十就開(kāi)始出現(xiàn)明顯排隊(duì)而異步模式下同樣實(shí)例能扛到三百以上。3.2 異步通信的幾種落地方式異步通信不是簡(jiǎn)單地把同步調(diào)用改成異步就完事了它涉及整個(gè)調(diào)用鏈的重構(gòu)。我們實(shí)踐下來(lái)主要有三種落地方式各有適用場(chǎng)景。第一種是消息隊(duì)列解耦。主 Agent 把子任務(wù)作為消息投遞到隊(duì)列子 Agent 消費(fèi)消息、處理、再把結(jié)果投遞到結(jié)果隊(duì)列主 Agent 從結(jié)果隊(duì)列里收結(jié)果。這種方式解耦最徹底子 Agent 可以獨(dú)立擴(kuò)縮容某個(gè)子 Agent 掛了也不影響其他。缺點(diǎn)是鏈路變長(zhǎng)端到端延遲會(huì)增加而且需要處理消息的順序和冪等。第二種是響應(yīng)式編程。用 Reactor 或者類(lèi)似框架把調(diào)用鏈組織成數(shù)據(jù)流主 Agent 訂閱子 Agent 的結(jié)果流有結(jié)果就處理沒(méi)結(jié)果就等著不阻塞線(xiàn)程。這種方式延遲低適合對(duì)響應(yīng)時(shí)間敏感的場(chǎng)景。缺點(diǎn)是對(duì)開(kāi)發(fā)者的心智負(fù)擔(dān)比較重調(diào)試起來(lái)不如同步代碼直觀(guān)。第三種是事件驅(qū)動(dòng)加狀態(tài)機(jī)。主 Agent 維護(hù)一個(gè)任務(wù)狀態(tài)機(jī)每個(gè)子 Agent 完成后發(fā)一個(gè)事件狀態(tài)機(jī)根據(jù)事件推進(jìn)任務(wù)狀態(tài)。這種方式最適合長(zhǎng)流程、多步驟的任務(wù)比如需要人工審批介入的流程。缺點(diǎn)是狀態(tài)管理復(fù)雜需要考慮狀態(tài)持久化和恢復(fù)。我們最終是混合使用的短鏈路、低延遲要求的用響應(yīng)式長(zhǎng)鏈路、需要解耦的用消息隊(duì)列涉及人工介入的用狀態(tài)機(jī)。沒(méi)有銀彈關(guān)鍵是看場(chǎng)景。3.3 超時(shí)、重試與降級(jí)的實(shí)戰(zhàn)配置異步通信繞不開(kāi)超時(shí)、重試和降級(jí)這三個(gè)問(wèn)題。我們的配置原則是超時(shí)時(shí)間要分層設(shè)置重試要有上限和退避降級(jí)要有兜底方案。超時(shí)分層的意思是不同層級(jí)的調(diào)用設(shè)置不同的超時(shí)。比如主 Agent 調(diào)用子 Agent 的超時(shí)是兩秒子 Agent 調(diào)用下游服務(wù)的超時(shí)是八百毫秒下游服務(wù)調(diào)用數(shù)據(jù)庫(kù)的超時(shí)是兩百毫秒。這樣任何一層出問(wèn)題都能在上一層超時(shí)之前暴露出來(lái)避免雪崩。我們最初所有層都設(shè)五秒超時(shí)結(jié)果一個(gè)慢查詢(xún)能把整條鏈路拖死。重試的策略是只對(duì)冪等操作重試重試次數(shù)不超過(guò)三次每次重試間隔指數(shù)退避。非冪等操作比如寫(xiě)操作重試可能導(dǎo)致重復(fù)寫(xiě)入我們改成先查后寫(xiě)或者用唯一鍵約束來(lái)保證冪等。重試間隔從一百毫秒開(kāi)始每次翻倍最多到一秒。這樣既能應(yīng)對(duì)瞬時(shí)抖動(dòng)又不會(huì)在持續(xù)故障時(shí)瘋狂重試把下游壓垮。降級(jí)的兜底方案分幾檔如果實(shí)時(shí)數(shù)據(jù)查不到降級(jí)到查最近一次的快照數(shù)據(jù)并在回答里標(biāo)注數(shù)據(jù)可能有延遲如果子 Agent 完全不可用降級(jí)到只返回主 Agent 能處理的部分結(jié)果如果整個(gè)鏈路都掛了返回一個(gè)友好的錯(cuò)誤提示并引導(dǎo)用戶(hù)稍后重試。降級(jí)的關(guān)鍵是讓用戶(hù)感知到系統(tǒng)還在工作而不是直接報(bào)錯(cuò)。4. 云原生部署下的資源博弈GPU 配額、沙盒與彈性伸縮4.1 GPU 配額管理的現(xiàn)實(shí)困境AI 應(yīng)用上云原生GPU 配額是最現(xiàn)實(shí)的約束。我們遇到過(guò)好幾次GPU 配額已不夠預(yù)凍結(jié)的報(bào)錯(cuò)任務(wù)提交上去直接被拒。這個(gè)問(wèn)題的根源在于GPU 是稀缺資源云平臺(tái)的配額是硬上限而 AI 應(yīng)用的 GPU 需求波動(dòng)很大——推理高峰期需要大量 GPU低谷期又閑置。我們的應(yīng)對(duì)策略有三條。第一是推理和訓(xùn)練分離訓(xùn)練任務(wù)用搶占式實(shí)例能接受被中斷推理任務(wù)用預(yù)留實(shí)例保證穩(wěn)定性。第二是模型量化把 FP16 量化到 INT8顯存占用直接減半同樣的 GPU 能跑更多實(shí)例。第三是動(dòng)態(tài)批處理把多個(gè)推理請(qǐng)求攢成一批一起送進(jìn) GPU提高 GPU 利用率。這三條組合下來(lái)我們的 GPU 成本降了將近四成。4.2 沙盒環(huán)境的安全邊界Agent 執(zhí)行代碼或者調(diào)用外部工具時(shí)沙盒是必須的。我們用的是容器級(jí)沙盒每個(gè) Agent 任務(wù)跑在獨(dú)立的容器里有獨(dú)立的文件系統(tǒng)、網(wǎng)絡(luò)命名空間和資源限制。這樣即使 Agent 執(zhí)行了惡意代碼也影響不到宿主機(jī)和其他任務(wù)。沙盒配置里有幾個(gè)參數(shù)特別關(guān)鍵。CPU 和內(nèi)存限制不用多說(shuō)超了直接 OOM 或者被 throttle。網(wǎng)絡(luò)策略要嚴(yán)格默認(rèn)禁止所有出站連接只白名單必要的服務(wù)。文件系統(tǒng)要掛載成只讀需要寫(xiě)入的目錄單獨(dú)掛載臨時(shí)卷任務(wù)結(jié)束就銷(xiāo)毀。還有一個(gè)容易被忽略的是執(zhí)行時(shí)間限制我們?cè)O(shè)的是單任務(wù)最長(zhǎng)五分鐘超時(shí)直接 kill。這個(gè)限制防止了死循環(huán)或者卡死的任務(wù)長(zhǎng)期占用資源。4.3 彈性伸縮的觸發(fā)條件設(shè)計(jì)云原生的彈性伸縮聽(tīng)起來(lái)很美但觸發(fā)條件設(shè)計(jì)不好反而會(huì)導(dǎo)致頻繁擴(kuò)縮容系統(tǒng)穩(wěn)定性下降。我們的經(jīng)驗(yàn)是擴(kuò)容要快縮容要慢。擴(kuò)容的觸發(fā)條件用兩個(gè)指標(biāo)CPU 利用率超過(guò)百分之七十或者請(qǐng)求隊(duì)列長(zhǎng)度超過(guò)閾值。兩個(gè)條件滿(mǎn)足任意一個(gè)就擴(kuò)容擴(kuò)容步長(zhǎng)是當(dāng)前實(shí)例數(shù)的百分之五十最多不超過(guò)配額上限。擴(kuò)容要快是因?yàn)榱髁扛叻鍋?lái)得猛慢一步用戶(hù)就排隊(duì)了??s容的觸發(fā)條件用三個(gè)指標(biāo)同時(shí)滿(mǎn)足CPU 利用率低于百分之三十、請(qǐng)求隊(duì)列為空、且持續(xù)五分鐘以上。三個(gè)條件都滿(mǎn)足才縮容縮容步長(zhǎng)是當(dāng)前實(shí)例數(shù)的百分之二十。縮容要慢是因?yàn)榱髁康凸瓤赡苤皇菚簳r(shí)的縮太快了下一個(gè)高峰又得擴(kuò)來(lái)回抖動(dòng)反而浪費(fèi)資源。5. Agent 記憶與多 AI 協(xié)作的工程化落地5.1 短期記憶與長(zhǎng)期記憶的分層Agent 記憶是最近討論很多的話(huà)題但很多實(shí)現(xiàn)只停留在把對(duì)話(huà)歷史塞進(jìn)上下文這個(gè)層面。生產(chǎn)環(huán)境下這種做法很快會(huì)遇到上下文長(zhǎng)度限制和成本問(wèn)題。我們的做法是分層短期記憶存最近幾輪對(duì)話(huà)直接進(jìn)上下文長(zhǎng)期記憶存關(guān)鍵事實(shí)和用戶(hù)偏好用向量庫(kù)存儲(chǔ)按需檢索。短期記憶的窗口大小要權(quán)衡。窗口太小Agent 記不住上下文回答會(huì)前后矛盾窗口太大token 消耗高而且模型對(duì)長(zhǎng)上下文的注意力會(huì)稀釋。我們實(shí)測(cè)下來(lái)最近十輪對(duì)話(huà)是個(gè)比較平衡的點(diǎn)超過(guò)十輪的信息就壓縮成摘要存進(jìn)長(zhǎng)期記憶。長(zhǎng)期記憶的寫(xiě)入要有選擇性不是什么信息都值得存。我們的規(guī)則是用戶(hù)明確表達(dá)的偏好、任務(wù)的關(guān)鍵結(jié)論、需要跨會(huì)話(huà)保持的狀態(tài)這三類(lèi)才寫(xiě)入長(zhǎng)期記憶。其他信息用完就丟。這樣既控制了存儲(chǔ)成本又保證了檢索時(shí)的信噪比。5.2 多 Agent 協(xié)作的通信協(xié)議多 Agent 協(xié)作不是把幾個(gè) Agent 湊在一起就行它們之間需要一套通信協(xié)議。我們用的是基于消息的協(xié)議每個(gè) Agent 有唯一的標(biāo)識(shí)消息包含發(fā)送者、接收者、消息類(lèi)型、負(fù)載和關(guān)聯(lián) ID。關(guān)聯(lián) ID 用來(lái)把同一個(gè)任務(wù)的多條消息串起來(lái)方便追蹤和調(diào)試。消息類(lèi)型我們定義了幾種任務(wù)派發(fā)、結(jié)果返回、狀態(tài)查詢(xún)、錯(cuò)誤上報(bào)、心跳。任務(wù)派發(fā)和結(jié)果返回是主要的狀態(tài)查詢(xún)用于主 Agent 監(jiān)控子 Agent 的健康狀況錯(cuò)誤上報(bào)用于子 Agent 主動(dòng)通知異常心跳用于檢測(cè)子 Agent 是否存活。這套協(xié)議看起來(lái)簡(jiǎn)單但它讓整個(gè)多 Agent 系統(tǒng)變得可觀(guān)測(cè)、可調(diào)試出問(wèn)題時(shí)能快速定位是哪個(gè) Agent 的哪一步出了岔子。5.3 協(xié)作中的沖突處理多 Agent 協(xié)作最麻煩的是沖突。比如兩個(gè) Agent 同時(shí)對(duì)同一份數(shù)據(jù)做了修改或者兩個(gè) Agent 給出了矛盾的建議。我們的處理原則是能預(yù)防的預(yù)防預(yù)防不了的就仲裁。預(yù)防的手段主要是加鎖和版本控制。對(duì)共享資源的寫(xiě)操作先獲取分布式鎖寫(xiě)完釋放。對(duì)共享數(shù)據(jù)的修改帶上版本號(hào)版本不匹配就拒絕寫(xiě)入讓 Agent 重新讀取最新版本再操作。仲裁的手段是設(shè)一個(gè)主 Agent 作為協(xié)調(diào)者當(dāng)子 Agent 之間出現(xiàn)矛盾時(shí)由主 Agent 根據(jù)預(yù)設(shè)規(guī)則裁決比如以最新數(shù)據(jù)為準(zhǔn)或者以置信度高的結(jié)果為準(zhǔn)。6. 生產(chǎn)環(huán)境下的可觀(guān)測(cè)性與故障排查6.1 實(shí)時(shí)數(shù)據(jù)鏈路的監(jiān)控指標(biāo)實(shí)時(shí)數(shù)據(jù)智能系統(tǒng)的監(jiān)控不能只看 CPU 和內(nèi)存這些基礎(chǔ)指標(biāo)更要看數(shù)據(jù)鏈路的健康度。我們重點(diǎn)監(jiān)控幾個(gè)指標(biāo)數(shù)據(jù)延遲也就是變更發(fā)生到檢索層可查的時(shí)間差這個(gè)指標(biāo)直接反映實(shí)時(shí)性數(shù)據(jù)積壓也就是消息隊(duì)列里待消費(fèi)的消息數(shù)積壓說(shuō)明下游處理不過(guò)來(lái)數(shù)據(jù)一致性定期抽樣比對(duì)業(yè)務(wù)庫(kù)和檢索層的數(shù)據(jù)確保沒(méi)有丟失或錯(cuò)亂。數(shù)據(jù)延遲我們?cè)O(shè)的告警閾值是五秒超過(guò)就告警。實(shí)測(cè)下來(lái)正常情況下延遲在五百毫秒以?xún)?nèi)網(wǎng)絡(luò)抖動(dòng)時(shí)會(huì)到一兩秒超過(guò)五秒基本就是出問(wèn)題了。數(shù)據(jù)積壓的告警閾值根據(jù)業(yè)務(wù)量動(dòng)態(tài)調(diào)整一般是正常消費(fèi)速率的十分鐘量。數(shù)據(jù)一致性的檢查是每小時(shí)跑一次抽樣一萬(wàn)條比對(duì)不一致率超過(guò)萬(wàn)分之一就告警。6.2 Agent 執(zhí)行鏈路的問(wèn)題定位Agent 執(zhí)行鏈路長(zhǎng)出問(wèn)題時(shí)定位困難。我們的做法是全鏈路追蹤每個(gè)任務(wù)生成一個(gè) trace ID從主 Agent 到子 Agent 到下游服務(wù)每一跳都帶上這個(gè) ID日志和指標(biāo)都按 trace ID 聚合。這樣排查時(shí)拿到一個(gè) trace ID 就能看到整個(gè)任務(wù)的完整執(zhí)行路徑哪一步慢、哪一步錯(cuò)一目了然。常見(jiàn)的 Agent 執(zhí)行問(wèn)題有幾類(lèi)超時(shí)通常是下游依賴(lài)慢或者網(wǎng)絡(luò)抖動(dòng)死循環(huán)通常是 Agent 的決策邏輯有 bug反復(fù)調(diào)用同一個(gè)工具上下文溢出通常是短期記憶窗口設(shè)得太大或者對(duì)話(huà)輪次太多工具調(diào)用失敗通常是參數(shù)格式不對(duì)或者下游服務(wù)不可用。每一類(lèi)問(wèn)題我們都有對(duì)應(yīng)的排查手冊(cè)新人照著手冊(cè)走基本能定位到根因。6.3 從故障中恢復(fù)的實(shí)戰(zhàn)流程故障恢復(fù)的關(guān)鍵是快和穩(wěn)??焓侵缚焖僦箵p穩(wěn)是指恢復(fù)后不再?gòu)?fù)發(fā)。我們的流程是發(fā)現(xiàn)故障后先切降級(jí)方案保住核心功能然后定位根因修復(fù)后灰度恢復(fù)觀(guān)察一段時(shí)間再全量。舉個(gè)例子有一次檢索層因?yàn)閿?shù)據(jù)量突增導(dǎo)致查詢(xún)超時(shí)AI 應(yīng)用大面積報(bào)錯(cuò)。我們的處理是第一步把檢索層的查詢(xún)超時(shí)從兩百毫秒放寬到一秒先讓請(qǐng)求能返回第二步臨時(shí)擴(kuò)容檢索層實(shí)例分擔(dān)壓力第三步定位到是某個(gè)大客戶(hù)的批量導(dǎo)入導(dǎo)致數(shù)據(jù)量突增和客戶(hù)協(xié)調(diào)錯(cuò)峰導(dǎo)入第四步給檢索層加了寫(xiě)入限流防止類(lèi)似情況再發(fā)生。整個(gè)過(guò)程從發(fā)現(xiàn)到恢復(fù)用了不到十五分鐘核心功能沒(méi)有中斷。7. 一些踩坑之后的個(gè)人體會(huì)做實(shí)時(shí)數(shù)據(jù)智能這一年多最大的體會(huì)是實(shí)時(shí)不是目的可靠才是。很多團(tuán)隊(duì)為了追求實(shí)時(shí)性把架構(gòu)搞得極其復(fù)雜結(jié)果穩(wěn)定性反而下降。我的建議是先想清楚業(yè)務(wù)到底需要多實(shí)時(shí)是秒級(jí)、分鐘級(jí)還是小時(shí)級(jí)然后按需設(shè)計(jì)不要過(guò)度工程。第二個(gè)體會(huì)是異步通信雖然好但不是所有地方都適合。短鏈路、低延遲要求的場(chǎng)景同步調(diào)用反而更簡(jiǎn)單可靠。異步帶來(lái)的復(fù)雜度只有在鏈路長(zhǎng)、并發(fā)高、需要解耦的場(chǎng)景下才劃算。第三個(gè)體會(huì)是可觀(guān)測(cè)性要提前做不要等出問(wèn)題了才補(bǔ)。我們最初沒(méi)做全鏈路追蹤排查一個(gè)問(wèn)題要翻好幾臺(tái)機(jī)器的日志后來(lái)補(bǔ)上追蹤之后排查效率提升了不止一個(gè)量級(jí)。監(jiān)控和追蹤這些基礎(chǔ)設(shè)施越早投入回報(bào)越高。最后一個(gè)體會(huì)是關(guān)于 GPU 和云資源的。云原生雖然彈性好但配額是硬約束不要假設(shè)資源隨時(shí)可得。關(guān)鍵任務(wù)要有預(yù)留資源非關(guān)鍵任務(wù)才用搶占式。而且資源使用要有配額管理防止某個(gè)任務(wù)把配額吃光導(dǎo)致其他任務(wù)無(wú)法提交。這些都是真金白銀換來(lái)的教訓(xùn)。