決策引擎系統設計原理與開源實踐

前幾天在 “開源小秀場” 分享了關於我自研的開源決策引擎系統的相關話題,主要介紹了 “天網決策引擎系統” 的開發設計原理以及如何將其部署到生產環境中使用。

01

決策引擎應用場景

隨着互聯網金融的發展以及銀行數字化轉型的需求,金融風控、智能風控、智能營銷等話題頻頻出現,而 “決策引擎” 作爲支撐其業務場景的核心繫統,也受到了更多的關注。一般來說,決策引擎可以用於包括金融風控、內容風控、推薦營銷、物聯網監控等各個領域,凡是涉及到使用規則或模型來做業務決策的場景都可以考慮使用決策引擎來實現。

規則引擎(專家系統)被更多人所熟知,那麼決策引擎又是什麼?和規則引擎有什麼區別和聯繫呢?我認爲,決策引擎正是在規則引擎的基礎上發展而來的。事實上,有不少決策引擎系統就是通過規則引擎改造實現的。而差別在於決策引擎在規則引擎的基礎上實現了更多元的決策方式,並引入了流程編排過程,使其可以支持更復雜的決策場景。

規則引擎的實現模式是規則清單,執行的主體是規則,簡單的規則引擎就是羅列出所有規則並執行,有些複雜的規則引擎會引入規則的優先級和規則編排,但編排的主體仍是規則。

決策引擎的實現模式是決策流編排,執行的主體是決策流,在決策流中編排不同的規則節點、決策節點以及分支節點來實現複雜的決策流程。

(左側爲規則清單,右側爲決策流)

02

決策引擎開發原理

**▌2.1 **規則構建

簡單介紹了決策引擎是什麼,現在我們來看一下它是如何實現的?將決策引擎拆解開來,從基礎構建元素 “規則” 開始,再將規則組合起來構成更復雜的決策集合。


(風控規則案例)

要實現這條規則,首先想到可以通過代碼 if / else 來實現。


(規則模擬代碼)

此代碼有明顯的硬編碼問題,規則調整要涉及到開發、測試、上線的流程,調整週期長。且規則邏輯維護到了代碼中,難以傳承,也容易造成生產中跑的規則和業務預想的規則有差異。當有大量規則或決策場景接入時,工作量巨大難以維護。

(生產中的決策流包含幾十個決策節點)

(生產中的規則集包含上百條規則)

爲了實現規則調整不受系統制約,我們需要將 規則配置 與 程序代碼 進行分離。我們可以通過在程序中嵌套腳本或代碼來實現,這樣每次調整規則,只需要重新加載即可,而不用修改和發佈系統程序。

常見的嵌入式腳本有 Lua、Groovy、Javascript 等,市面上有不少引擎是基於此類腳本語言實現的。另一種方式可以通過自定義語言語法,也叫領域特定語言 Domain Specific Language(DSL),比如大名鼎鼎的開源規則引擎 Drools 就自己實現了一套 DSL 語法(命名爲 DRL)。DSL 可以更清晰地表達要實現的規則含義。


(Drools 語法 demo)

我們也自定義實現了一套 DSL ,使用的語法結構是 Yaml。簡單介紹下 Yaml 是一個輕量級的語法結構,比 xml / json 更小巧,可讀性非常好,完全面向人類語言,也有很好的表達能力,支持多種數據結構。

回到剛纔的規則,我們看看如何用 Yaml 將該規則描述出來。對規則進行拆解發現,規則由三個條件表達式組成。

每個條件表達式又分別由 特徵、運算符、閾值 構成。

然後將這三個條件表達式的計算結果,再進行邏輯(布爾)運算。

(表達式一 或 表達式二) 且 表達式三

邏輯運算後的結果,如果是 true,即代表命中,觸發結果輸出 “拒絕”。

將上述過程用 Yaml 語法描述如下。

構建出規則 DSL 後,我們對其進行語法解析,從上述分析來看,解析過程主要是分別完成條件表達式的比較運算以及針對表達式結果的邏輯運算,最後根據結果輸出。

實現比較運算的算子,要考慮不同類型特徵需要支持不同的操作符和不同的實現。如數值型特徵,支持大於、小於、等於、不等於、大於等於、小於等於、區間等;字符串特徵支持等於、不等於、模糊查找等;數組特徵的等於運算要考慮數組元素完全相同。實現時要根據特徵的不同,來做不同的比較算子邏輯。

此外還要實現邏輯運算(or、and)和算數運算(+ - * / % 平方、開方等)。

對於複雜的表達式支持,要實現表達式運算。像 Python 類動態語言,支持 eval 執行字符串表達式。而像 Golang、Java 類靜態語言,則需要自己實現字符串表達式的執行,其基本思路就是通過構建抽象語法樹,將操作符、特徵、常量區分出來,通過樹的有序遍歷來執行。有一些方便的三方包可以輔助實現表達式執行,如 govaluate(Golang)、SpEL(Java)、QLExpress(Java)。

參考代碼:https://github.com/skyhackvip/risk_engine/tree/master/internal/operator

**▌2.2 **規則組合

實現了基本規則和表達式,那麼將規則和表達式以不同的方式組合起來,就構成了規則集、決策樹、決策表等不同的組合形式。

規則集,就是多條規則組成的集合,規則集中的所有規則都是並列的,每條規則的執行都不影響其他規則,可以串行依次執行,也可以並行執行。

規則集的 Yaml 描述,就是在規則的基礎上進行嵌套來實現。

如果要讓規則集中的規則並行執行,可以設置規則執行計劃,增加 Yaml 描述。

exec_plan=parallel

執行時,將每條規則都放置到 goroutine 中執行,得益於 Golang 協程的輕量級特性,每條規則可以開一個協程,並行執行效率更高,通過 WaitGroup 彙總等待所有規則執行完成。

如果同時命中了規則集的多條規則,而規則的觸發策略不同,有的規則觸發輸出通過,有的則輸出拒絕,那麼規則集要對結果進行衝突決策,可以通過設置觸發結果的優先級,優先級高的結果作爲規則集的輸出結果。

其他更多的決策類型,如決策樹、決策矩陣、評分卡可以參閱之前文章。

詳情參閱:

決策節點實現

評分卡實現

**▌2.3 **決策流實現

有了不同類型的節點(規則集、決策樹、決策矩陣、評分卡等),我們進一步將不同的節點編排起來即形成了決策流。

決策流可分無分支決策流和有分支決策流。無分支決策流即將所有節點順序連接起來。所謂分支即決策流在執行到該節點時根據不同的條件進行分流選擇,分流方式可以是條件分流(如根據性別條件分男、女兩條分支),也可是隨機分流(也叫冠軍挑戰者、Abtest,隨機分 55% 流量和 45% 流量兩條分支)。

決策流實現遵循 BPMN 規範,包含開始節點、結束節點、活動節點(放置不同的規則集、決策樹、決策矩陣等)、分流節點(條件分流、隨機分流)、帶箭頭的線代表流向。

要實現決策流,首先要對決策流的數據結構進行技術選型,考慮是基於樹、圖還是單向鏈表或其他結構。

首先決策流是有流向(方向)的,也就是說前後節點存在依賴關係,後繼節點依賴於前繼節點的結果。比如決策樹節點輸出了評級特徵,後繼分流節點根據評級不同走不同的分支。對於有方向的特性,樹、無向圖結構無法採用。

有向圖如果存在環,會造成執行死循環,無法終止,所以不滿足。剩下有向無環圖和單向鏈表可以放入備選方案考慮。

先來看看有向無環圖(DAG)的方案:


(DAG:a-e 分別代表不同任務節點)

有向無環圖實現了有向的依賴關係,計算過程沿着依賴關係方向進行,後繼節點 b 是依賴於前繼節點 a 執行完成;同時 (c->d)節點執行和 (f->g)節點執行可以並行,提高執行效率。因此有向無環圖方案是可行的,DAG 方案可用於檢測配置的決策流的正確性,驗證決策流 “不成環”、“全連通” 等。

此外介紹一下網絡圖(Rete)的方案:


(Rete:斜線左上方爲 alpha 網絡,右下方爲 beta 網絡)

Rete 網絡方案是一種高效的規則解析方案,Drools 即選擇該方案來進行規則引擎的執行。其優點是通過構建的 beta 網絡緩存記憶了推理數據,利用空間換時間加速了結果的推理。缺點是算法比較複雜。

介紹了兩種可行的方案後,我們引入新的需求,進一步評估下新需求下方案的選擇。

需求一:分支節點實現的是排它網關,無論是做隨機分流還是條件分流,都是排它執行。即通過上圖節點 b 後會選擇 (c->d) 或 (f->g)其中一條路徑執行,而不是全部節點執行。

需求二:決策流支持熔斷。即執行到某節點時,由於其輸出或命中滿足特定條件,就會終止不繼續執行。比如執行到節點 c,觸發了黑名單規則,要做熔斷處理,那麼就會返回結果,而放棄繼續執行 d、e 節點。

帶着這兩個需求來評估,對於 DAG 來說,其圖遍歷過程會執行所有節點,而 Rete 也無法簡單的支持分流和熔斷。這裏考慮使用另一種解決方案,改進型單向鏈表方案。

改進型單向鏈表,對於無分支的決策流,按指針順序執行即可。對於有分支的決策流,可以通過剪枝的方式將流拉平爲單向鏈表。而剪枝的方法就是在執行到分支節點的時候,根據執行結果動態的輸出下一個節點是什麼,進而控制決策流走向。

同時,每個節點執行完畢後,都可以查看是否滿足熔斷策略,如果滿足熔斷策略,可以控制後繼節點爲空,終止決策流的執行,進而實現決策流熔斷能力。

執行過程採用了改進 Pipeline 模型,執行依賴通過全局上下文 Context 來控制。執行時,節點所依賴特徵可以通過全局上下文來獲取,其輸出結果也將存儲到全局上下文中,後繼節點即可通過全局上下文獲取到上一節點已處理的特徵和結果來完成節點計算。節點之間通過全局上下文交換數據,可保障節點間無直接依賴關係(解耦),實現靈活編排,同時全局上下文也掌握全部的依賴特徵、執行過程數據、執行結果數據和執行路徑信息等,用於最終輸出。這種模式也稱爲 “全局工作臺模式”。

確定了數據結構方案,我們還是通過 Yaml 來描述出一個簡單的決策流,然後通過代碼解析 Yaml(DSL) 來實現決策流的執行。

左側 Yaml 描述決策流:

右側解析決策流代碼:

參考代碼:https://github.com/skyhackvip/risk_engine/blob/master/core/flow.go

03

開源決策引擎實踐

▌3.1 天網決策引擎介紹

天網決策引擎系統是完全免費開源的決策引擎系統,基於 Golang 語言開發,實現自定義 DSL 語言,實現決策流編排和複雜規則決策。

開源決策引擎介紹

天網決策引擎通過啓動 WEB 服務,對外提供 HTTP 接口,實現了開箱即用。其輸出結果包含決策過程和決策結果的完整信息,可以據此進行業務邏輯的組裝。

天網決策引擎代碼結構簡單,有完整語法文檔可參考,可以快速實現業務接入。

▌3.2 生產環境應用

如果你打算嘗試使用天網決策引擎系統,後期生產迭代方向和上下游系統架構可以考慮如下兩方面。

1) 構建可視化的管理後臺

雖然 Yaml 語法簡單易懂,但它仍偏向於技術人員,如果要交付給風控業務團隊直接使用,需要構建一個可視化管理後臺。通過可視化後臺可以快速實現規則編輯,決策流繪製等工作,調整完成後可以一鍵發佈生成 DSL,決策引擎發現決策流變更,重新加載最新數據,這個過程可以藉助數據庫來實現。

在決策流發佈時,還可以增加審批、完整性校驗等,保障發佈安全可靠。

2) 上下游系統架構

決策引擎一般是作爲中颱提供服務的,其上游對接業務後端系統,根據接入場景對接不同上游系統。如風控場景中根據貸前、貸中、貸後分別對接申請授信、貸中監測、貸後催收等系統。

決策引擎下游主要依賴於特徵指標平臺,根據特徵指標的來源和加工方式的不同,又可能包括數據 API 平臺,對接一些三方徵信數據接口或其他內部接口。實時計算引擎,實現特徵指標的實時加工。基於圖關係的圖特徵也可以通過圖數據庫來實現。

此外,一些需要使用機器學習模型的場景,還會包含建模相關平臺(AI 中臺),模型執行平臺(模型引擎)實現在線實時打分,模型分也作爲特徵指標提供給決策引擎做決策支持。

決策引擎配套可視化管理後臺,提供給業務人員進行配置,其結果可以輸出到風險大盤中進行實時監控分析和風險預警。

調用時序圖中,決策引擎在執行時依賴的特徵指標可由上游系統推送(推模式),也可以按需實時從特徵引擎中加載(拉模式),實現推拉結合的模式。實際場景中一些三方數據因爲考慮費用問題,可以採用拉模式延時加載,配置決策流先執行內部特徵和黑名單規則,命中熔斷即不會產生數據調用成本。

最後歡迎大家下載試用起來,如有任何問題也可以通過 “技術歲月” 公衆號與我聯繫。

開源決策引擎下載地址:https://github.com/skyhackvip/risk_engine

以上就是分享的全部內容,如要下載分享 PPT 可以關注公衆號 “技術歲月”,發送 開源小秀場 即可。

直播回放地址:https://z.itpub.net/article/detail/71BA0EB721592F5782F8F17001E66E68

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Z6xFrt2cg61w59wtTV7GuA