重复商品治理介绍
根据得物的平台特性,同一个商品在平台上不能出现多个链接,原因是平台需要保证一品一链的特点,以保障商品的集中竞价,所以说一个商品在整个得物平台上只能有一个商详链接,因此我们需要对一品多链的情况做治理,也就是我们所说的重复商品治理。
目前重复商品的治理流程是:
-
算法识别出疑似重复商品
-
人工对疑似重复商品做审核
-
人工确认重复后对SPU下架或合并
在商品重复识别的过程中,算法识别的重复商品人工审核后实际认可率较低,导致有大量的非重复商品需要进行审核,浪费了较多的人力成本,重复商品治理的效率也偏低。
引入多模态大模型
基于这样的业务场景和遇到的难点痛点问题,我们尝试通过多模态大模型对疑似重复商品做识别,一方面提升疑似重复商品识别的准确率,另一方面降低需要人工审核的数据量,提升人效降低成本。
主要的方案是在算法识别出的疑似商品的基础上,基于重复商品判别规则+多模态大模型进行重复商品的识别,过滤掉不重复只保留下模型识别为重复的商品,作为人工审核的数据。
Q3通过测试,在规则+google大模型的双重识别下,认可率至少提升了20%+,过滤掉有效非重复商品约60w,节省了15个人力/季度,节约成本30.6W。通过三盲标注一致的样本数据进行测试,模型识别准确率均在80%以上,部分类目可达90%+。
期间我们也对比了字节、百度、阿里等多模态大模型,进行了内部测试。测试结果表明,谷歌的Gemini 1.5模型在处理复杂多模态数据方面表现最佳,识别准确率比较认可,最终我们确定选择Gemini大模型。
接下来我来介绍下在重复商品识别的过程中我们是怎样应用多模态大模型并对架构进行一次次演进优化的。
第一版方案
首先在第一版的方案设计中,第一要素是要快,需要快速拿到验证的效果,所以基本上是一把梭的架构设计,按一级类目的维度设计提示词,将重复商品识别拆分成两个子任务:1、文本比较,2、图片比较,每个子任务都有自己的结构输出要求,最后再让大模型将2个任务的结果进行合并,返回最终的判定结果。
其中多模态模型的执行链路如下:
在提示词中定义了大模型输出结果的格式:
主要输出2行纯文本内容,第一行是文本识别的信息,其中包含了当前类目中所有需要对比的字段或属性,让大模型按照我们定义的格式进行结果输出;第二行是最终判定的结果,让模型返回2个商品是否重复,如果不重复需要给出理由。
文本识别信息=一级类目:相同(鞋与鞋);品牌:相同(AUTRY与AUTRY);适用人群:不相同(女与男);鞋面材质:相同(皮革与皮革);颜色:颜色相同(白浅绿与白浅绿); 最终判定结果=判断结果:不重复;理由:实际的理由
可以看到在第一版中,所有的业务逻辑都被封装在了大模型的prompt中,这对大模型的文本理解能力、指令遵循能力、复杂规则的处理能力都要求极高,识别结果的准确率可能不会太高,因为第一轮主要目的是先把链路跑通。通过拿以往人工审核过的有结果的数据作为数据集进行模型训练。模型识别的结果与人工的结果一致即认为是正确,在第一轮模型训练之后,针对服装女装内衣(3个类目的规则是一致的)的重复商品识别的准确率在90%以上。
以下是一些测试过程中的抽样数据:
因为第一轮主要是快速验证可行性,并且快速在多个类目中进行试验,所以第一版的方案非常适合,因为架构设计简单,只需要编写不同类目的提示词即可,并且提示词设计也比较简单具有通用性,在快速批量扩类目的过程中,可以利用大模型帮我写其他类目的提示词,事实上也确实是这样做的。
但是第一版的方案的缺点也是很明显的,首先因为是按照一级类目的维度设计的提示词,只适合服装类、鞋类这些规则简单的类目,其他类目的规则比较复杂需要细化到三级类目的维度,所以就不适合了。另外把判别结果交给模型进行推断,这本身就是一件靠运气的事,因为模型是通过推理进行任务处理,本身就是一种概率事件,当要处理的文本信息比较少的情况下,模型推理会比较稳定,当需要处理的内容过多时模型就会出现幻觉,文本识别信息和最终判定的结果会存在不一致,导致最终结果不正确,准确率低。
所以第一版的方案只适合验证方案的可行性,不适合正式使用。
第二版方案
第二版的方案也是按一级类目的维度设计提示词。只不过是在第一版的基础上优化了提示词,只让模型专注于判断具体的字段是否相同、图片是否相同,而不用给出结论,这样可以降低最终结果不一致的情况
修改了提示词中定义的输出结果的格式:
三级类目:是否相同=相同/不同,原因=具体的原因; 品牌:是否相同=相同/不同,原因=具体的原因; 属性信息:是否相同=相同/不同,原因=具体的原因; 图片信息:是否相同=相同/不同,原因=具体的原因;
只让模型按照规则分析商品信息中对应字段是否相同,而不用给出最终的判定结果,由应用系统根据模型返回的结果判断最终的结果。
但是第二版方案依然存在以下问题:
1.依然是按照一级类目的维度设计提示词,无法适应复杂类目下的复杂规则
2.文本和图片一起识别,当图文本身不一致时,模型无法判断是以文本为准还是图片为准,会存在互相干扰的情况,导致最终结果不正确
第三版方案
为了解决第二版存在的问题,第三版方案在第二版的基础上做了2个优化调整:
-
分类目情况按一级、二级、三级维度分别设计提示词。
-
将文本识别和图片识别拆分,分成2个单独的提示词任务,避免图文一起识别时互相干扰。
拆分后的文本任务单独返回字段对比相关的结果:
三级类目:是否相同=相同/不同,原因=具体的原因; 品牌:是否相同=相同/不同,原因=具体的原因; 属性信息:是否相同=相同/不同,原因=具体的原因;
图片任务单独返回图片对比的结果:
图片信息:是否相同=相同/不同,原因=具体的原因;
拆分之后的收益是很明显的:不会存在文本与图片对比互相干扰的情况,并且当文本识别结果明确是不重复时,即可取消对图片的识别,应用系统直接可以判定该条记录为不重复,从而减少一次多模态的模型调用。
另外按细化后的类目设计提示词后,可以根据具体的类目规则进行更详细的提示词设计,准确率提升明显
类目规则定义描述
为了能够在运行时根据类目动态确定具体的提示词,我们定义了一套按类目进行规则描述的方案,并在定义中配置不同类目的提示词和具体的规则,如下所示:
首先规则描述按一级类目、二级类目、三级类目分成了3个规则组,因为有的类目的规则比较简单,只需要按一级类目设计对比规则即可,例如箱包和服装;但是有的类目规则非常复杂,需要细化到具体的二级类目或三级类目,这时我们就需要在二级或三级类目规则组中描述具体的规则,例如3C数码。
在运行时匹配具体的规则时,会依次从三级类目、二级类目、一级类目进行匹配,如果三级类目配置了特定的规则,则会优先使用三级类目的规则,否则会使用一级类目的兜底规则。
第三版方案虽然提升了准确率,但仍然存下以下问题:
1.按三级类目维度设计提示词工作量骤升,并且需要在运行时根据类目动态确定具体的提示词,代码复杂度也变高了,扩类目的成本升高
2.针对特定字段的识别结果依然存在幻觉,并且在处理特别复杂的对比任务时,准确率下降很厉害。例如在对比2个箱包的尺寸时(长宽高误差在2cm内即可认为相同)准确率非常低
第四版方案
到目前为止文本类的字段对比任务依然是依赖大模型,大模型的优势在于能处理并解析复杂的不规范的内容,但是缺点也很明显,因为大模型的推理是一种概率事件,结果是不稳定的。
怎么保证每次输入的内容都能得到稳定、准确的结果是非常难的一件事,因此需要通过工程化的方式进行优化,通过在模型推理的流程中加入代码执行逻辑,以保证结果的稳定。
例如需要对比两个疑似重复商品中的适用型号字段中的品牌的值是否一致,而适用型号的内容值非常长,可能会有几十个型号,对于简短的适用型号模型可以很好的进行品牌信息的提取并对比,而对于长内容的对比,模型可能就会出现失误。
我们在使用大模型处理这个任务时,通常会将任务分为2个子任务:
1)从型号中提取出对应的品牌值,可能有多个品牌值
2)对比多个品牌值是否存在相同值
子任务越多,模型出错的概率越大,最好的方法是让每个模型只执行单一的、确定的子任务,这里我们可以只让模型执行第一个子任务,然后通过代码执行第二个子任务,这样就可以大大增加整个任务的准确率。
基于此,我们在第四版的方案中,引入了FunctionCall的功能,也就是将文本对比的任务拆成:
-
字段值提取
-
字段值对比
对于字段值的提取仍然交给大模型,只要把需要提取的字段是什么,按照怎样的规则进行提取描述清楚,一般模型提取出来的值都是比较稳定的。第二步对于字段值的对比,就交给我们的Function,因为函数的处理是按照规则稳定执行的,不可能存在字段值相等但却返回对比结果不相等的情况,即避免了模型出现幻觉的可能性。
第四版方案修改了提示词返回的结果的格式:
文本任务返回:
三级类目:商品1=xxx,商品2=xxx; 品牌:商品1=xxx,商品2=xxx; 尺寸:商品1=xxx,商品2=xxx;
图片任务返回:
图片信息:是否相同=相同/不同,原因=具体的原因;
在链路中引入FunctionCall
原来的重复商品识别的逻辑是完全由大模型执行,主要分为:文本对比和图片对比。
优化后的方案针对文本对比引入了FunctionCall,大模型主要负责:标准字段值提取,然后由应用系统提供的Function进行具体的字段对比。
优化后的图片对比由一次对比改为多次对比,需要查询出CSPU维度的所有规格图后进行一次相似度预识别,找出最相似的2张规格图之后,再对最相似的2张规格图进行一次多模态识别。
例如:spuA与spuB是一对重复组的商品,其中spuA中有5个CSPU:a1,a2,a3,a4,a5,spuB中有3个CSPU:b1,b2,b3,新链路中除了会返回spuA和spuB的相似度distance,还会返回spuA的CSPU中与spuB的CSPU中最相似的一个CSPU,比如a1,b3最相似,则会返回a1和b3的相似度。
标准FunctionCall介绍
谷歌FunctionCall介绍:
https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/function-calling?hl=zh-cn
标准的FunctionCall中大模型将外部系统的函数作为模型能力的一种补充,通过定义FunctionCall,大模型在执行推理时,可以通过外部系统的函数获取到推理过程中所需要的信息,然后进行推理。
例如我们想让大模型帮我们进行行程规划,此时可能会需要关注目的地的天气情况,这时就可以通过定义一个天气查询的FunctionCall并通过工具参数配置到大模型中,当大模型进行行程规划并且需要根据天气情况进行行程推荐时,此时大模型就会激活FunctionCall,调用工具中指定的函数获取具体的天气信息,然后进行下一步动作。
自定义FunctionCall设计
标准的FunctionCall对于我们重复商品识别的场景有2个问题:
-
重复商品识别的规则复杂,不同类目下关注的字段或属性项不同,很难通过编程式的方式定义出所有的FunctionCall的函数定义
-
标准的FunctionCall链路中,推理结果主要还是依赖模型进行返回,而我们的场景对于准确率的要求非常高,依赖模型会存在一定的幻觉
为此我设计了一套自定义FunctionCall的方案,通过提示词让模型提取出特定自定标准值的方案。
标准字段提取规则设计如下:
在promptPath中定义提示词,在提示词中指定模型的任务目标为:从输入字段或属性中提取出当前类目所关注的对比字段,并按照输出字段中定义的格式进行返回。
当模型提取出对应的对比字段的标准值之后,就可以调用外部系统的函数进行字段匹配了,如下所示在outputFields中定义了每个需要对比的字段的matcher函数是什么,执行FunctionCall时直接指定需要对比的matcher函数即可。
{
"lv1CategoryPromotConfigs" : [
{
"categorys" : ["箱包"],
"fieldCompare" : {
"promptPath" : "prompts_extract_args/luggage_extract.txt",
"llmInputFields" : [],
"llmInputProperties" : ["尺寸"],
"matchFields" : [
{"field" : "一级类目", "source" : "inputField", "sourceField" : "lv1Category", "matcher" : "EqualsItemMatcher"},
{"field" : "品牌", "source" : "inputField", "sourceField" : "brand", "matcher" : "EqualsItemMatcher"},
{"field" : "质地", "source" : "inputProperty", "sourceField" : "质地", "matcher" : "AnyOfEqualsItemMatcher"},
{"field" : "尺寸", "source" : "outputLlm", "sourceField" : "尺寸", "matcher" : "SizeOfEqualsItemMatcher"}
]
}
}
]
}
这里获取要对比的字段的值也有个巧妙的设计,通过source配置字段值的来源:
-
inputField:直接从商品标准字段中提取
-
inputProperty:直接从商品的属性字段中提取
-
outputLlm:经过大模型处理后的输出值
有了字段来源之后,在通过Matcher函数进行对比:
首先定义一个抽象类和抽象方法:
CSPU维度图片重识别
除此之外,第四版方案针对两个商品的主图识别不重复的情况,还会再对两个SPU的所有CSPU维度的规格图再做一次重识别,防止遗漏掉重复商品,因为有的商品存在很多的规格,虽然主商品不相似,但是规格中存在相似的相同。
但是对CSPU规格图做重识别也是有前提条件的,会根据类目确定是否需要进行CSPU维度的重复判别,如果该类目需要根据CSPU维度判重,则此时才会查询出两个商品的所有CSPU子集,然后获取CSPU维度下最相似的2张规格图进行对比。
获取规格图的过程如下:
首先将spu_id,cspu_url_list查询到一张宽表中,其中cspu_url_list字段中是所有规格图片,以逗号分隔,如下所示:
spu_id1, logo_url1, cspu_url_list1[cspu_url1_1,cspu_url1_2,cspu_url1_3], spu_id2, logo_url2, cspu_url_list2[cspu_url2_1,cspu_url2_2,cspu_url2_3,cspu_url2_4]
最终得到一个包含主图、规格图列表、最相似规格图的宽表,如下所示:
spu_id1, logo_url1, cspu_url_list1, most_similar_cspu_url1 spu_id2, logo_url2, cspu_url_list2, most_similar_cspu_url2
得到最相似的2张规格图之后,只要再调用一次多模态模型进行图片对比即可,这步可以将那些主图不相同但是规格图相同的商品找出来,避免了重复商品的遗漏。
但是目前算法提供的图片相似度识别接口,设置召回的阈值比较高,只有对于相似度非常高的图片,才会召回出相似图片,如以下这些高相似度的图片:
架构升级演进总结
版本 | 架构设计 | 模型输出结果 | 优点 | 缺点 | 架构设计变化 |
---|---|---|---|---|---|
第一版 | 按一级类目的维度设计提示词。 将重复商品识别拆分成两个子任务:1、文本比较,2、图片比较,每个子任务按照要求产出具体的结果数据,最后再将2个任务的结果进行合并,返回最终的判定结果 | 文本识别信息=一级类目:相同(鞋与鞋);品牌:相同(AUTRY与AUTRY);适用人群:不相同(女与男);鞋面材质:相同(皮革与皮革);颜色:颜色相同(白浅绿与白浅绿); 最终判定结果=判断结果:不重复;理由:实际的理由 | 1.提示词设计简单,可以快速验证结果 2.提示词具有通用性,可以快速批量扩展不同类目的提示词 | 1.按照一级类目设计重复商品识别的规则,只适合鞋、服等规则简单的类目,其他复杂类目需要细化到三级类目分别设置规则 2.模型处理的任务过多,文本识别信息和最终判定的结果存在不一致,导致最终结果不正确,准确率低 | 重复商品识别的结果完全由模型判断,准确率依赖于模型的智力。 最终的识别结果由模型确定。 |
第二版 | 按一级类目的维度设计提示词。 只让模型按照规则分析商品信息中对应字段是否相同,而不用给出最终的判定结果,由应用系统根据模型返回的结果判断最终的结果。 | 三级类目:是否相同=相同/不同,原因=具体的原因; 品牌:是否相同=相同/不同,原因=具体的原因; 属性信息:是否相同=相同/不同,原因=具体的原因; 图片信息:是否相同=相同/不同,原因=具体的原因; | 1.只让模型专注于判断具体的字段是否相同、图片是否相同,而不用给出结论,可以降低最终结果不一致的情况 | 1.依然是按照一级类目的维度设计提示词,无法适应复杂类目下的复杂规则 2.文本和图片一起识别,当图文本身不一致时,模型无法判断是以文本为准还是图片为准,会存在互相干扰的情况,导致最终结果不正确 | 重复商品识别的结果不需要由模型判断了,模型只需要分析具体的字段是否相同。 最终的识别结果由应用系统确定。 |
第三版 | 分类目情况按一级、二级、三级维度分别设计提示词。 并将文本识别和图片识别拆分,分成2个单独的提示词任务,避免图文一起识别时互相干扰。 | 文本任务返回: 三级类目:是否相同=相同/不同,原因=具体的原因; 品牌:是否相同=相同/不同,原因=具体的原因; 属性信息:是否相同=相同/不同,原因=具体的原因; 图片任务返回: 图片信息:是否相同=相同/不同,原因=具体的原因; | 1.按细化后的类目设计提示词后,可以根据具体的类目规则进行更详细的提示词设计,准确率提升明显 2.文本识别和图片识别拆分后,不会存在互相干扰的情况,并且当文本识别结果明确是不重复时,即可取消对图片的识别 | 1.按三级类目维度设计提示词工作量骤升,并且需要在运行时根据类目动态确定具体的提示词,代码复杂度也变高了,扩类目的成本升高 2.针对特定字段的识别结果依然存在幻觉,并且在处理特别复杂的对比任务时,准确率下降很厉害。例如在对比2个箱包的尺寸时(长宽高误差在2cm内即可认为相同)准确率非常低 | 文本对比任务和图片对比任务做拆分,让模型每次只专注于做一件事,降低互相干扰的概率。 最终的识别结果由应用系统确定。 |
第四版 | 分类目情况按一级、二级、三级维度分别设计提示词。 并将文本识别和图片识别拆分,分成2个单独的提示词任务,避免图文一起识别时互相干扰。 并且在文本识别任务中引入FunctionCall,提升文本对比的准确性。 针对主图识别为不重复的商品,再对规格图做重识别。 | 文本任务返回: 三级类目:商品1=xxx,商品2=xxx; 品牌:商品1=xxx,商品2=xxx; 尺寸:商品1=xxx,商品2=xxx; 图片任务返回: 图片信息:是否相同=相同/不同,原因=具体的原因; | 1.文本识别任务只让模型提取出对应商品对应字段的标准值,然后通过FunctionCall进行字段值的对比,准确率进一步提升 2.对规格图做重识别,可以进一步识别出主图不重复,但是规格图重复的商品。 | 1.需要针对不同的对比规则编写不同的对比函数,代码复杂度进一步提升 | 文本对比任务也不需要模型判断了,模型只需要提取的需要对比的字段的标准值,值的对比交给应用系统的对比函数。 进一步优化图片对比,优先对比主图,如果主图不重复,再对比规格图。 最终的识别结果由应用系统确定。 |