应用办公生活信息教育商业
投稿投诉
商业财经
汽车智能
教育国际
房产环球
信息数码
热点科技
生活手机
晨报新闻
办公软件
科学动态
应用生物
体育时事

决策引擎的迭代历史

  在消费金融业务场景中,对用户的风控决策,会持续影响整个借贷流程。一个合理的授信额度,可以提高用户的下单率;一个准确的逾期风险评级,可以减轻贷后的催告压力,也能有效降低用户逾期率。
  决策引擎作为风控场景中的运算中心,能够接收用户的一系列特征数据,经过诸如模型分析、规则决策等一系列复杂的运算之后,综合输出授信结果、授信额度以及风控评级等决策信息,为风控业务提供支持。
  让我们假设一个简单的,只输出授信结果的决策流程:if(用户处于白名单)return授信通过if(用户疑似学生)return授信拒绝if(用户模型分A处于〔0,0。2〕用户模型分B处于〔0,0。5))return授信通过elsereturn授信拒绝
  在这个流程中,会使用用户唯一ID如手机号,来判断其是否处于白名单;接收用户录入的年龄、联系地址、职业等信息,判断其是否为学生;同时使用身份证信息、人像信息等入模型,计算得到模型分,通过阈值判断做出授信通过或者授信拒绝的决策,再将其返回给业务以继续后续的业务处理:
  如果授信通过,短信召回并对用户开放下单入口;如果授信拒绝,做信息通知,同时关闭下单入口。
  基于此,决策时间的长短,也会一定程度上影响用户的留存率,试想如果一个决策执行了24小时,可能我们的用户早就在长时间的等待下流失,选择了别家下单。
  因此,为了使风控决策能准确而快速的达成,这几年,我司的决策引擎持续迭代,经历了规则集、drools和自研风控引擎三个阶段,而本文会对这三个阶段逐一进行介绍,并对自研风控引擎进行重点演示。第一代:规则集模式
  我们依然以上文中提到的决策流程举例,对每一个if条件进行分析:用户处于白名单,其输出为是或者否,因此可以将其定义为一个输出类型为Boolean的规则用户疑似学生,其输出为是或者否,但是它不再是一个单一条件,反而是一系列逻辑的整合,包括但不限于:用户的年龄23用户的联系地址中包含学校、学院、中专、大专、大学之一用户的职业为学生因其入参多样,故有不同的实现方式:一是将其整合为一个规则,规则内容为上述三个判断逻辑取或,输出Boolean类型的结果;二是上述三条判断逻辑各自作为一条规则,用户疑似学生成为一个规则的集合,集合里的每个规则顺序执行,规则之间是或的关系,一旦存在一条规则为true,则规则集也输出true。用户模型分A处于〔0,0。2〕的处理相对复杂,它可以被单独定义为一个规则,输出结果为Boolean;也可以将用户模型分A结果定义为一个规则,这个规则输出结果为Double类型的分数,此时判断语句会被进一步翻译为:规则结果操作符(between)比较值(〔0,0。2〕)。对用户模型分B的处理,也是一样。
  初步分析已经完成,再重新来看后两个条件,是否能寻求一种方式来实现整体逻辑的统一。
  考虑到用户疑似学生这个判定条件,后续还可能增加新的判断标准,那么把它设计为规则集无疑是更优的处理,这样当新的标准增加时,只需要新增规则放入规则集即可,每个规则都有自己的单一职责,原来的规则也不会被影响。
  再看用户模型分A处于〔0,0。2〕,将其作为一个单独的规则来设计,直观来看是最合理的,输出类型也与前两个条件一致,是Boolean。但是现在考虑这样一种情况,决策流程试运行一段时间之后,分析发现模型分A处于〔0。18,0。2〕范围内的用户逾期率整体更高一些,这时需要把阈值从〔0,0。2〕改到〔0,0。18),就需要对规则进行重新修改和发布,如果需要频繁修改阈值,就需要频繁修改规则,不稳定的规则反而会增加系统运行的风险。这样的话,选择让用户模型分A结果成为一个规则,那么修改发生时,只需要更新比较值,看起来更加满足需求。
  因此,上文的决策流程现在就变成:if(〔规则:用户处于白名单〕)return授信通过if(〔规则集:用户疑似学生〕)return授信拒绝if(〔规则:用户模型分A结果〕处于〔0,0。2〕〔规则:用户模型分B结果〕处于〔0,0。5))return授信通过elsereturn授信拒绝
  此时,由于流程中既出现规则集类型又出现规则类型,开发环节要做的兼容变多了,考虑到规则集与规则是完美的包含关系,所以为了简化配置,我们最终将规则全部都包装一层,变成规则集,来完成配置的统一。
  至此,第一版规则集方式的决策引擎,就达成了以下几条共识:参与比较的单元是规则集规则集的输出类型为Boolean或者Double规则集可以指定运行策略
  在风控部门成立之初,其实是没有严格划分风控开发部和风控策略部的,研发也会参与进策略运营中,此时的业务量比较小,场景简单,需要的决策条件也相对比较简单。因此,直接对这些规则进行代码编写无疑是成本最低的方案。同时,为了支持条件阈值随时可修改,执行流程可以在后台页面中动态配置,这些配置信息被存放进数据库,使用时再做解析。
  对于上文示例流程,经过第一步规则的硬编码,最终会定义6个规则,这6个规则分组后,形成4组规则集:
  而流程配置则直接使用Json,由用户通过前端页面编写完成:{states:〔{name:WHITELIST,actions:〔{conditions:〔{ruleSetId:1,operator:EQ,value:true}〕,type:ACCEPT,data:{credits:1000}},{conditions:〔〕,type:CONTINUE,next:STUDENTREJECT}〕},{name:STUDENTREJECT,actions:〔{conditions:〔{ruleSetId:2,operator:EQ,value:true}〕,type:REJECT,data:{credits:0}},{conditions:〔〕,type:CONTINUE,next:MODELSCORE}〕},{name:MODELSCORE,actions:〔{conditions:〔{ruleSetId:3,operator:GE,value:0},{ruleSetId:3,operator:LE,value:0。2},{ruleSetId:4,operator:GE,value:0},{ruleSetId:4,operator:LT,value:0。5}〕,type:ACCEPT,data:{credits:3000}},{conditions:〔〕,type:REJECT,data:{credits:0}}〕}〕}
  在这个用户流程中,每个action包含多个condition,condition是最小单位的条件,多个condition之间做且()运算,每个condition由规则集的ID、操作符和比较值三个部分组成,用户处于白名单这行伪代码最终被翻译为:{ruleSetId:1,operator:EQ,value:true}
  在配置中,若action运算结束,结果为true,此action中配置的type会成为当前state的结果;若结果为false,会继续运行下一个action,直到action命中。而type则分为终态类型与非终态类型:
  type
  类型
  操作
  含义
  ACCEPT
  终态
  中断流程
  授信通过
  REJECT
  终态
  中断流程
  授信拒绝
  CONTINUE
  非终态
  流转到下一个state
  下一执行节点为next对应的state
  当然,type只能确定对用户授信通过或者拒绝,如果授信通过,应该给用户授信多少金额是由data决定的。每一个终态节点都应该输出必要的决策数据,例如白名单通过的用户,统一授信1000元的额度,模型分匹配的用户授信3000元额度,而被授信拒绝的用户,授信金额显然为0。
  这样的设计,在业务发展的初期已经基本满足需求,但是这样的流程也存在显而易见的问题:如果需要增加新的规则,需要开发人员先进行编码,代码上线到生产之后,策略人员才可以配置决策流程,上线周期较长。流程中使用了ruleSetId参与配置,在流程配置阶段,无法直观感知ruleSetId对应的规则集的含义。示例中,当有两个模型分的筛选条件时,conditions中就需要包含4组condition了,可以预见,若条件配置变得复杂,condition的配置数量可能会爆炸增长。直接进行json配置的方式,缺少一定的校验,需要人为保证json配置的正确性,比如:路径需要是闭合的,不能出现每一个action都无法命中的情况终态的情况下,data需要正确配置非终态的情况下,next需要正确配置ruleSet的输出类型需要和比较值的类型保持一致
  这些问题,在初期的业务场景下,都是可以容忍的,但是随着业务规模的发展壮大,慢慢就会成为痛点。第二代:Drools配置
  随着业务场景的增多,最先令人难以忍受的问题出现了:condition的配置数量爆炸增长,可读性变差,多分支跳转配置易出错。依然以上文提到的例子为例,当走到了模型分的判断逻辑时,如果对模型分A和模型分B更加精细化的划分:
  对应的json配置会变成{name:MODELSCORE,actions:〔{conditions:〔{ruleSetId:3,operator:GE,value:0},{ruleSetId:3,operator:LT,value:0。2},{ruleSetId:4,operator:GE,value:0},{ruleSetId:4,operator:LT,value:0。5}〕,type:ACCEPT,data:{credits:10000}},{conditions:〔。。。忽略4个条件〕,type:ACCEPT,data:{credits:8000}},{conditions:〔。。。忽略4个条件〕,type:ACCEPT,data:{credits:6000}},{conditions:〔。。。忽略4个条件〕,type:ACCEPT,data:{credits:5500}},{conditions:〔。。。忽略4个条件〕,type:ACCEPT,data:{credits:3000}},{conditions:〔〕,type:REJECT,data:{credits:0}}〕}
  可以看到,这种配置非常的繁琐,重复度很高,在我们生产的实际应用中,甚至有配置近千行json的决策,可读性很差,修改发生时,配置出错的风险大大增加。在这种背景下,Drools被引入,期望能完成系统配置的升级。
  Drools的基本语法为:rule规则名when条件规则的LHS(lefthandside)then动作结果规则的RHS(righthandside)end
  对上面的模型分配置逻辑,我们切换成Drools配置,会变成:importcom。yqg。risk。core。drools。Data;importjava。lang。Math;ruleModelRulewhend:Data();thendoublemodelScoreAd。scoreRuleSet。get(3);从规则集的结果中获得模型分AdoublemodelScoreBd。scoreRuleSet。get(4);从规则集的结果中获得模型分B评级if(modelScoreA0modelScoreA0。2modelScoreB0modelScoreB0。5){d。decisionACCEPT;d。credit10000;}elseif(modelScoreA0。2modelScoreA0。5modelScoreB0modelScoreB0。5){d。decisionACCEPT;d。credit8000;}elseif(modelScoreA0。5modelScoreA0。75modelScoreB0modelScoreB0。5){d。decisionACCEPT;d。credit6000;}elseif(modelScoreA0modelScoreA0。2modelScoreB0。5modelScoreB1){d。decisionACCEPT;d。credit5500;}elseif(modelScoreA0。2modelScoreA0。5modelScoreB0。5modelScoreB1){d。decisionACCEPT;d。credit3000;}else{d。decisionREJECT;d。credit0;}end
  其中Data类为预先定义好的Java类,Drools通过读取Data类的scoreRuleSet获取模型分,经过一系列的计算逻辑之后,对decision和credit完成赋值。
  可以看到,相对于长Json的配置方式,Drools脚本的编写,可读性更好,灵活度也很高。直接书写代码的方式,不但可以同时进行多个变量之间的比较运算,还可以进行算术运算,决策方式更加丰富,也解决了配置复杂的问题。Drools的使用,在很长一段时间内缓解了策略人员的配置压力。
  不过相应的,Drools代码的书写,对于不熟悉代码的策略人员来说,会有一定的使用门槛,并且依然没有解决规则集方式下的其他问题,最终只成为一个过渡方案。第三代:自研风控引擎
  近一两年,规则集和Drools方式的混合使用,已经无法满足我们的需求。
  一方面,业务高速发展,数据源、特征和模型数量快速增长,出于系统监控、资源利用、问题分析等多方面的考虑,整个风控系统有微服务化拆分的要求;另一方面,风控部门也完全拆分为开发和策略两个团队,对于部分策略同学来说,直接编写Json或者Drools代码的成本很高;除此之外,快速的策略迭代需要,也无法容忍之前规则开发测试发布配置修改的长发布流程,尤其当规则上线出现问题时,只能通过发布回滚解决问题,为策略上线增加了更多的不稳定性。
  为了解决这些问题,一个新的决策引擎系统,自然被提上开发日程,此系统在设计之初制定了如下目标:服务化。除了支持Boolean和Double的输出用以兼容老系统逻辑,还需要支持更多的输出类型。支持灵活的策略配置,取消规则硬编码。使用界面化配置方式,减少甚至避免策略人员的代码编写。能支持规则、规则集、决策表等多种决策方式。一、变量定义
  决策引擎的核心是组件,组件可以认为是对一个表达式或者多种复合的配置条件的封装,而变量作为表达式的构成要素之一,会在运行时根据用户数据绑定不同的变量值完成表达式的计算,同时,此计算结果也会直接赋值给组件预定义的输出变量,实现数据的存储。
  在此系统中,变量分为全局变量和特征变量两类,其数据类型有四种:整数、小数、字符串和布尔:
  全局变量,标为var,运行时变量值可以被修改,作为组件的入参或者出参使用,在组件中实现数据的传递。例如,一个决策流中,前后配置了两个节点A、B,A节点配置输出全局变量var。score,B节点输入依赖var。score,那么运行时,A输出的var。score可以直接被B使用。
  特征变量,标为feature,运行时变量一旦被赋值,后续无法再被修改。特征值的初始化,是在运行时与特征引擎交互后获得的,在组件的运行过程中,该特征变量可读,但是不再支持修改。二、组件分类
  组件是决策引擎系统最重要的组成部分,丰富的组件类型是支撑复杂业务场景的基础,目前启用的组件包括规则、规则集、决策表、打分卡、模型、函数、决策流七种。
  1。规则
  规则由表达式构成,一个规则即一个表达式。我们将表达式定义为Expression,其结构体为IValueop(operator)IValue,其中IValue为抽象单元,有三种实现:Parameter(参数,即全局变量或者特征变量,如feature。userage)ExpressionRealValue(数据值,如自然数、布尔、字符串等)
  因此Expression可以使用以上实现类进行组合,灵活配置用户所需的表达式,如ParameteropRealValue(如feature。userage18)ExpressionopExpression(如(feature。userage18)(feature。userjob‘学生’)ParameteropParameter(如feature。score1feature。score2)RealValueopRealValue(如2018)
  目前,决策引擎对用户只开放了前两种表达式方式配置入口。
  2。规则集
  规则集是一系列规则的集合,配有确定的执行策略。
  受不同的策略影响,规则呈现不同的执行方式,例如,当配置了执行策略为命中即中断,规则会顺序执行,如果遇到第一个命中的规则,就中断当前规则集的执行,当前规则的输出也会成为规则集的最终输出。{rules:〔〕,arraystrategy:执行策略}
  3。决策表
  分为一维决策表和二维决策表两类:一维决策表
  对单一的输入变量进行表达式判定,表达式命中之后,输出该表达式对应的结果。
  二维决策表
  即交叉决策表,输入X和Y两个维度的变量,并在两个维度上分别设置X和Y的取值范围,交叉得到最终的输出。
  4。打分卡
  决策组件之一,支持多个变量作为输入,每个变量可以配置不同的阈值条件,形成分箱。通过条件分箱与得分汇总,辅以权重,输出最终得分。
  以上图中的打分卡为例,输入变量为:feature。income和var。age,假设对于某个用户
  feature。income15000,命中分箱3,得出第一个得分score1301。442
  var。age45,命中分箱2,得到第二个得分score2100。88
  则该用户最终得分50
  5。模型
  直接对接模型服务,配置其支持的模型ID,在决策时直接调用模型服务拿到输出结果。
  6。函数
  在此系统中,由于一期暂未能支持更复杂的表达式配置(如ParameteropParameter),故保留了允许用户自定义脚本的功能,新增函数组件,作为第二代与第三代之间的过渡组件。
  函数组件允许用户使用Groovy自定义函数组件,所有的函数组件均使用main(arg)作为入口函数,除此之外,用户需要选择该函数的入参变量(全局变量特征)来完成函数的赋值,选择函数的出参变量(仅全局变量)完成函数的输出值承接。
  假如用户配置了如下函数,并且选择一个入参变量feature。loanuserproducts,来完成运行时的数据绑定:intmain(intproducts){for(intp:〔8388608,268435456〕){if((productsp)!0){productsproductsp;}}if(products0){return8;}returnproducts;}
  在函数组件执行时,会在上述代码的基础上,补充函数入口的调用:main(feature。loanuserproducts),最终将完善后的脚本,转换为CompiledScript类,通过CompiledScript的eval方法,拿到执行结果。
  核心代码为:publicMethodResultvisitMethod(StringscriptText,ListFuncArgmethodRealArgs,Inputinput){将〔加工后的脚本〕编译成CompiledScriptCompiledScriptscriptloadScript(scriptText);实参与形参绑定BindingsbindingnewSimpleBindings();for(FuncArgarg:methodRealArgs){fillScriptBindings(入参值,Bindings对象,feature。loanuserproducts,入参是否允许为空)fillScriptBindings(input,binding,arg。getArgName(),arg。getNullable());}ScriptContextscriptContextnewSimpleScriptContext();scriptContext。setBindings(binding,ScriptContext。GLOBALSCOPE);PrintInfoCollectorcollectornewPrintInfoCollector();scriptContext。setWriter(collector);执行Objectoscript。eval(scriptContext);收集printinfo并作为log返回StringlogCollectionUtils。isEmpty(collector。logs)?null:StringUtils。join(collector。logs,);returnnewMethodResult()。setRawResult(o)。setLog(log);}
  7。决策流
  决策流是一种特殊的组件,它是组件类型之一,却可以使用任意的组件来完成配置,最终形成一个由多种节点组成,按照先后或者分支顺序连接起来的图。
  节点的分类:起始节点入度为0,出度为1。为每一个决策流的入口节点。组件节点入度与出度均为1。允许配置除当前组件之外的其他组件。节点的运行逻辑,实际为节点中组件的运行逻辑;节点中组件的输出即为节点的输出。决策流的输入、前置节点的输出,均可以被当前节点所使用。如果决策流的输入或者前置节点的输出,与当前节点的输出重名,当前节点的输出会将之前的数据覆盖(空跑除外)可以设置中断、空跑等附加属性中断:当中断打开,并且组件存在输出,当前节点直接中断当前流以及上层流(如有)的执行空跑:当空跑打开,当前组件的输出不会覆盖组件输入值或者前置节点的输出值,当前节点的输出也不会被后置节点所见所使用。分支节点入度为1,出度为n,根据不同的条件,指向不同的节点。分为条件分支和ABTEST两种条件分支不同的路径上会设置不同的表达式,表达式的配置方式,与规则相同,使用IValueopIValue的方式配置ExpressionABTEST不同的路径会设置分流比例,所有的分流比例加和为100。分流的计算方式,是对当前节点选定变量的运行时数据进行hash并将其映射落在01的范围内。赋值节点入度为1,出度为1。对特定的变量进行赋值,赋值来源为用户自定义或者从特征中读取。赋值后的变量值作为当前节点的输出,会覆盖决策流的同名输入或者前置节点的同名输出。终止节点入度为1,出度为0。为每一个决策流的终止节点,每个决策流只有一个终止节点。
  回到最初的决策举例上,用决策流的方式,最终会被配置为:
  其中,红色节点被配置为中断打开,若白名单命中或者学生禁入的规则集命中时,会直接中断并退出当前流程执行。三、决策流执行流程
  自研的决策引擎被设计为一个单独的运算子系统,对外暴露组件的基础信息,包括组件的ID、版本、组件依赖的入参、组件最终的出参列表;同时接收业务侧指定组件ID和版本的执行请求,异步完成组件执行,并回调业务调用方。
  在决策引擎中,不会存储用户信息,也不会查询用户相关的信息,这部分的工作由协作系统特征引擎来完成。决策引擎中每个组件的运算单元由基础表达式构成,表达式依赖的特征,在运算时与特征引擎实时交互;同时,部分组件依赖模型执行,也会在运行时与模型服务实时交互。
  因此决策引擎的系统间调用流程关系大致如下:
  业务系统向决策引擎系统提交一笔执行请求,这笔请求在决策引擎落库后,会被记作一条trace记录,traceId会被实时返回给业务系统,业务系统后续可以通过traceId异步查询trace执行结果,并根据trace结果进行不同的业务逻辑处理。
  trace状态分为以下几种:INIT(I),落库后的初始化状态,可执行状态RUNWAITING(W),特征值已完成收集,可执行状态RUNNING(R),正在执行中SUCCEED(S),执行成功,终态FAILED(F),执行失败,终态BLOCKED(B),等待特征值完成收集EXCEPTION(X),执行异常,需要人工介入CANCELED(C)取消,无需执行,终态
  trace的调度流程主要分两部分,trace获取与trace执行,前者负责沟通数据库,取出当前待执行trace清单;后者针对每一个待处理的trace完成执行并生成运行结果。trace获取按照trace的创建时间排序,批量获取状态为INIT或者RUNWAITING的trace,并将trace的状态标记为RUNNING后,提交给TraceExecutor;如果没有符合条件的trace,数据库轮询休眠1s。trace执行以一条trace的执行为例,首先根据trace上的组件信息,按组件ID和版本从组件工厂中拿到唯一的组件,然后对组件传入必要的全局变量参数,执行组件自身的execute方法,输出执行结果并修改数据库的trace状态。
  决策流阶段分析决策流的节点类型之一为分支节点,分支节点代表出现了两条及以上的互斥路径,在实际执行时只会执行其中一条,因此在分支节点跑出结果之前,考虑到特征的获取时间、特征采集的资费问题、额外的特征采集可能对用户造成的影响(例如人行信息的采集会增加征信查询次数),后置的特征获取不可提前进行,只有当分支节点确定了后续执行路径,才能进行后置节点的特征获取。类似的,如果组件节点标记了中断,中断节点之后的节点是否真正需要执行,是取决于中断节点的输出情况的。所以在这两种情况下,当决策流每遇到中断或者条件分支,自然就会形成一个阶段,当前阶段执行结束后,再确定下一阶段的节点组成。阶段特征获取完成判断阶段确定之后,当前阶段包含的节点、节点依赖的特征与全局变量就可以确定下来,若当前阶段需要的特征缺失特征值,就需要先行准备特征数据。阶段性地、批量地执行特征值获取,可以有效减少和特征引擎的网络IO次数,也减少由于特征缺失引发的执行中断的次数,加快决策流的整体执行。特征值获取与trace暂存与特征引擎进行交互,如果可以实时获取到特征值,则组件继续执行;如果特征引擎实时接口返回正在处理中,当前trace执行会被中断,trace被标记成BLOCKED状态写回数据库,直到收到特征引擎处理完成的回调,并修改trace状态为RUNWAITING,等待下一轮trace获取。组件执行当阶段需要的特征值准备好之后,组件按照节点顺序开始执行。节点执行前,先检查当前节点的全局变量和特征数据是否都存在,如果所需的全局变量无法从当前流的入参中获得,也无法从前置节点的输出中获得,并且设置了不允许为空,当前流会执行中断,最终当前trace会被标记为执行失败;如果所需的特征设置了不允许为空,但是特征引擎返回的特征值为空,同样的,也会执行失败并中断流的执行。当前阶段顺利执行完成之后,并不会立刻进行下一阶段的特征获取,而是继续尝试执行接下来的节点,直到遇到一个缺失特征值的节点,再从缺失特征值的节点开始,进行下一阶段的特征获取。这样做的原因是,特征是全局不可修改的,前置节点获得的特征,如果足以满足后置节点的特征需求,那么无需进行更多的中断,就可以顺利执行到结束。如果节点是组件节点,当前执行就交给对应的组件类执行它自身的execute方法,其中,模型组件实时调用模型服务拿到用户的模型分,而其他组件都是本地执行。四、系统问题
  自研决策引擎系统在22年8月开始正式切全量,迄今已运行约半年时间。在这一段时间内,新系统也逐渐暴露出一些的问题。
  1。冗余组件配置问题
  在策略人员使用过程中,为了简化配置流程,通常会抽出一些通用的组件形成一个单独的决策流,比如把所有首贷依赖的模型组件全部配置为一个小的决策流,这样,当其他组件需要使用某一个首贷模型分时,只需要引用这个子决策流即可。
  如果存在两个决策流,各自都需要首贷模型分来做决策,其可以配置为:
  这样配置的优点是,使用者可以将注意力更加倾斜给后面的决策组件配置,当决策组件需要使用模型分时,直接在前置节点引入包含所有模型组件的一个公共决策流即可。如果需要新增一个模型,也只需要在首贷依赖的模型中直接新增,所有上层决策流(决策流A和B)都无需做出修改。
  但是缺点也很明显,执行决策流A时,由于决策表只依赖模型分A和B,其实只需要前置执行模型A和模型B就可以满足需求,但是现在完整执行了首贷依赖的模型这个决策流,那剩下的模型CE都是额外多执行的组件。这种情况下,不止浪费了执行资源,同时也增加了整体的执行耗时。
  显然,如果想要解决这个问题,就需要对用户配置的决策流进行自动简化,让决策流只执行其必须执行的组件。
  还是以决策流A为例,原本使用的首贷依赖的模型,如果在执行时,先进行后置节点分析,得到首贷依赖的模型的必要输出:模型分A与模型分B,进而删除多余的35号节点,形成首贷依赖的模型(副本A),并按副本A的结构来执行,那问题就迎刃而解。
  理论如此,但是实际上,由于gateway节点的存在、决策流的多层嵌套等问题,如何能在运行时快速并准确的完成分析,目前还没有寻求到合适的算法来解决,这也是我们目前的一大难题。
  2。组件配置异常
  组件可以划分为复杂组件和简单组件两类,复杂组件(决策流、规则集)在配置时支持使用其他组件;剩余的其他组件不具备此功能,全部为简单组件。当简单组件配置时,组件表达式中的变量的集合,就自然成为当前组件的入参;当组件为复杂组件时,入参由子组件入参和出参综合计算得来:规则集的入参等于所有规则的入参的集合。决策流的入参若某一节点的入参,无法从前置节点的输出中获得,则此入参会成为决策流的入参。
  还是以上述提到的决策流A举例,其输入输出定义如下:
  节点
  输入
  输出
  1规则:学生一刀切
  feature。age
  var。decision
  2决策流:首贷依赖的模型
  var。modelScoreA、var。modelScoreB、var。modelScoreC、var。modelScoreD、var。modelScoreE
  3决策表:使用模型分AB
  var。modelScoreA、var。modelScoreB
  var。decision、var。credits
  可以看到,节点3的入参var。modelScoreA和var。modelScoreB,都可以在节点2的输出中获得,因此决策流A的入参只有feature。age。
  节点的增删,都会引发决策流的入参变化,比如删除节点2,那决策流A的输入就会变成feature。age、var。modelScoreA、var。modelScoreB三个。很显然,对于风控业务侧而言,在提交trace准备执行决策流A时,如果决策流A发生了这样的修改,业务侧是无法上送两个模型分作为入参的,这时候决策流A就会执行失败。
  除此之外,执行时还可能会有一些其他的问题,比如组件预先设置了特征为不允许为空,但是实际运行过程中从特征平台拿到的特征值却为空,这时执行也会出现异常,导致trace执行失败。
  这些运行时问题,往往在生产配置生效后才会被发现,在新系统启用的前几个月时间内,当策略更新后,经常会出现由于配置异常导致的执行失败,这时候我们的解决方案只能是通过组件的回滚功能,一键回滚到上一可用版本,但是这需要人工来操作;这些错误版本的trace也会被卡住,一直等到新版本上线后,再等待人工介入重新提交。
  为了使上面这种组件配置异常问题减少发生,我们在组件配置流程里增加了多种测试方式供策略配置人员提前测试以发现问题,但是这并不能解决根本问题。
  最终,我们上线了空跑功能。
  空跑,又叫陪跑,在决策流版本升级之后、生效之前,会生成一个空跑版本,对这个版本,我们会提交一批trace预先试跑一遍,如果一定数量下,trace都正常执行结束,则当前版本可以从空跑版本正式变更为决策版本;否则当前版本无法生效,直到策略人员分析完失败原因后修改并重新提交。
  空跑版本无法对决策可见,当一笔决策trace执行结束之后,若空跑版本存在,会使用这笔trace的用户信息,发起空跑trace的提交,提交空跑trace的数量取决于当前有多少空跑版本存在。
  举例说明一下空跑流程,假设有这样一个组件A,第一次修改后生成的空跑版本记作V1,第二次记作V2,第三次V3,这三个版本都在空跑中未生效。
  如果每一笔决策trace,都发起3笔空跑trace对应V1、V2、V3,虽然空跑trace的执行优先级为低优,理论上不会导致决策trace的处理延迟,但还是会产生资源的浪费,空跑版本越多越严重;同时,考虑到V3版本是基于V2版本修改而来的,V2同样基于V1,如果V3空跑成功的话,V2和V1作为过时的版本也就没有空跑的必要,因此,集中资源优先去跑V3,让更晚提交的版本更早空跑成功上线,是更优的执行方案。但是V2和V1的空跑频率只是降低,而不是完全暂停,这样可以做一个策略兜底:如果V3不幸空跑失败了,V2还有更高的空跑条数起点,能尽快跑完空跑条数,实现上线。
  最终我们限制,当空跑版本存在时,每一笔决策trace会发生12条空跑:
  最新的空跑版本(本例中是V3)在空跑失败之前,会固定发生一条空跑;最新之下的所有空跑版本整体共享100的比例,以哈希结果决定另外一条空跑时发生在哪个版本下。
  空跑上线之后,由于组件配置异常导致的线上决策结果延迟的问题已不再出现,配置问题的发现发生在测试和空跑阶段,增强了新策略上线的稳定性。最后
  三代决策引擎的落地,都是阶段发展的需要:业务发展初期,规则集这种硬编码方式实现简单但是已经足够满足需求;随着业务规模的扩大,Drools的引入支持了更加复杂的决策场景;在业务成熟阶段,开发与策略进行了更好的职责分配,决策工具的建设就成为了更高的要求,自研风控引擎系统成为新的方案被落地。
  技术无法与业务切割,为了更好的支持业务,决策引擎也会随之成长,我们也期望其最终成为一个更加智能高效的平台。
  作者:骆英云
  来源:微信公众号:洋钱罐技术团队
  出处:https:mp。weixin。qq。comsqjg7OOCCrLvqc2v8DRbelQ

奥迪启动零使命计划在奥迪的自然栖息地提高人们对全球物种灭绝的联合国宣布这十年为联合国生物多样性十年,以提高对全球物种灭绝的认识,并促进采取措施制止这一现象。奥迪正在为这一努力做出贡献,并正在所有地点实施生物多样性项目。作为好公司生物多样……喝酒必懂的一些小知识中国是礼仪之邦,自古以来就有以酒宴客的习俗,无论婚嫁、祝寿、酬谢、乔新居、宴宾客、还是洗尘接风、饯行送别,处处都有酒的身影。生活中不止会喝酒,更要懂酒!……沃尔沃宣布了在线购车和预订服务的非接触式计划网上购车或预订服务与3M合作,为经销商和示范车消毒汽车沃尔沃汽车印度推出了一个非接触式的购买汽车和在线预订服务项目。这一新的数字举措使沃尔沃车主能够在网上预订他们的……2020尼桑前线提供了可观的燃油经济性收益与新的V6发动机2020日产前沿燃料经济在这里。感谢Motor1的一份报告,我们与日产确认,我们知道前沿是多么有效与其新的3。8升V6和九速自动传输。日产今年在芝加哥车展上宣布了这款新引擎。在……离婚需要什么(一份完整的离婚协议书)离婚协议书男方:民族:出生年月:住址:身份证号码:女方:民族:出生年月:住址:身份证号码:男方与女方于年月日认识,于年月日在省市区登记结婚,婚后于年月日生育一……字解半年经济物价稳稳住百姓菜篮子央视网消息:粮食安全有了保障,中国经济的稳就有了坚实的基础。接下来我们再来看稳字的另外一部分心。俗话说:人心齐,泰山移,要想稳住人心,首先就得稳住老百姓的吃穿住用行这些关键小事……VAR消点有违操作规范?申花哑巴吃黄连1、2、3,申花!全队围在了一起,紧紧拥抱着彼此,这一通常在赛前上演的画面第一次在比赛结束后出现了。申花更像是胜者,在一场以九人残阵逼平对手的比赛中能够昂首离开。杨旭赛后说:我……糯米粉可以做什么甜品(糯米粉什么牌子做甜品好吃)今天来做一款个人特别喜欢的美食,它拥有一流的颜值,吃起来香糯可口,尤其是柔软嫩滑的外表,带着毛茸茸的质感,怎么看怎么喜欢。它就是我们常说的糯米滋,确实是一款居家必备的小点心。……血压高怎么调理(高血压不能吃哪些食物)在生活中高血压患者是需要严格控制饮食的,因为大部分时候盐分摄入就与高血压有关系,但不仅仅是盐,目前生活中的各种食物都有可能会影响到高血压患者。最高血压患者有必要根据食物的烹饪以……宝马发布罕见的11。5万英镑X7DarkShadowEdit这是一辆大型的V8SUV,由宝马车队的人们制造。它的正式名称是BMWX7ldquo;DarkShadowEditionrdquo;,据宝马汽车公司的知情人士称,这是大型V8SU……这是一款近千马力的奥迪RS6还记得德国的调谐器Wheelsandmore及其1,036bhp的AudiR8V10PlusSpyder吗?好吧,现在人们已经将相同的面部融合功能添加到了新的RS6中。W……人到中年要戒酒?建议过了45岁,牢记2不喝1不买,早懂早受益导语:人到中年要戒酒?建议过了45岁,牢记2不喝1不买,早懂早受益我国作为白酒的发源地,到现在为止,已经有五千多年的历史了。喝酒也已经成了很多人生活中常见的一件事情,尤其……
内马尔参与总统选举!巴西足协制止未果,引球迷不满或无缘世界杯欧洲球队近期整体状态比较低迷,欧国联赛场法国、英格兰等世界强队表现均比较一般,这让欧洲球队的世界杯前景并不明朗。相比之下巴西以及阿根廷两队的状态一直很火热,他们也成为今年卡塔尔……大数据指标体系为什么指标体系这么重要?要搞清楚指标体系为什么重要,很自然的想到的就是:为什么要有指标体系?要回答这个问题,我们就要回答一个更根本的问题:为什么要有指标?我们需要指……丰收中国最美画卷来源:人民网人民日报黑龙江绥化机械力量足玉米抢鲜收本报记者方圆黑土生金,沃野飘香。在黑龙江绥化青冈县祯祥镇兆林村,一台大型鲜食玉米采收机,正以每天450……休赛期老谋深算的六笔交易,篮网未雨绸缪,热火名留青史伴随着各支球队陆续发布新赛季新闻发布会与训练营时间,预示着距离新赛季也越发临近,而各支球队在休赛期的引援计划也将告一段落,自由市场作为各支球队一飞冲天的重要手段,一直深受青睐,……银行业保险业这十年河北支持京津冀协同发展三个重点领域的贷款余央广网北京9月27日消息(记者冯方)9月27日,银保监会举行银行业保险业这十年系列主题新闻发布会。河北银保监局党委书记、局长王文刚介绍,十年来,河北银保监局聚焦三大任务,全面推……改造升级完成!大同这个公园新颜值超亮眼为改善市民健身娱乐休闲环境提升市民幸福生活指数近期云冈区园林绿化中心对平旺公园的园区环境设备设施进行了全面的改造升级成为市民游园又一好去处云……熬夜多年的舌苔是什么样的,看看你是哪一种现在网络时代的发展,让很多人的作息都变得很不规律,所以来看失眠的也挺多的。下面我就整理了一些熬夜患者的舌象,我们来看一下,经常熬夜的人,舌象上会有什么样的表现。熬夜对我们……虚不受补?一补就上火?秋冬进补,一定要先清理体内这几大障碍喜欢中医吗?关注张景明教授,从零基础开始学起!一年一度的秋冬进补季又来咯,去年的秋膘还没减下去,很多人又开始为今年的秋膘煞费苦心,寻思着来点什么补汤、膏方进补一下。……2007年时装莲娜丽姿莲娜丽姿(NinaRicci)创于1932年,以服饰起家,以香水闻名于世。NinaRicci的品牌创立者是出生于意大利的NinaRicci,她是30年代巴黎最杰出的服装设计师之……在华为智慧屏Z65面前,索尼也变得索然无味,唯有海信电视E8华为智慧屏此次的命名是Vision智慧屏,Z65电竞版,也意味着这款电视是迎合Z时代年轻人的需求。作为一款液晶电视,同样也是华为智慧屏的代表作,我更愿意把华为Z65称作是一个超……为什么老是早上鼻炎发作,到中午就好了?有这3大注意事项鼻炎是出现在鼻腔部位的炎性病变,有多种类型,有的人出现慢性鼻炎,有的人属于过敏性鼻炎,在发病过程中多有打喷嚏、流鼻涕、鼻腔发痒等症状,给生活带来许多不方便。因此,要发现疾病之后……房地产政策叠加有助强信心稳预期国庆假期的前两天,房地产市场密集迎来3项调控举措。其一是9月29日,央行、银保监会决定阶段性调整差别化住房信贷政策,符合条件的城市可自主决定在2022年底前阶段性维持、下调或取……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网