得物新商品審核鏈路建設(shè)
一、前言
二、如何實(shí)現(xiàn)高效審核
三、動態(tài)配置實(shí)現(xiàn)思路
四、商品審核方式演進(jìn)介紹
五、現(xiàn)狀問題分析
六、流程介紹
七、詳細(xì)設(shè)計(jì)
1. 整體架構(gòu)圖
2. 業(yè)務(wù)實(shí)體
3. 機(jī)審執(zhí)行流程框架
4. 動態(tài)配置能力建設(shè)
八、關(guān)于數(shù)據(jù)分析&指標(biāo)提升
一、前言
得物近年來發(fā)展迅猛,平臺商品類目覆蓋越來越廣,商品量級越來越大。而以往得物的上新動作更多依賴于傳統(tǒng)方式,效率較低,無法滿足現(xiàn)有的上新訴求。那么如何能實(shí)現(xiàn)更加快速的上新、更加高效的上新,就成為了一個(gè)至關(guān)重要的命題。
近兩年AI大模型技術(shù)的發(fā)展,使得發(fā)布和審核逐漸向AI驅(qū)動的方式轉(zhuǎn)變成為可能。因此,我們可以探索利用算法能力和大模型能力,結(jié)合業(yè)務(wù)自身規(guī)則,構(gòu)建更加全面和精準(zhǔn)的規(guī)則審核點(diǎn),以實(shí)現(xiàn)更高效的工作流程,最終達(dá)到我們的目標(biāo)。
本文圍繞AI審核,介紹機(jī)審鏈路建設(shè)思想、規(guī)則審核點(diǎn)實(shí)現(xiàn)快速接入等核心邏輯。
二、如何實(shí)現(xiàn)高效審核
對于高效審核的理解,主要可以拆解成“高質(zhì)量”、“高效率”。目前對于“高質(zhì)量”的動作包括,基于不同的類目建設(shè)對應(yīng)的機(jī)審規(guī)則、機(jī)審能力,再通過人工抽查、問題Case分析的方式,優(yōu)化算法能力,逐步推進(jìn)“高質(zhì)量”的效果。
而“高效率”,核心又可以分成業(yè)務(wù)高效與技術(shù)高效。
業(yè)務(wù)高效
- 逐步通過機(jī)器審核能力優(yōu)化審核流程,以解決資源不足導(dǎo)致上新審核時(shí)出現(xiàn)進(jìn)展阻礙的問題。
- 通過建設(shè)機(jī)審配置業(yè)務(wù),產(chǎn)品、業(yè)務(wù)可以直觀的維護(hù)類目-機(jī)審規(guī)則-白名單配置,從而高效的調(diào)整機(jī)審策略。
技術(shù)高效
- 通過建設(shè)動態(tài)配置能力,實(shí)現(xiàn)快速接入新的機(jī)審規(guī)則、調(diào)整機(jī)審規(guī)則等,無需代碼發(fā)布,即配即生效。
Q2在搭建了動態(tài)配置能力之后,算法相關(guān)的機(jī)審規(guī)則接入效率提升了70%左右。
三、動態(tài)配置實(shí)現(xiàn)思路
建設(shè)新版機(jī)審鏈路前的調(diào)研中,我們對于老機(jī)審鏈路的規(guī)則以及新機(jī)審規(guī)則進(jìn)行了分析,發(fā)現(xiàn)算法類機(jī)審規(guī)則占比超過70%以上,而算法類的機(jī)審規(guī)則接入的流程比較固化,核心分成三步:
- 與算法同學(xué)溝通定義好接口協(xié)議
- 基于商品信息構(gòu)建請求參數(shù),通過HTTP請求算法提供的URL,從而獲取到算法結(jié)果。
- 解析算法返回的結(jié)果,與自身商品信息結(jié)合,輸出最終的機(jī)審結(jié)果。
而算法協(xié)議所需要的信息通常都可以從商品中獲取到,因此通過引入“反射機(jī)制”、“HTTP泛化調(diào)用”、“規(guī)則引擎”等能力,實(shí)現(xiàn)算法規(guī)則通過JSON配置即可實(shí)現(xiàn)算法接入。
四、商品審核方式演進(jìn)介紹
商品審核方式的演進(jìn)
人審
依賴商管、運(yùn)營,對商品上架各字段是否符合得物上新標(biāo)準(zhǔn)進(jìn)行人工核查。
機(jī)審
對于部分明確的業(yè)務(wù)規(guī)則,比如白底圖、圖片清晰度、是否重復(fù)品、是否同質(zhì)品等,機(jī)審做前置校驗(yàn)并輸出機(jī)審結(jié)果,輔助人工審核,降低審核成本,提升審核效率。
AI審核
通過豐富算法能力、強(qiáng)化AI大模型能力、雷達(dá)技術(shù)等,建設(shè)越來越多的商品審核點(diǎn),并推動召回率、準(zhǔn)確率的提升,達(dá)標(biāo)的審核點(diǎn)可通過自動駁回、自動修改等action接管商品審核,降低人工審核的占比,降低人工成本。
五、現(xiàn)狀問題分析
產(chǎn)品層面
- 機(jī)審能力不足,部分字段沒覆蓋,部分規(guī)則不合理:
機(jī)審字段覆蓋度待提升
機(jī)審規(guī)則采納率不足
部分機(jī)審規(guī)則不合理
- 缺少產(chǎn)品配置化能力,配置黑盒化,需求迭代費(fèi)力度較高:
規(guī)則配置黑盒
規(guī)則執(zhí)行結(jié)果缺乏trace和透傳
調(diào)整規(guī)則依賴開發(fā)和發(fā)布
缺少規(guī)則執(zhí)行數(shù)據(jù)埋點(diǎn)
技術(shù)層面
- 系統(tǒng)可擴(kuò)展性不足,研發(fā)效率低:
業(yè)務(wù)鏈路(AI發(fā)品、審核、預(yù)檢等)不支持配置化和復(fù)用
規(guī)則節(jié)點(diǎn)不支持配置化和復(fù)用
六、流程介紹
搭建機(jī)審配置后臺,可以通過配置應(yīng)用場景+業(yè)務(wù)身份+商品維度配置來確定所需執(zhí)行的全量規(guī)則,規(guī)則可復(fù)用。
其中應(yīng)用場景代表業(yè)務(wù)場景,如商品上新審核、商家發(fā)品預(yù)檢、AI發(fā)品預(yù)檢等;業(yè)務(wù)身份則表示不同業(yè)務(wù)場景下不同方式,如常規(guī)渠道商品上新的業(yè)務(wù)場景下,AI發(fā)布、常規(guī)商品上新(商家后臺、交易后臺等)、FSPU同款發(fā)布品等。
當(dāng)商品變更,通過Binlog日志觸發(fā)機(jī)審,根據(jù)當(dāng)前的應(yīng)用場景+業(yè)務(wù)身份+商品信息,構(gòu)建對應(yīng)的機(jī)審執(zhí)行鏈(ProcessChain)完成機(jī)審執(zhí)行,不同的機(jī)審規(guī)則不通過支持不同的action,如自動修正、自動駁回、自動通過等。
鏈路執(zhí)行流程圖如下:
圖片
七、詳細(xì)設(shè)計(jì)
整體架構(gòu)圖
圖片
業(yè)務(wù)實(shí)體
ER圖
圖片
含義解釋
※ 業(yè)務(wù)場景
觸發(fā)機(jī)審的應(yīng)用場景,如新品發(fā)布、商家新品預(yù)檢等。
※ 業(yè)務(wù)身份
對于某個(gè)應(yīng)用場景,進(jìn)一步區(qū)分業(yè)務(wù)場景,如新品發(fā)布的場景下,又有AI發(fā)品、常規(guī)發(fā)品、FSPU同款發(fā)品等。
※ 業(yè)務(wù)規(guī)則
各行業(yè)線對于商品的審核規(guī)則,如校驗(yàn)圖片是否是白底圖、結(jié)構(gòu)化標(biāo)題中的類目需與商品類目一致、發(fā)售日期不能超過60天等。同一個(gè)業(yè)務(wù)規(guī)則可以因?yàn)闃I(yè)務(wù)線不同,配置不同的機(jī)審規(guī)則。
※ 規(guī)則組
對規(guī)則的分類,通常是商品字段模塊的名稱,一個(gè)規(guī)則組下可以有多個(gè)業(yè)務(wù)規(guī)則,如商品輪播圖作為規(guī)則組,可以有校驗(yàn)圖片是否白底圖、校驗(yàn)圖片是否清晰、校驗(yàn)?zāi)L刈藙菔欠窈弦?guī)等。
※ 機(jī)審規(guī)則
對商品某個(gè)商品字段模塊的識別并給出審核結(jié)果,數(shù)據(jù)依賴機(jī)審能力以及spu本身。
※ 機(jī)審能力
商品信息(一個(gè)或多個(gè)商品字段模塊)的審核數(shù)據(jù)獲取,通常需要調(diào)用外部接口,用于機(jī)審規(guī)則審核識別。
※ 業(yè)務(wù)&機(jī)審規(guī)則關(guān)聯(lián)關(guān)系
描述業(yè)務(wù)規(guī)則和機(jī)審規(guī)則的關(guān)聯(lián)關(guān)系,同一個(gè)業(yè)務(wù)規(guī)則可以根據(jù)不同業(yè)務(wù)線,給予不同的機(jī)審規(guī)則,如輪播圖校驗(yàn)正背面,部分業(yè)務(wù)線要求校驗(yàn)全量輪播圖,部分業(yè)務(wù)線只需要校驗(yàn)輪播圖首圖/規(guī)格首圖。
機(jī)審執(zhí)行流程框架
流程框架
通過責(zé)任鏈、策略模式等設(shè)計(jì)模式實(shí)現(xiàn)流程框架。
觸發(fā)機(jī)審后會根據(jù)當(dāng)前的業(yè)務(wù)場景、業(yè)務(wù)身份、商品信息等,獲取到對應(yīng)的業(yè)務(wù)身份執(zhí)行鏈(不同業(yè)務(wù)身份綁定不同的執(zhí)行節(jié)點(diǎn),最終構(gòu)建出來一個(gè)執(zhí)行鏈)并啟動機(jī)審流程執(zhí)行。
由于機(jī)審規(guī)則中存在數(shù)據(jù)獲取rt較長的情況,如部分依賴大模型的算法能力、雷達(dá)獲取三方數(shù)據(jù)等,我們通過異步回調(diào)的方式解決這種場景,也因此衍生出了“異步結(jié)果更新機(jī)審觸發(fā)”。
※ 完整機(jī)審觸發(fā)
完整機(jī)審觸發(fā)是指商品變更后,通過Binlog日志校驗(yàn)當(dāng)前商品是否滿足觸發(fā)機(jī)審,命中的機(jī)審規(guī)則中如果依賴異步回調(diào)的能力,則會生成pendingId,并記錄對應(yīng)的機(jī)審結(jié)果為“pending”(其他規(guī)則不受該pending結(jié)果的影響),并監(jiān)聽對應(yīng)的topic。
圖片
※ 異步結(jié)果更新機(jī)審觸發(fā)
部分pending規(guī)則產(chǎn)出結(jié)果后發(fā)送消息到機(jī)審場景,通過pendingId以及對應(yīng)的商品信息確認(rèn)業(yè)務(wù)身份,獲取異步結(jié)果更新責(zé)任鏈(與完整機(jī)審的責(zé)任鏈不同)再次執(zhí)行機(jī)審執(zhí)行責(zé)任鏈。
圖片
動態(tài)配置能力建設(shè)
調(diào)研
新機(jī)審鏈路建設(shè)不僅要支持機(jī)審規(guī)則復(fù)用,支持不同業(yè)務(wù)身份配置接入,還要支持新機(jī)審規(guī)則快速接入,降低開發(fā)投入的同時(shí),還能快速響應(yīng)業(yè)務(wù)的訴求。
經(jīng)過分析,機(jī)審規(guī)則絕大部分下游為算法鏈路,并且算法的接入方式較為固化,即“構(gòu)建請求參數(shù)” -> “發(fā)起請求” -> “結(jié)果解析”,并且數(shù)據(jù)模型通常較為簡單。因此技術(shù)調(diào)研之后,通過HTTP泛化調(diào)用實(shí)現(xiàn)構(gòu)建請求參數(shù)、發(fā)起請求,利用規(guī)則引擎(規(guī)則表達(dá)式)實(shí)現(xiàn)結(jié)果解析。
規(guī)則引擎技術(shù)選型
調(diào)研市面上的幾種常用規(guī)則引擎,基于歷史使用經(jīng)驗(yàn)、上手難度、文檔閱讀難度、性能等方面綜合考慮,最終決定選用QLExpress。
圖片
HTTP泛化調(diào)用能力建設(shè)
※ 實(shí)現(xiàn)邏輯
- 定義MachineAuditAbilityEnum統(tǒng)一的動態(tài)配置枚舉,并基于MachineAuditAbilityProcess實(shí)現(xiàn)其實(shí)現(xiàn)類。
- 統(tǒng)一入?yún)镸ap結(jié)構(gòu),通過反射機(jī)制、動態(tài)Function等方式,實(shí)現(xiàn)商品信息映射成算法請求參數(shù);另外為了提升反射的效率,利用預(yù)編譯緩存的方式,將字段轉(zhuǎn)成MethodHandle,后續(xù)對同一個(gè)字段做反射時(shí),可直接獲取對應(yīng)的MethodHandle,提升效率。
/**
* 緩存類字段的MethodHandle(Key: Class+FieldName, Value: MethodHandle)
*/
private static final Map<String, MethodHandle> FIELD_HANDLE_CACHE = new ConcurrentHashMap<>();
/**
* 根據(jù)配置從對象中提取字段值到Map
* @return 提取后的Map
*/
public Map<String, Object> fieldValueMapping(AutoMachineAlgoRequestConfig requestConfig, Object spuResDTO) {
AutoMachineAlgoRequestConfig.RequestMappingConfig requestMappingConfig = requestConfig.getRequestMappingConfig();
Map<String, Object> targetMap = Maps.newHashMap();
//1.簡單映射關(guān)系,直接將obj里的信息映射到resultMap當(dāng)中
//2.遍歷復(fù)雜映射關(guān)系,value是基礎(chǔ)類型
//3.遍歷復(fù)雜映射關(guān)系,value是對象
return targetMap;
}
/**
* 預(yù)編譯FieldMapping
*/
private List<AutoMachineAlgoRequestConfig.FieldMapping> compileConfig(List<AutoMachineAlgoRequestConfig.FieldMapping> fieldMappingList, Object obj) {
List<AutoMachineAlgoRequestConfig.FieldMapping> mappings = new ArrayList<>(fieldMappingList.size());
//緩存反射mapping
return mappings;
}
private Object getFieldValue(Object request, String fieldName) throws Throwable {
String cacheKey = request.getClass().getName() + "#" + fieldName;
MethodHandle handle = FIELD_HANDLE_CACHE.get(cacheKey);
return handle != null ? handle.invoke(request) : null;
}- 基于實(shí)現(xiàn)@FeignClient注解,實(shí)現(xiàn)HTTP調(diào)用的執(zhí)行器,其中@FeignClient中的URL表示域名,autoMachineAuditAlgo方法中的path表示具體的URL,requestBody是請求體,另外還包含headers,不同算法需要不同headers也可動態(tài)配置。
- 返回結(jié)果均為String,而后解析成Map<String,Object>用于規(guī)則解析。
@FeignClient(
name = "xxx",
url = "${}"
)
public interface GenericAlgoFeignClient {
@PostMapping(value = "/{path}")
String autoMachineAuditAlgo(
@PathVariable("path") String path,
@RequestBody Object requestBody,
@RequestHeader Map<String, String> headers
);
@GetMapping("/{path}")
String autoMachineAuditAlgoGet(
@PathVariable("path") String path,
@RequestParam Map<String, Object> queryParams,
@RequestHeader Map<String, String> headers
);
}- 動態(tài)配置JSON。
{
"url": "/ai-check/demo1",
"requestMappingConfig": {
"fieldMappingList": [
{
"sourceFieldName": "categoryId",
"targetKey": "categoryId"
},
{
"sourceFieldName": "brandId",
"targetKey": "brandId"
}
],
"perItemMapping": {
"mappingFunctionCode": "firstAndFirstGroundPic",
"fieldMappingList": [
{
"sourceFieldName": "imgId",
"targetKey": "imgId"
},
{
"sourceFieldName": "imgUrl",
"targetKey": "imgUrl"
}
]
}
}
}機(jī)審規(guī)則動態(tài)解析建設(shè)
※ 實(shí)現(xiàn)邏輯
- 定義MachineAuditRuleEnum統(tǒng)一的動態(tài)配置枚舉,并基于MachineAuditRuleProcess實(shí)現(xiàn)其統(tǒng)一實(shí)現(xiàn)類。
- 搭建QLExpress規(guī)則引擎,為了提升QLExpress規(guī)則引擎的效率,同樣引入了緩存機(jī)制,在機(jī)審規(guī)則配置表達(dá)式時(shí),則觸發(fā)loadRuleFromJson,將表達(dá)式轉(zhuǎn)換成規(guī)則引擎并注入到緩存當(dāng)中,真正機(jī)審流程執(zhí)行時(shí)會直接從緩存里獲取規(guī)則引擎并執(zhí)行,效率上有很大提升。
// 規(guī)則引擎實(shí)例緩存
private static final Map<String, ExpressRunner> runnerCache = new ConcurrentHashMap<>();
// 規(guī)則配置緩存
private static final Map<String, GenericEngineRule> ruleConfigCache = new ConcurrentHashMap<>();
// 規(guī)則版本信息
private static final Map<String, Integer> ruleVersionCache = new ConcurrentHashMap<>();
/**
* 加載JSON規(guī)則配置
* @param jsonConfig 規(guī)則JSON配置
*/
public GenericEngineRule loadRuleFromJson(String ruleCode, String jsonConfig) {
//如果緩存里已經(jīng)有并且是最新版本,則直接返回
if(machineAuditCache.isSameRuleConfigVersion(ruleCode) && machineAuditCache.getRuleConfigCache(ruleCode) != null) {
return machineAuditCache.getRuleConfigCache(ruleCode);
}
// 如果是可緩存的規(guī)則,預(yù)加載
return rule;
}- 機(jī)審規(guī)則執(zhí)行時(shí),通過配置中的規(guī)則名稱,獲取對應(yīng)的規(guī)則引擎進(jìn)行執(zhí)行。
/**
* 根據(jù)規(guī)則名稱執(zhí)行規(guī)則
* @param ruleCode 規(guī)則名稱
* @param context 上下文數(shù)據(jù)
* @return 規(guī)則執(zhí)行結(jié)果
*/
public MachineAuditRuleResult executeRuleByCode(String ruleCode, Map<String, Object> context, MachineAuditRuleProcessData ruleProcessData) {
if (StringUtils.isBlank(ruleCode)) {
throw new IllegalArgumentException("機(jī)審-通用協(xié)議-規(guī)則-規(guī)則名稱不能為空");
}
//從緩存中獲取規(guī)則引擎
//基于規(guī)則引擎執(zhí)行condition
//統(tǒng)一日志
}※ 配置demo
- 動態(tài)配置JSON。
{
"ruleCode": "demo1",
"name": "規(guī)則demo1",
"ruleType": 1,
"priority": 100,
"functions": [
],
"conditions": [
{
"expression": "result.code == null || result.code != 0",
"action": {
"type": "NO_RESULT",
"messageExpression": "'無結(jié)果'"
}
},
{
"expression": "result.data == 0",
"action": {
"type": "PASS",
"messageExpression": "'機(jī)審?fù)ㄟ^"
}
},
{
"expression": "result.data == 1",
"action": {
"type": "REJECT",
"messageExpression": "'異常結(jié)果1'",
"suggestType": 2,
"suggestKey": "imgId",
"preAuditSuggestKey": "imgUrl"
}
},
{
"expression": "result.data == 2",
"action": {
"type": "REJECT",
"messageExpression": "'異常結(jié)果2'",
"suggestType": 2,
"suggestKey": "imgId",
"preAuditSuggestKey": "imgUrl"
}
}
],
"defaultAction": {
"type": "PASS"
}
}八、關(guān)于數(shù)據(jù)分析&指標(biāo)提升
在經(jīng)歷了2-3個(gè)版本搭建完新機(jī)審鏈路 + 數(shù)據(jù)埋點(diǎn)之后,指標(biāo)一直沒有得到很好的提升,曾經(jīng)一度只是維持在20%以內(nèi),甚至有部分時(shí)間降低到了10%以下;經(jīng)過大量的數(shù)據(jù)分析之后,識別出了部分規(guī)則產(chǎn)品邏輯存在漏洞、算法存在誤識別等情況,并較為有效的通過數(shù)據(jù)推動了產(chǎn)品優(yōu)化邏輯、部分類目規(guī)則調(diào)整、算法迭代優(yōu)化等,在一系列的動作做完之后,指標(biāo)提升了50%+。
在持續(xù)了比較長的一段時(shí)間的50%+覆蓋率之后,對數(shù)據(jù)進(jìn)行了進(jìn)一步的剖析,發(fā)現(xiàn)這50%+在那個(gè)時(shí)間點(diǎn)應(yīng)該是到了瓶頸,原因是像“標(biāo)題描述包含顏色相關(guān)字樣”、“標(biāo)題存在重復(fù)文案”以及部分輪播圖規(guī)則,實(shí)際就是會存在不符合預(yù)期的情況,因此緊急與產(chǎn)品溝通,后續(xù)的非緊急需求停止,先考慮將這部分天然不符合預(yù)期的情況進(jìn)行處理。
之后指標(biāo)提升的動作主要圍繞:
- 算法側(cè)產(chǎn)出各算法能力的召回率、準(zhǔn)確率,達(dá)標(biāo)的算法由產(chǎn)品與業(yè)務(wù)拉齊,是否配置自動駁回的能力。
- 部分缺乏自動修改能力的機(jī)審規(guī)則,補(bǔ)充臨時(shí)需求建設(shè)對應(yīng)的能力。
經(jīng)過產(chǎn)研業(yè)務(wù)各方的配合,以最快速度將這些動作進(jìn)行落地,指標(biāo)也得到了較大的提升。


































