AI 應用推理架構中五大關鍵問題的解決方案 原創(chuàng) 精華
一個企業(yè)級的 AI 應用推理架構中往往面臨以下5個關鍵問題:限流、負載均衡、異步化、數(shù)據(jù)管理、索引增強,本文對這5個關鍵問題進行深度剖析并給出優(yōu)雅的解決方案。
1、AI 應用推理架構中的關鍵問題剖析
落地一個企業(yè)級 AI 應用產(chǎn)品是一項復雜的任務,它涉及到多個層面的產(chǎn)品化挑戰(zhàn)。為了確保產(chǎn)品的穩(wěn)定性、效率和高質(zhì)量的輸出結果,必須在大模型推理引擎的外圍進行大量的工程優(yōu)化工作。以下是構建此類 AI 應用服務時可能遇到的一些關鍵問題:
第一、接入層調(diào)度問題
- 用戶請求的速率可能遠高于大模型推理服務的處理速率,導致請求積壓和服務器過載。
- 推理服務器間的負載可能不均衡,一些服務器過載而另一些則資源閑置,影響整體性能。
- 推理請求的處理時間可能較長且不確定,使得接入層服務難以設置合適的超時時間,增加了連接異常斷開的風險。
- 傳統(tǒng)的一問一答模式限制了人機交互的流暢性,無法支持復雜的雙向交互。
第二、用戶數(shù)據(jù)管理問題
- 需要有效管理用戶信息,以便根據(jù)用戶的具體需求定制化服務。
- 在多輪對話場景中,需要存儲和管理歷史對話信息,以維持對話的連貫性。
第三、結果的準確性問題
- 由于大模型的訓練數(shù)據(jù)有限,可能無法覆蓋所有行業(yè)數(shù)據(jù)和企業(yè)私域數(shù)據(jù),影響結果的準確性。
2、AI 應用推理架構中5大關鍵問題解決方案
上面提到的 AI 應用推理架構中的問題可以概括為5大關鍵問題,分別為:限流、負載均衡、異步化、數(shù)據(jù)管理、索引增強,下面我們針對每個關鍵問題來逐一給出解決方案。
第一、限流關鍵問題的解決方案
為確保 AI 應用推理服務在面臨前端請求速率與后端處理速率不匹配時的穩(wěn)定性,防止服務過載,并維持服務的吞吐量和服務質(zhì)量水平,實施請求限流是一種有效策略。在傳統(tǒng)微服務服務架構中,可以利用 Redis 的 Incr 命令結合過期時間機制來實現(xiàn)固定窗口限流功能。
以下是實現(xiàn)該限流邏輯的偽代碼示例:
ret = jedis.incr(KEY);
if (ret == 1) {
// 設置過期時間
jedis.expire(KEY, EXPIRE_TIME);
}
if (ret <= LIMIT_COUNT) {
return true;
} else {
return false;
}
這是一種基礎的限流方法,它能夠在一個固定的 ??EXPIRE_TIME ?
??時間內(nèi)限制用戶的請求數(shù)量不超過 ??LIMIT_COUNT?
?。
然而,這種方法存在一些不足之處:限流效果不夠平滑,用戶可能在限流周期開始的第一秒就耗盡了所有的請求額度,導致在剩余時間內(nèi)無法進行任何請求。此外,這種方法還要求用戶不斷嘗試重新發(fā)送請求,這可以想象,在一個人機交互的場景中,如果機器人服務一直提示用戶“系統(tǒng)繁忙,請稍后再試”,而用戶需要不斷重試,這種體驗是非常糟糕的。
為了改善這個問題,我們可以采用令牌桶算法的限流邏輯,它能夠解決限流不平滑和減少用戶重試的需求。
以下是采用令牌桶算法的限流邏輯的偽代碼示例:
// 請求端阻塞方式獲取令牌
jedis.blpop(TIMEOUT, KEY);
// 令牌生成端,定期向隊列中投放令牌
if (jedis.llen(KEY) < MAX_COUNT) {
jedis.rpush(KEY, value, ...);
}
在限流策略中,引入等待機制可以在一定時間內(nèi)避免用戶端的重復請求嘗試。如果用戶在指定的 TIMEOUT 時間內(nèi)未能成功獲取令牌,則請求將被判定為失敗。這種方法有效減少了用戶端的重試頻率。通過設置較短的令牌發(fā)放間隔,可以實現(xiàn)更加平滑的流量控制。
然而,這種限流方法并沒有細致區(qū)分不同請求對推理服務器資源的不同影響。由于不同的推理請求可能會對推理服務器資源造成不同程度的消耗,因此,依據(jù)生成的 Token 數(shù)量來評估資源消耗可能更為合理。此外,業(yè)務可能需要根據(jù)特定情況實施自定義的限流邏輯。
為了滿足復雜的限流需求,僅依靠 Redis 的基本接口可能不夠靈活。因此,引入一個獨立的限流服務變得必要。該服務通過 Redis 與接入服務和限流服務解耦,利用 Redis 實現(xiàn)消息通知和結果推送。
簡化后的 AI 應用推理服務框架如下圖所示:用戶的請求首先到達無狀態(tài)的接入服務。接入服務利用 Redis 將限流相關的請求轉(zhuǎn)發(fā)至限流服務。限流服務根據(jù)用戶標識信息(uid)、推理服務器的負載情況、令牌狀態(tài)等,結合業(yè)務邏輯和策略,決定請求是直接失敗還是進入排隊隊列。請求在排隊成功或超時后,限流服務將結果通知接入服務,接入服務根據(jù)限流結果決定是否將請求轉(zhuǎn)發(fā)至推理服務。
通過這種設計,獨立的限流服務能夠根據(jù)產(chǎn)品的具體需求定制限流策略,實現(xiàn)復雜的限流邏輯。同時,Redis 作為消息隊列,不僅解耦了接入服務和限流服務,還完成了限流結果的實時推送,提高了系統(tǒng)的靈活性和響應速度。
這種架構設計使得系統(tǒng)能夠更加精細和靈活地控制流量,同時保證了服務的穩(wěn)定性和高效性,為實現(xiàn)高級的業(yè)務需求提供了支持。
第二、負載均衡關鍵問題的解決方案
為了應對不斷增長的業(yè)務需求,后端通常會部署多臺服務器來處理請求,這就需要一種策略來將用戶的請求路由到合適的推理服務器上。常見的做法是使用 LVS、Nginx 等提供的第4層(L4)和第7層(L7)負載均衡服務來分配請求。
負載均衡器通常采用輪詢調(diào)度(Round Robin)或加權輪詢的方式來分發(fā)請求。這些調(diào)度算法沒有考慮到請求之間的差異,也沒有動態(tài)地考慮服務器負載的差異。在傳統(tǒng)的應用場景中,由于每個用戶請求對服務器的資源消耗相差不大,且請求執(zhí)行速度快、資源消耗少,因此在請求數(shù)量足夠多的情況下,各個服務器的負載會趨于均衡。
然而,在 AI 應用推理場景下,不同請求對推理服務器的資源消耗可能有很大差異,請求執(zhí)行時間較長,資源消耗較高。如果采用輪詢調(diào)度的方式,可能會導致部分推理服務器過載,而另一部分服務器的資源卻閑置,這不僅無法最大化整體吞吐量,也無法保證服務水平目標(SLO)。
雖然傳統(tǒng)的負載均衡服務提供了基于應用服務器的連接數(shù)、負載等指標的動態(tài)調(diào)度算法,但在推理場景下,這些算法的效果并不理想。應用服務器的連接數(shù)并不能準確代表其負載,而且負載指標通常是由負載均衡服務定期刷新的,無法實時更新。此外,多個負載均衡服務器之間的狀態(tài)同步也需要時間,如果多個負載均衡服務器同時將請求調(diào)度到一個負載較低的推理服務器上,可能會導致該服務器過載。
總的來說,由于單個推理請求的資源消耗較大,個體差異較大,少量的調(diào)度失衡就可能導致負載差異很大,因此傳統(tǒng)的負載均衡服務無法滿足推理請求的調(diào)度需求。
目前,針對推理請求的調(diào)度主要有兩類方案:
- 基于代價估算的方案:由一個調(diào)度器評估每條推理請求的代價,通過一個小模型快速估算請求推理結果所需的 Token 數(shù)量,然后在全局維度上根據(jù)估算的代價來分發(fā)請求。這種方案的優(yōu)點是在分發(fā)請求時能夠考慮 KVCache 的親和性,比如:將多輪對話分發(fā)到同一臺推理服務器上,復用之前的 KVCache,減少重復計算。但缺點是調(diào)度邏輯較為復雜,調(diào)度器需要考慮服務器負載、請求估算代價、KVCache 親和性等多個指標,而且全局的調(diào)度器可能存在性能瓶頸,也需要考慮高可用性問題。當估算模型出現(xiàn)偏差時,還可能導致負載不均。
- 基于拉取的模型:接入服務并不直接將請求轉(zhuǎn)發(fā)給推理服務,而是將請求放入 Redis 的 stream 結構中,當推理服務空閑時,主動從 Redis 拉取請求。這保證了所有推理服務都能在最佳負載下運行。這種方案的優(yōu)點是實現(xiàn)起來比較簡單,能夠保證推理服務器在最佳負載下運行,同時實現(xiàn)服務器間的負載均衡,提高整體吞吐量。缺點是很難保持 KVCache 的親和性,后續(xù)優(yōu)化手段有限。
這兩種方案各有優(yōu)缺點,需要根據(jù)具體的業(yè)務需求和系統(tǒng)架構來選擇最合適的負載均衡調(diào)度策略。
第三、請求異步化關鍵問題的解決方案
在復雜的模型推理場景中,由于推理過程耗時較長且推理時間不確定,如果接入服務同步等待結果,可能會導致過多的 HTTP 連接,以及因連接異常斷開而導致的請求失敗等問題,這些問題會降低整體性能并增加失敗率。
另一方面,同步請求方式通常遵循用戶發(fā)起提問、服務端完成推理后返回答案的一問一答模式。如果服務端能夠合理判斷用戶需求并主動發(fā)起對話,可以提升交互體驗。例如,當用戶詢問北京的景點后,他們可能對北京的旅游感興趣,因此也可能關心北京的酒店信息。異步化可以使架構更加靈活,簡化后期擴展新業(yè)務邏輯的過程。
此時,可以引入 Redis 作為消息隊列,將推理結果寫入 Redis stream 結構中。接入服務在請求提交成功后即可返回用戶請求提交成功的狀態(tài),并可以流式地返回推理結果,避免用戶長時間等待。此外,這種設計解耦了接入服務和推理服務之間的強綁定關系,允許其他服務組件也能向 Redis stream 結構寫入數(shù)據(jù),實現(xiàn)對用戶的主動交互。
通過異步化改造,可以獲得以下好處:
- 流式返回結果給用戶,提升用戶體驗。
- 解耦組件間的直接關聯(lián),方便后續(xù)業(yè)務邏輯的擴展。
- 避免請求發(fā)起端盲目等待結果返回,提高效率。
第四、用戶數(shù)據(jù)管理關鍵問題的解決方案
1.用戶信息管理與個性化服務
通過整合用戶的注冊信息和歷史對話記錄,系統(tǒng)能夠為每位用戶創(chuàng)建獨特的標簽。這些標簽隨后作為系統(tǒng)提示(Prompt)與用戶請求一同提交至推理引擎,從而生成定制化的結果。這種“千人千面”的方法使得服務結果更貼合用戶的個性化需求和預期。
利用 Redis 的 hash 結構,可以以樹狀格式高效存儲用戶的屬性信息,該結構同時支持快速的單個查詢(點查)和批量查詢操作。
2.歷史消息管理與對話連續(xù)性
在多輪對話場景中,系統(tǒng)需存儲先前的對話內(nèi)容,并將這些信息作為提示詞(Prompt)影響后續(xù)請求,以保持對話的連貫性。此外,為了產(chǎn)品化需求,系統(tǒng)還需保存用戶在一定時間內(nèi)的歷史對話記錄,以便用戶能夠回顧之前的交流內(nèi)容。
對話信息的存儲方式具有很高的靈活性,可采用多種實現(xiàn)策略。例如,可以使用 zset 結構來保存歷史對話,并將對話的時間戳作為評分(score),這樣不僅便于對對話信息進行排序,還能輕松實現(xiàn)最早對話的刪除以及按時間順序查看歷史對話。
如果服務已經(jīng)通過 stream 結構實現(xiàn)了異步化改造,那么所有的推理請求和結果都將存儲在 stream中,無需額外存儲。Stream 結構支持設置隊列大小,并能自動刪除最早的對話消息。
3.會話(Session)管理
鑒于不同的對話可能涉及不同的上下文信息,可以使用 Redis 的 hash 結構來存儲會話(session)信息,以實現(xiàn)快速切換和管理。這種方法有助于維護不同對話的獨立性和連貫性,提升用戶體驗。
第五、RAG(檢索增強生成)
采用檢索增強生成(Retrieval-Augmented Generation,簡稱 RAG)的方法可以有效應對傳統(tǒng)大語言模型(LLM)在實際應用中遇到的限制,這些限制包括:
- 知識更新滯后:LLM 的訓練數(shù)據(jù)往往停留在某個時間節(jié)點,難以實現(xiàn)實時更新。
- 產(chǎn)生幻覺:LLM 有時會產(chǎn)生與事實不符的內(nèi)容。
- 領域?qū)I(yè)性不足:通用模型在特定領域(比如:法律、醫(yī)學等)的表現(xiàn)可能不盡如人意。
- 推理能力有限:LLM 在處理復雜的推理任務時可能表現(xiàn)不佳。
與大模型微調(diào)(Fine-tuning)相比,RAG 方法的成本更低,且能保持更高的數(shù)據(jù)時效性。
以實現(xiàn)一個接入 Milvus 向量數(shù)據(jù)庫的 FAQ 問答機器人為例,可以采取以下方案:
- 數(shù)據(jù)檢索:利用 Milvus 等向量數(shù)據(jù)庫,根據(jù)用戶的問題檢索最相關的 FAQ 條目。
- 信息融合:將檢索到的信息與 LLM 的生成能力相結合,以提供更準確、更豐富的回答。
- 上下文理解:通過檢索增強,LLM 能夠更好地理解上下文,從而提高回答的相關性和準確性。
- 持續(xù)更新:由于 RAG 不依賴于模型的全面微調(diào),因此可以更容易地更新知識庫,以反映最新的信息和數(shù)據(jù)。
通過這種方式,RAG 不僅能夠提高問答系統(tǒng)的性能,還能夠保持成本效益和靈活性,使其成為處理特定領域問題的有效工具。
綜合上述5個關鍵問題的解決方案,一個典型場景的 AI 應用推理服務流程如下所示:
1.用戶發(fā)起請求到接入服務服務器。
2.接入服務異步請求限流服務,并在請求的 UUID 上等待 Redis 通知。
3.限流服務在排隊完成或超時后通過 Redis 將限流結果通知給接入服務。
4.接入服務通過 Redis 查詢到用戶信息、歷史對話信息,作為請求的 Prompt。
5.接入服務通過 Milvus 向量檢索拿到相關信息,也作為請求的 Prompt。
6.接入服務將請求寫入 Redis stream 隊列。
7.空閑的推理服務從 Redis stream 拉取到推理請求。
8.推理服務將推理結果寫入 Redis stream 隊列。
9.接入服務通過 Redis 異步獲取到推理結果。
10.返回用戶結果。
這個流程描述了用戶請求如何通過接入服務、限流服務、Redis 以及推理服務進行處理,并最終將結果返回給用戶。通過使用 Redis 作為消息隊列和存儲,實現(xiàn)了請求的異步處理和負載均衡,提高了系統(tǒng)的響應性和可靠性。
?? 輪到你了:你認為 AI 應用企業(yè)級落地還有哪些注意點?
本文轉(zhuǎn)載自??玄姐聊AGI?? 作者:玄姐
