A/B服务集成

在推荐场景下,用户经常需要调整召回策略、排序模型以及模型参数以测试新思路。为此,PAI-Rec开发了一款轻量级A/B测试服务,旨在最小化对现有系统的干扰,并支持快速实验。目前,该服务已提供服务器端的实验功能。

A/B服务介绍

A/B服务主要包括以下组件:

  • AB Web控制台:作为A/B服务后台管理系统,用于实验配置。数据会持久化到MySQL里。

  • AB Server:提供HTTP API服务,并部署在PAI-EAS中。该服务从MySQL中读取数据,要求EAS能够直接访问MySQL数据库,确保网络连通性。详情请参见配置网络连通

  • AB SDK:需集成到服务端程序中,支持实验配置与流量分配策略。通过SDK可实现请求分流及实验匹配,并依据返回结果采取进一步行动。当前版本支持Go、Python和Java语言。

image

集成A/B服务实验功能

操作原理

在召回运行时,首先检查是否存在相关的实验参数,如果存在,根据已有的召回实例反射调用 CloneWithConfig方法,并传入实验参数,生成新的召回实例。新生成的召回实例将被注册到系统中。后续调用时,系统将直接返回已注册的实例,避免重复创建。

操作步骤

  1. 设置环境

    环境值可设为dailyprepubproduct,设置方法有两种:

    • config.json中配置RunMode

    • 设置环境变量PAIREC_ENVIRONMENT,其优先级高于config.json中的设置。

  2. 配置实验参数

    PAI-Rec预先定义了一些实验参数,设置这些参数时必须严格遵守命名规则,否则即使匹配到实验也无法找到相应参数。

    参数名称

    类型

    说明

    示例

    类目+".RecallNames"

    json array

    召回的列表,需要包含所有的召回。

    "default.RecallNames":[ "HomepageEtrecRecall"**, **"HomepageDssmRecall"]

    "recall."+具体的recall name

    json object

    根据recall config,创建新的recall。

    {"recall.MyRecall":{"version":"v2"}}

    filterNames

    json array

    过滤列表,包含所有的过滤流程。

    {"filterNames":["UniqueFilter", "UserExposureFilter"]}

    rankconf

    recconf.RankConfig

    排序算法的配置。

    "rankconf":{"RankAlgoList":["pai_homepage_fm"],"RankScore":"${pai_homepage_fm}"}

    features.scene.name

    string

    Features load对应的场景名称。

    "homepage"

    user_features.scene.name

    string

    User Features预期对应的场景名称。详情请参见User特征预取

    "Home_feed"

    类目+".SortNames"

    json array

    排序模块的列表,需要包含所有排序的模块名称。

    "default.SortNames": [

    "RetargetDistinctSort",

    "RetargetSort",

    "TagWeightSort",

    "PositionReviseSort",

    "DiversitySortHead" ]

    "sort."+具体的sort name

    json object

    根据sort config创建新的sort。

    {

    "sort.RetargetSortV": {

    "Debug": false,

    "BoostScoreConditions": [

    {

    "Conditions": [

    {

    "Name": "recall_name",

    "Domain": "item",

    "Type": "string",

    "Value": "retarget_u2i",

    "Operator": "equal"

    }

    ],

    "Expression": "score * 1.0"

    }

    ]

    }

    }

    generalRankConf

    recconf.GeneralRankConfig

    粗排的配置,包括user feature的获取、算法配置RankConf。具体操作,请参见粗排配置

    {"generalRankConf":{"FeatureLoadConfs":[{"FeatureDaoConf":{}}],"RankConf":{},"ActionConfs":[]}}

    coldStartGeneralRankConf

    recconf.ColdStartGeneralRankConfig

    冷启动粗排配置。具体操作,请参见粗排配置

    {"coldStartGeneralRankConf":{"FeatureLoadConfs":[{"FeatureDaoConf":{}}],"RankConf":{},"ActionConfs":[]}}

    coldStartRankConf

    recconf.ColdStartRankConfig

    冷启动召回,rank阶段配置,指定rank算法。

    {"coldStartRankConf":{"RecallName":"ColdStartRecall", "AlgoName":"linucb"}}

  3. 匹配实验

    每次请求均需匹配实验,并构建上下文。示例代码如下:

    	func (c *HomeFeedController) makeRecommendContext() {
    	c.context = context.NewRecommendContext()
    	c.context.Size = c.param.Limit
    	c.context.Param = &c.param
    	c.context.RecommendId = c.RequestId
    	c.context.Config = recconf.Config
    	c.context.Debug = c.param.Debug
    	abcontext := model.ExperimentContext{
    		Uid:         c.param.DistinctId,
    		RequestId:   c.RequestId,
    		FilterParams: map[string]interface{}{},
    	}
    
    	if abtest.GetExperimentClient() != nil {
    		c.context.ExperimentResult = abtest.GetExperimentClient().MatchExperiment(c.param.SceneId, &abcontext)
    		log.Info(c.context.ExperimentResult.Info())
    	}
    }
  4. 调整实验参数

    RecommendContext对象可通过context.ExperimentResult获取特定的实验参数。使用GetLayerParams获取某一层上的实验参数,支持Get、GetInt、GetFloat、GetInt64方法。第一个参数是参数名,第二个参数是默认值,在找不到指定参数时返回默认值。

    	count := r.recallCount
    	if context.ExperimentResult != nil {
    		count = context.ExperimentResult.GetLayerParams("").GetInt("recall.base.count", count)
    	}
    	fmt.Println("test count", count)
  5. 对召回做实验

    对于特定的召回做实验时,可通过不同参数动态调整recall配置。需要遵循以下规则:

    • 参数名称格式为:"recall."+已有的recall name

    • 参数配置应采用JSON映射形式。

    • 相关召回实例必须实现CloneWithConfig方法,用于基于给定参数生成新的召回实例。例如:

      type MyRecall struct {
      	version string
      }
      
      func NewMyRecall() *MyRecall {
      	r := MyRecall{version: "v1"}
      
      	return &r
      }
      func (m *MyRecall) CloneWithConfig(params map[string]interface{}) *MyRecall {
      
      	r := MyRecall{}
      	if _, ok := params["version"]; ok {
      		r.version = params["version"].(string)
      	}
      	return &r
      }

集成A/B服务参数功能

使用方式如下:

// 获取到具体的场景名称
scene := context.GetParameter("scene").(string)

// 根据场景获取参数列表,然后用具体的 Get* function 获取具体的参数值
count := abtest.GetParams(scene).GetInt("count", 100)
fmt.Println("recall count:", count)