商業(yè)CRM系統(tǒng)的商機(jī)模塊業(yè)務(wù)復(fù)雜、場(chǎng)景繁多、規(guī)則調(diào)整頻繁,商機(jī)流轉(zhuǎn)效率一定程度決定了銷售開(kāi)單的效率。如何高效配合產(chǎn)品側(cè)完成業(yè)務(wù)規(guī)則調(diào)整,商機(jī)流轉(zhuǎn)經(jīng)歷了硬編碼到半配置化的優(yōu)化升級(jí),過(guò)程中遇到了一些問(wèn)題,也總結(jié)了一些經(jīng)驗(yàn),今天來(lái)和大家掰開(kāi)揉碎了講一講這其中遇到的問(wèn)題和解決方案。
先看一下CRM的官方定義:
CRM(Customer Relationship Management):客戶關(guān)系管理,是指企業(yè)為提高核心競(jìng)爭(zhēng)力,利用相應(yīng)的信息技術(shù)以及互聯(lián)網(wǎng)技術(shù)協(xié)調(diào)企業(yè)與顧客間在銷售、營(yíng)銷和服務(wù)上的交互,從而提升其管理效率,向客戶提供創(chuàng)新式的個(gè)性化的客戶交互和服務(wù)的過(guò)程。
其最終目標(biāo)是:吸引新客戶、保留老客戶以及將已有客戶轉(zhuǎn)為忠實(shí)客戶,增加市場(chǎng)。
可以這么簡(jiǎn)單的理解,CRM的核心價(jià)值就是:將潛在客戶更高效的轉(zhuǎn)化為客戶,將客戶更高效的轉(zhuǎn)化為長(zhǎng)期客戶。
圖片
介紹完什么是CRM,那CRM系統(tǒng)就很容易理解了,用于支撐企業(yè)進(jìn)行客戶關(guān)系管理的系統(tǒng),就可以稱作CRM系統(tǒng)。這個(gè)定義比較寬泛,每個(gè)公司對(duì)CRM中功能邊界也不完全一樣,大家初步理解這個(gè)概念就行。比如轉(zhuǎn)轉(zhuǎn)商業(yè)CRM系統(tǒng),主要包含:商機(jī)管理、客戶管理、銷售/運(yùn)營(yíng)人員管理、業(yè)績(jī)管理、效率監(jiān)控等功能模塊。
要想把潛在客戶變成客戶,就需要銷售人員進(jìn)行跟進(jìn),對(duì)潛在客戶進(jìn)行產(chǎn)品的售賣,用戶購(gòu)買產(chǎn)品后,變成客戶。這個(gè)潛在客戶,我們稱作“商機(jī)”,也就是一次成單的機(jī)會(huì),有的CRM系統(tǒng)中,也稱為“線索”。
上圖是潛在用戶到客戶簡(jiǎn)單的流轉(zhuǎn)圖
從商機(jī)生成到最終成單,銷售跟進(jìn)過(guò)程中,涉及一些概念,比如商機(jī)池(公海池、私海池)、商機(jī)狀態(tài)/來(lái)源/類型/等級(jí)、商機(jī)的流轉(zhuǎn)等。
商機(jī)池:各種商機(jī)的集合。公海池:該集合里的商機(jī)當(dāng)前不歸屬于任何銷售,所有銷售均可以看到公海里的商機(jī)。私海池:綁定了特定銷售的商機(jī)集合,比如銷售A的商機(jī)私海池,只有銷售A可以看到和跟進(jìn),其他銷售不可見(jiàn)、不可跟進(jìn)。商機(jī)流轉(zhuǎn):商機(jī)在跟進(jìn)過(guò)程中,被不同的銷售跟進(jìn),狀態(tài)發(fā)生不同的變化。流轉(zhuǎn)規(guī)則:流轉(zhuǎn)過(guò)程中會(huì)有各種各樣的業(yè)務(wù)規(guī)則限制,比如銷售最多可以認(rèn)領(lǐng)100條商機(jī)、負(fù)責(zé)手機(jī)類目的銷售不能認(rèn)領(lǐng)電腦類目的商機(jī)、銷售剛放棄的商機(jī)不能立馬重新認(rèn)領(lǐng)、單位時(shí)間內(nèi)不進(jìn)行電話溝通的商機(jī)將流出銷售私海等等。
這里舉一個(gè)例子來(lái)說(shuō)明商機(jī)的流轉(zhuǎn),業(yè)務(wù)背景:商機(jī)對(duì)應(yīng)用戶主營(yíng)類目為手機(jī),銷售A、B負(fù)責(zé)手機(jī)類目,銷售C負(fù)責(zé)電腦類目,銷售D也負(fù)責(zé)手機(jī)類目。
圖片
這是一個(gè)簡(jiǎn)單的流程,實(shí)際流程比這個(gè)復(fù)雜。從這個(gè)簡(jiǎn)易的流程介紹中,可以窺見(jiàn)部分商機(jī)流轉(zhuǎn)模塊的業(yè)務(wù)特點(diǎn),總結(jié)起來(lái)有三點(diǎn):
圖片
圖片
圖片
之前商業(yè)CRM中關(guān)于流轉(zhuǎn)的處理邏輯,好多都是硬編碼,舉個(gè)銷售認(rèn)領(lǐng)某條商機(jī)的例子:
//狀態(tài)校驗(yàn)if(checkClueStatus(param)){ return “狀態(tài)不合法”;}//綁定人校驗(yàn)if(checkClueBindUser(param)){ return “上一個(gè)綁定人不可以為···”;}//私海容量校驗(yàn)if(checkPrivateClueCount(param)){ return “私海庫(kù)已滿,無(wú)法操作··”;}//類目校驗(yàn)if(checkClueCate(param)){ return “類目不匹配,無(wú)法操作··”;}//任務(wù)是否完成校驗(yàn)if(checkClueTaskFinished(param)){ return “任務(wù)未完成,無(wú)法操作··”;} ······bind(param);//綁定操作log();//日志記錄操作
從代碼中可以看出,銷售從公海進(jìn)行認(rèn)領(lǐng)一條自己覺(jué)得有價(jià)值的商機(jī)時(shí),并不是直接就讓該商機(jī)流入到該銷售私海中,這個(gè)過(guò)程會(huì)有各種規(guī)則的業(yè)務(wù)校驗(yàn)。
帶著我們的痛點(diǎn)和訴求,接下來(lái)看看可以找到什么樣的解決方案。然后我們進(jìn)入了調(diào)研階段,發(fā)現(xiàn)對(duì)于這種策略比較密集的業(yè)務(wù),規(guī)則引擎是一個(gè)可參考方向,然后就開(kāi)始了解規(guī)則引擎相關(guān)細(xì)節(jié),了解完后,發(fā)現(xiàn)和業(yè)務(wù)問(wèn)題匹配度很高。接下來(lái),先介紹一下規(guī)則引擎相關(guān)的基本知識(shí)。
規(guī)則就是:條件 --> 推理 --> 結(jié)果。一個(gè)完整的規(guī)則是需要這三部分元素的,平時(shí)大家討論規(guī)則,某些時(shí)候只是在討論第一部分的條件,比如學(xué)校的行為規(guī)范,咱們國(guó)家的各種法律條文,可能關(guān)注的部分是需要滿足什么條件(不能做什么什么),后面的推理和結(jié)果省去了。比如學(xué)生準(zhǔn)則里的不辱罵同學(xué),這是一個(gè)條件,那怎么算辱罵呢,這是推理過(guò)程,辱罵后會(huì)發(fā)生什么呢,會(huì)受到老師批評(píng),這是結(jié)果。
那什么是推理引擎和規(guī)則引擎呢?
圖片
推理引擎通過(guò)決定哪些規(guī)則滿足事實(shí)或目標(biāo),并授予規(guī)則優(yōu)先級(jí),滿足事實(shí)或目標(biāo)的規(guī)則被加入議程,具體過(guò)程:
推理方式分為正向推理和反向推理
常見(jiàn)的模式匹配算法有Rete,LFA,TREAI,LEAPS。Rete算法是目前效率最高的一個(gè)演繹法推理算法,許多規(guī)則引擎都是基于Rete算法來(lái)進(jìn)行推理計(jì)算的。
圖片
這是Rete算法的原理圖,Rete算法涉及兩種網(wǎng)絡(luò)和6種不同作用的節(jié)點(diǎn)。
圖片
a) 檢查模式1中的參數(shù)類型,如果是新類型,添加一個(gè)類型節(jié)點(diǎn)。
b) 檢查模式1對(duì)應(yīng)的Alpha節(jié)點(diǎn)是否存在,如果存在記錄下節(jié)點(diǎn)的位置;如果沒(méi)有,將模式1作為一個(gè)Alpha節(jié)點(diǎn)加入到網(wǎng)絡(luò)中。同時(shí)根據(jù)Alpha節(jié)點(diǎn)建立Alpah內(nèi)存表。
c) 重復(fù)b,直到處理完所有模式。
d) 組合Beta節(jié)點(diǎn):Beta(2)左輸入節(jié)點(diǎn)為Alpha(1),右輸入節(jié)點(diǎn)為Alpha(2);Beta(i)左輸入節(jié)點(diǎn)是Beta(i-1),右輸入節(jié)點(diǎn)為Alpha(i),并將兩個(gè)父節(jié)點(diǎn)的內(nèi)存表內(nèi)聯(lián)成為自己的內(nèi)存表。
e) 重復(fù)d,直到所有Beta節(jié)點(diǎn)處理完畢。
f) 將動(dòng)作Then部分封裝成最后節(jié)點(diǎn)做為Beta(n)。
圖片
上面介紹的這些都偏理論化,可能有一點(diǎn)不太容易理解,沒(méi)關(guān)系,接下來(lái)咱們用一個(gè)具體的例子,看看Rete算法到底是如何運(yùn)行的。咱們依然以這個(gè)選拔籃球苗子的例子來(lái)說(shuō)明。
圖片
圖片
A節(jié)點(diǎn):拿StudentFact的年級(jí)數(shù)值進(jìn)行年級(jí)匹配,如果年級(jí)符合條件,則把該StudentFact的引用記錄到A節(jié)點(diǎn)的alpha內(nèi)存區(qū)中,退出年級(jí)匹配。
B節(jié)點(diǎn):拿StudentFact的性別內(nèi)容進(jìn)行性別匹配,如果性別符合條件,則把該StudentFact的引用記錄到B節(jié)點(diǎn)的alpha內(nèi)存區(qū)中,然后找到B節(jié)點(diǎn)左引用的Beta節(jié)點(diǎn),也就是C節(jié)點(diǎn)。
C節(jié)點(diǎn):C節(jié)點(diǎn)找到自己的左引用也就是A節(jié)點(diǎn),看看A節(jié)點(diǎn)的alpha內(nèi)存區(qū)中是否存放了StudentFact的引用,如果存放,說(shuō)明年級(jí)和性別兩個(gè)條件都符合,則在C節(jié)點(diǎn)的Beta內(nèi)存區(qū)中存放StudentFact的引用,退出性別匹配。
D節(jié)點(diǎn):拿StudentFact的年齡數(shù)值進(jìn)行年齡條件匹配,如果年齡符合條件,則把該StudentFact的引用記錄到D節(jié)點(diǎn)的alpha的內(nèi)存區(qū)中,然后找到D節(jié)點(diǎn)的左引用的Beta節(jié)點(diǎn),也就是E節(jié)點(diǎn)。
E節(jié)點(diǎn):E節(jié)點(diǎn)找到自己的左引用也就是C節(jié)點(diǎn),看看C節(jié)點(diǎn)的Beta內(nèi)存區(qū)中是否存放了StudentFact的引用,如果存放,說(shuō)明年級(jí),性別,年齡三個(gè)條件符合,則在E節(jié)點(diǎn)的Beta內(nèi)存區(qū)中存放StudentFact的引用,退出年齡匹配。
F節(jié)點(diǎn):拿StudentFact的身體數(shù)值進(jìn)行身體條件匹配,如果身體條件符合,則把該StudentFact的引用記錄到D節(jié)點(diǎn)的alpha的內(nèi)存區(qū)中,然后找到F節(jié)點(diǎn)的左引用的Beta節(jié)點(diǎn),也就是G節(jié)點(diǎn)。
G節(jié)點(diǎn):G節(jié)點(diǎn)找到自己的左引用也就是E節(jié)點(diǎn),看看E節(jié)點(diǎn)的Beta內(nèi)存區(qū)中是否存放了StudentFact的引用,如果存放,說(shuō)明年級(jí),性別,年齡,身體四個(gè)條件符合,則在G節(jié)點(diǎn)的Beta內(nèi)存區(qū)中存放StudentFact的引用,退出身體匹配。
H節(jié)點(diǎn):拿StudentFact的身高數(shù)值進(jìn)行身高條件匹配,如果身高條件符合,則把該StudentFact的引用記錄到H節(jié)點(diǎn)的alpha的內(nèi)存區(qū)中,然后找到H節(jié)點(diǎn)的左引用的Beta節(jié)點(diǎn),也就是I節(jié)點(diǎn)。
I節(jié)點(diǎn):I節(jié)點(diǎn)找到自己的左引用也就是G節(jié)點(diǎn),看看G節(jié)點(diǎn)的Beta內(nèi)存區(qū)中是否存放了StudentFact的引用,如果存放了,說(shuō)明年級(jí),性別,年齡,身體,身高五個(gè)條件都符合,則在I節(jié)點(diǎn)的Beta內(nèi)存區(qū)中存放StudentFact引用。同時(shí)說(shuō)明該StudentFact對(duì)象匹配了該規(guī)則,形成一個(gè)議程,加入到?jīng)_突區(qū),執(zhí)行該條件的結(jié)果部分:該學(xué)生是一個(gè)籃球苗子。
規(guī)則的條件與facts的數(shù)目如果過(guò)大,對(duì)應(yīng)memory會(huì)指數(shù)級(jí)升高,極端情況下會(huì)耗盡系統(tǒng)資源。
看完這個(gè)匹配的過(guò)程,相信大家對(duì)規(guī)則引擎中常用的Rete算法有了一定的了解。回到規(guī)則引擎,那為啥用規(guī)則引擎呢,也就是它有何優(yōu)勢(shì),以及有哪些適用的場(chǎng)景呢?
一般多用于規(guī)則較多且規(guī)則調(diào)整頻繁的業(yè)務(wù)場(chǎng)景,比如:積分規(guī)則、計(jì)費(fèi)系統(tǒng)、信用風(fēng)險(xiǎn)評(píng)估、監(jiān)控告警、工作流系統(tǒng)。
網(wǎng)上有兩種分類方式,這里我列舉出來(lái),供大家了解。
圖片
了解了上面這些業(yè)務(wù)背景以及遇到的問(wèn)題,也熟悉了規(guī)則引擎的理論知識(shí),現(xiàn)在需要制定具體的解決方案了,我們?cè)趺醋龅哪兀渴忻嬗懈鞣N各樣的規(guī)則引擎,先進(jìn)行技術(shù)選型,這里列舉下當(dāng)前主流規(guī)則引擎優(yōu)缺點(diǎn)。
圖片
通過(guò)各方面綜合評(píng)估,重點(diǎn)放到了Drools和easyRule兩者,且easyRule最終勝出。
圖片
確定了要使用easyRule就得知道easyRule如何使用的,先介紹下其相關(guān)概念和使用方法。
Easy Rules提供了3種CompositeRule的實(shí)現(xiàn)。
值越低優(yōu)先級(jí)越高。要覆蓋此行為,可重寫compareTo()方法以提供自定義優(yōu)先級(jí)策略。
支持自定義規(guī)則監(jiān)聽(tīng)器、規(guī)則引擎監(jiān)聽(tīng)器。
支持MVEL、SPEL表達(dá)式語(yǔ)言,可通過(guò)編程方式定義規(guī)則。
還是用篩選籃球苗子的例子
圖片
public class Student { /** * 年級(jí) */ private Integer grade; /** * 性別 */ private String gender; /** * 年齡 */ private Integer age; /** * 是否強(qiáng)壯 */ private Boolean isStrong; /** * 身高 */ private Integer height; /** * 是否一個(gè)好苗子 */ private Boolean isGoodSeed = true;}
//創(chuàng)建規(guī)則1-年級(jí)Rule rule1 = new MVELRule() .name("grade rule") .description("判斷一個(gè)學(xué)生是否是一個(gè)籃球好苗子-年級(jí)") .priority(1) .when("student.getGrade() <= 3") .then("System.out.println(/"年級(jí)-不是好苗子/");") .then("student.setIsGoodSeed(false);");
//創(chuàng)建規(guī)則2-性別Rule rule2 = new MVELRuleFactory(new YamlRuleDefinitionReader()). createRule(new FileReader( ResourceUtils.getFile("classpath:gender-rule.yml")));
規(guī)則2需要的yml文件內(nèi)容如下:
name: "gender rule"description: "判斷一個(gè)學(xué)生是否是一個(gè)籃球好苗子-性別"priority: 2condition: "student.getGender().equals(/"girl/")"actions: - "System.out.println(/"性別-不是好苗子/");student.setIsGoodSeed(false);"
//創(chuàng)建規(guī)則3-年齡 Rule rule3 = new MVELRuleFactory(new JsonRuleDefinitionReader()). createRule(new FileReader( ResourceUtils.getFile("classpath:age-rule.json")));
//創(chuàng)建規(guī)則4-是否強(qiáng)壯Condition condition = new MVELCondition("!student.getIsStrong()");Action action = new Action() { @Override public void execute(Facts facts) throws Exception { Student student1 = (Student) facts.get("student"); student1.setIsGoodSeed(false); System.out.println("強(qiáng)壯-不是好苗子"); }};Rule rule4 = new RuleBuilder() .name("strong rule") .description("判斷一個(gè)學(xué)生是否是一個(gè)籃球好苗子-是否強(qiáng)壯") .priority(4) .when(condition) .then(action).build();
@Rule(name = "height rule" ,description = "判斷一個(gè)學(xué)生是否是一個(gè)籃球好苗子-身高")public class HeightRule { @Condition public boolean checkHeight(){ return student.getHeight() <= 170;} @Action public void action(){ System.out.println("身高-不是好苗子"); student.setIsGoodSeed(false); } private Student student; public HeightRule(Student student){ this.student = student; }}//創(chuàng)建規(guī)則5-身高HeightRule rule5 = new HeightRule(student);
//創(chuàng)建一個(gè)Student實(shí)例(Fact) Student student = new Student(3,"girl",9,true, 160,true); Facts facts = new Facts(); facts.put("student", student);
//注冊(cè)規(guī)則Rules rules = new Rules();rules.register(rule1);rules.register(rule2);//rules.register(rule3);rules.register(rule4);rules.register(rule5);//創(chuàng)建規(guī)則執(zhí)行引擎,并執(zhí)行規(guī)則RulesEngine rulesEngine = new DefaultRulesEngine();System.out.println("開(kāi)始判斷是否是一個(gè)籃球苗子:" + JSON.toJSONString(student));rulesEngine.fire(rules, facts);System.out.println("是否為好苗子:" + student.getIsGoodSeed());
圖片
熟悉了easyRule如何使用的,接下來(lái)看看我們?nèi)绾卧陧?xiàng)目中落地的,我們分了幾步:
初始化規(guī)則相關(guān)配置(首次初始化+定時(shí)更新);
提供對(duì)外public T fire(String ruleId, V v)通用的規(guī)則引擎api接口。
圖片
這里我們將規(guī)則引擎的處理結(jié)果進(jìn)行了返回,因?yàn)闃I(yè)務(wù)上很多場(chǎng)景需要,比如不符合規(guī)則時(shí)的提醒文案。
項(xiàng)目中配置規(guī)則引擎相關(guān)配置;
實(shí)例化RuleEngineTemplate類;
根據(jù)場(chǎng)景,組裝上下文context;
調(diào)用ruleEngineTemplate.fire(ruleId,context)方法。
圖片
引入后,我們的商機(jī)流轉(zhuǎn)流程發(fā)生了如下變化:
圖片
圖片
spring: easy-rule: priority-threshold: 100 skip-on-first-failed-rule: false skip-on-first-applied-rule: true skip-on-first-non-triggered-rule: false rules: - rule-id: "opportunity_unbind" rule-file-location: "opportunity_unbind" #規(guī)則配置文件 rule-config-type: JSON rule-factory-type: SPEL
具體的規(guī)則配置json
[ { "name": "bind_check_cate", "description": "判斷是否凍結(jié)-72小時(shí)", "condition": "@opportunityUnbindRuleBll.checkOpportunityNeedFreeze(#context.getOpportunityId(), n,m)", "priority": 4, "actions": [ "@clueOpporBll.unbindOpportunity(#context,T(OpportunityStatusEnum).UNBIND, T(com.clue.enums.OpportunityMinorStatusEnum).UNBIND_FROZEN)" ] }, { "name": "task_bind_out", "description": "任務(wù)商機(jī)流回公海", "condition": "#context.getOpportunityStatus() == T(com.enums.OpportunityStatusEnum).TASK && #context.getOperationTypeEnum() == T(com.OpportunityOperationTypeEnum).TASK_BACK_PUBLIC", "priority": 5, "actions": [ "@clueBll.unbindOpportunity(#context,T(com.zhuanzhuan.biz.clue.enums.OpportunityStatusEnum).UNBIND, T(com.OpportunityMinorStatusEnum).UNBIND_NORMAL)" ] }, { "name": "unbind_operate", "description": "判斷解綁后去向,現(xiàn)階段全部回到公海", "condition": "true", "priority": 10, "actions": [ "@clueOpportunityBll.unbindOpportunity(#context,T(com.OpportunityStatusEnum).UNBIND, T(com.enums.OpportunityMinorStatusEnum).UNBIND_NORMAL)" ] } ] }]
public Result<ParallelExecuteDTO> unbindOpportunity(UnbindOpportunityRequest request) { return parallelExecutor.parallelExecute(request.getOpportunityIds(), (Long opportunityId) -> { final Result<String> unbindResult = opportunityUnbindRuleBll.unbindOpportunity(opportunityId, request.getOperator(), request.getReasonType(), request.getReasonDesc(), request.getOperationType()); logger.info("method=unbindOpportunity, act=unbind, opportunityId={},unbindResult={}", opportunityId, unbindResult); return unbindResult; } ); }
圖片
在easyRule引入商機(jī)流轉(zhuǎn)業(yè)務(wù)過(guò)程中,從調(diào)研到選型再到最終落地,遇到了各種大大小小的問(wèn)題,但最終的效果還是比較明顯的,對(duì)團(tuán)隊(duì)的整體效率提升非常明顯,這里有幾點(diǎn)總結(jié)與建議與大家分享。
楊迎,轉(zhuǎn)轉(zhuǎn)商業(yè)后端開(kāi)發(fā)工程師,目前負(fù)責(zé)商業(yè)B端相關(guān)業(yè)務(wù)系統(tǒng)開(kāi)發(fā)(商機(jī)線索、客戶運(yùn)營(yíng)、銷售運(yùn)營(yíng)管理、廣告發(fā)布等)。
本文鏈接:http://www.www897cc.com/showinfo-26-16530-0.html規(guī)則引擎與商業(yè)CRM的完美邂逅:將智能決策融入商業(yè)擴(kuò)展
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com
上一篇: 在Lombok的加持下,“小狗”.Equals(“老狗”) = True
下一篇: 聽(tīng)說(shuō)你會(huì)架構(gòu)設(shè)計(jì)?來(lái),弄一個(gè)微信群聊系統(tǒng)