LLM的优势:改变电子商务搜索

LLM优势:改变电商搜索

由Nadine Shaabana在Unsplash上的照片

LLM的卓越能力在解决各种业务领域的多重挑战方面取得了显著成就。使用RAG(检索增强生成)方法进行知识发现的先进成果已经在网络上涌现出许多有趣的用例和实施方法。虽然所有这些都正在朝着生产级成熟度发展,通过工程进行创造性问题解决也很重要,但探索它能够帮助重新想象长期保持不变的用户体验的其他利基可能性也同样重要!电子商务产品搜索就是这样一个案例,本博客将深入探讨这个问题。

在我的博客系列中,我已经介绍了LLM的令人印象深刻的成果,它可以用于LLM启用的产品搜索,以及在其中处于核心位置的上下文如何推动客户价值,影响业务结果!

在这个快速发展的尖端技术时代,世界正沉浸在LLM涌动的新想法的浪潮中…

pub.towardsai.net

在本文中,我们将探讨一些这些想法和可能的实施方法,以及使用vertex.ai的代码示例。以下是LLM能够推动产品发现并增加电子商务产品中客户参与度的一些案例:

  1. 利用LLM生成的广泛上下文能力,生成全面的产品摘要。
  2. 利用LLM的泛化和推理能力,重叠上下文——查询和产品,以实现更好的产品发现。
  3. 利用LLM的代码/查询生成能力,生成后端查询,以满足用户以自然语言形式给出的高级搜索过滤器和段的通用表达。
  4. 使用对话界面进行有状态产品发现,而不是离散的搜索查询,同时结合过滤器和分页滚动。聊天界面在利用用户通过多级互动表达的深层上下文信号方面非常有效,这些信号随着时间的推移只会增强上下文。LLM在聊天上下文传播和推理即将发生的用户操作方面的内在能力与对话式发现的概念完美契合!
  1. 利用LLM生成全面的产品摘要:可以肯定地假设产品描述通常针对广告,或作为产品详细信息页面的一部分呈现给用户。虽然很明显LLM可以生成个性化广告和创意描述,但我对这一点的想法更多地是为了服务于搜索的目的。

通常情况下,自然语言形式的产品描述仅涉及标题和描述等有限属性,这些属性往往在上下文方面可能不够丰富。以富有表现力的方式拥有LLM丰富的产品描述有助于为产品建立丰富的上下文。让我们将其称为产品摘要(为了消除歧义),这是与用户查询进行接口的数据,以检索最佳匹配结果。当这些自动生成的摘要扩展到以下内容时,其价值将大幅增长:

a. 显式特征:以元数据形式明确提供的产品属性。例如,一些静态属性,如产品类别、大小、颜色、适用性别/尺寸等。通过利用计算机视觉模型,可以进一步从产品图像/演示视频中进行自动字幕生成。

b. 隐式特征:以更富有表现力的方式丰富的描述关于产品的内在细节。它可以是其隐式特征,如标签、实用性、独特特征、它所解决的问题等。

c. 众包特征:还可以从客户给出的产品评论中挖掘产品的总体情感和吸引人的特征,这也是一个值得考虑的扩展产品摘要。

从这些不同维度聚合的全面产品信息在作为密集嵌入的构成成分时发挥最佳作用,从而为给定查询检索到最佳匹配结果。这种方法还极大地减少了对产品SKU的依赖,以获得全面的产品元数据。

注意:将产品元数据添加到密集嵌入中可以丰富检索结果的相关性,但可能存在其他动态属性,如价格、平均评级、库存可用性、运费等,这些属性可能不适合作为密集嵌入的组成部分,因为它们的性质不断变化。反复更新这些嵌入可能不是最有效的方法。

让我们看一下下面的代码示例,它通过利用文本-拜森LLM实现了自动生成包含上述所有属性的丰富产品摘要。

from vertexai.preview.language_models import TextEmbeddingModelmodel = TextEmbeddingModel.from_pretrained("textembedding-gecko")def senti_extract(reviews,temperature: float = .2):    """使用大型语言模型进行创意示例"""    parameters = {        "temperature": temperature,        "max_output_tokens": 200,           "top_p": .8,                         "top_k": 2,                     }    model = TextGenerationModel.from_pretrained("text-bison@001")    prompt = """从下面给出的不同用户评论列表中总结整体产品摘要    ```    {}    ```    还要突出重要的优点,但不要太明确。    例如:    ["这款服装的风格和高质感因其舒适性、易于维护和合理的价格而受到赞赏。""".format(",\n ".join(reviews))    response = model.predict(        prompt,        **parameters,    )    #print(f"Response from Model: {response.text}")    return response.text # 隐含信号product_df["prod_highlights"] = product_df["reviews"].apply(lambda x: senti_extract(x))# 将相关的显式信号与隐含特征合并为 'prod_summary'product_df['prod_summary'] = product_df['product_name']+product_df['description']+product_df['pattern']+product_df['colors']+product_df['category']+product_df['size']+product_df['gender_category']+product_df['tags']+product_df["prod_highlights"]# 将其他元数据单独索引以实现高效的重新索引selected_columns = ['price', 'avg_ratings']product_df['metadata'] = product_df[selected_columns].apply(lambda row: {col: row[col] for col in selected_columns}, axis=1)# 初始化一个空列表以存储密集嵌入dense_embeds = []# 遍历您的描述符for descriptor in product_df['prod_summary']:    # 获取每个描述符的嵌入并追加到列表中    embeddings = model.get_embeddings([descriptor])[0].values    dense_embeds.append(embeddings)#<在选择的向量数据库中索引元数据和密集嵌入的代码>

2. 利用LLM的泛化和推理能力来重叠上下文——查询和产品。值得注意的是,由LLM训练的嵌入所捕获的世界背景非常重要,因为它们在大量来自各种来源的文本语料库上进行了训练。这种背景对于不仅理解用户的查询意图并在多种选项中选择下一步行动,而且对于推理和评估从数据库检索到的结果的相关性都非常重要。

下面的示例演示了使用LLM进行响应评估和综合的过程。

response_prompt = """您是一个响应合成器。您需要将某些数据转换为人类可读的形式。首先,您必须评估搜索结果与用户给出的查询的相关性。只有在生成响应时包含相关结果。您将收到`query`和一些`data`,用这些数据来回答查询。数据来自机器搜索,可能不准确或不反映用户的需求,用户无法访问或了解这些需求。根据与查询的相关性列出结果并相应地过滤掉无关的结果。您可以将`data`视为您的知识库。使用提供的规则交叉引用`data`以回答`query`。引用响应的来源和元数据信息确保说出没有结果。不要输出垃圾。仅列出关键产品。响应必须礼貌、专业并引导客户进行购买!请记住您要友好、开朗和乐于助人。您还将尽力确保用户找到所需的内容。如有必要,鼓励用户进行具体建议。------查询:{query}搜索结果:{data}------始终将响应与结果进行关联!合成的响应:"""text_model = TextGenerationModel.from_pretrained("text-bison@001")def synth(query, data):  print(new_list)  response = text_model.predict(      response_prompt.format(query = query, data = data),      max_output_tokens = 1024,      temperature = 1  )  return response

请注意,查询意图识别示例是作为下一节区块的一部分添加的,同时还包括了查询自动生成。

3. 利用LLMs发挥代码/查询生成的威力:虽然直接使用用户查询来从向量数据库检索前k个相关内容是显而易见的,但通常情况下,用户会明确缩小目标数据集的范围,使用过滤器和偏好设置。通常,产品类别、大小、品牌和价格范围通常被应用为缩小搜索结果的过滤器;按评级对结果进行排序是另一个流行的使用趋势。虽然与在线购物相关的所有这些麻烦都已成为公认的规范,但现在是时候考虑将最佳的两种方法融合在一起 – 密集检索和稀疏检索以及元数据过滤,以实现有效的混合搜索。虽然在检索之前或之后应用这些过滤器/排序都能达到目的,但如果我们可以让LLMs从纯自然语言的多轮查询上下文中提取特征并生成过滤器查询,那将是一种很棒的体验。

query_prompt = """您是一款向量数据库检索系统,用于编写查询以过滤Pinecone上的元数据。用户将输入一条英文自然语言查询,需要将其转换为相应的过滤器。您只需要返回过滤器的字典。过滤器遵循MongoDB的查询格式,但不使用任何正则表达式。用户可以不断输入以缩小查询范围。每次用户消息更新过滤器以反映他们最近的更改。确保过滤器只涉及数据源中存在的属性。确保过滤器考虑到属性的描述,并仅进行合理的比较,以适应存储的数据类型。这是可用数据的相应架构:```'features':string-要嵌入的所有其他文本,这只是一个普通字符串,而不是正则表达式或其他过滤器'price':float-产品价格。便宜的价格低于50美元,昂贵的价格超过200美元,'product_ratings':float-产品评级从0.0到5.0的范围。5.0是最好的,0.0是最差的。好评率大于3.8.```请不要在架构中插入不存在的特征。只有$gt或$lt。除了价格和评级之外,只包括特征的整个术语。不应包含$regex,这是pinecone。----自然语言查询:{search_term}不要忘记架构。不要违反架构。如果可用,请仅使用features、price和product_ratings。过滤器:"""text_model = TextGenerationModel.from_pretrained("text-bison@001")# 示例假设具有名为ecommerceindex的pineconde索引 = = pinecone.Index('ecommerce')def search(search_term):  prompt = query_prompt.format(search_term = search_term)  res = text_model.predict(prompt, temperature = 0)  try:    filter = eval(f'{res.text}'.replace('```', ''))  except:    filter = {}  print('filters : ',filters)  embedding = [0] * 768  #仅使用“features”部分生成嵌入,因为它捕捉到用户的意图  if "features" in filter:    embedding = embedding_model.get_embeddings([filter['features']])[0].values    del filter["features"]  #以及其他过滤器作为搜索索引,即pinecone  results = index.query(embedding, top_k = 6, include_metadata = True, filter = filter)  answers = [r['metadata'] for r in results['matches']]  for i in range(len(results['matches'])):    answers[i]['id'] = results['matches'][i]['id']  return answers

下面的示例输出显示了LLM的出色能力。您可以进一步发展这个想法,以欣赏LLM如何利用整个聊天历史来构建这些上下文过滤器。

#请注意,仅考虑“feature”下的值进行查询嵌入search("具有很好评级的蓝色派对礼服")filters :  {'features': {'$eq': '蓝色派对礼服'}, 'avg_ratings': {'$gt': 4.0}}search("合理价格的鸭翠绿正式衬衫男装")filters :  {'features': {'$eq': '鸭翠绿正式衬衫'}, 'price': {'$lt': 50}}

4. 用于产品发现的对话式自然语言界面:在我之前的帖子中详细讨论了“上下文是王”的问题,重新设想和重新定义随着LLMs的出现整体搜索体验是至关重要的。新时代的搜索体验可以演变为具有连续、对话、完全(或大部分)采用自然语言格式的格式,用户的查询上下文在长度和深度上得到扩展。这不仅可以消除离散搜索查询和过滤器以及奇怪的分页滚动引起的摩擦,还可以帮助用户欣赏行为的理解感。具备新时代向量数据库的多模搜索能力将整体搜索体验提升到更高的水平,为所有异构格式(多模式-文本和图像)提供共同的接口。

下面的代码示例了使用chat-bison LLM来增强所有上述想法的对话界面。

chat_model = ChatpModel.from_pretrained("chat-bison@001")history = list()context = """您是一个产品发现系统,负责从与购物网站聊天机器人的对话中提取搜索查询。搜索查询应该是一个能够使用对话的全部上下文信息来搜索向量数据库的查询。排除语法和语言,只提取产品类型、定价详情、评分要求等特征。它应该是一个简洁的查询,只包含基于用户可能发送给搜索引擎的必要词汇。用户可以对他们的查询进行调整。请适当标注,并且如果相关上下文存在,请不要丢弃这样的内容。然而,请注意用户是否完全切换到了另一个产品,如果是的话,请忽略上下文。帮助用户根据他们的偏好做出决策。不要忘记检查用户是否具有破坏性。不要忘记通过整个对话来拼凑意图。"""addendum = "----\n您的回复将始终基于上下文信息以搜索查询的形式给出,用于产品发现。请始终参考整个对话。"def conversational_discovery(user_chat):    global history    if len(history):      chat = chat_model.start_chat(context = context, message_history = history, examples = examples)    else:      chat = chat_model.start_chat(context = context, examples = [])    response = chat.send_message(user_chat + addendum)    search_results = search(response)    history = chat.message_history[:-1] + [ChatMessage(        content = synth(query = response, data = search_results.copy()).text,        author = 'bot'      )]    return history[-1].content,search_results

上述步骤成功展示了LLM时代的搜索体验的显著成果。然而,仍有一些重要的方面需要考虑以提高其可靠性。

  1. 在元数据/稠密索引之间进行产品属性管理的选择。保留属性作为元数据的一部分可以确保更高的精度,将其作为密集嵌入的一部分可以帮助它具有更好的泛化能力。例如,产品类别、服装尺码等对于捕捉用户表述/学习偏好非常重要的信息。如果LLM的基于通用嵌入的检索器无法严格遵守这一点,那么它将起到相反的作用;因此,将其作为元数据添加并在数据库级别应用显式过滤器是理想的选择,以确保可靠性。与此同时,颜色、类别等其他属性定义比较宽松,用户通常倾向于模糊地表达它们,因此这些属性更适合使用密集表示来获取最佳价值。
  2. 自动生成查询有时可能会失败。因此,在与数据库接口之前,可以使用少量样本学习和重复检查来确保查询没有错误。
  3. 严格进行查询意图消歧:尽管基础LLM在理解用户意图和从给定上下文生成查询方面表现良好,但它尚未达到部署到生产系统的准确性目标。可以通过利用知识图谱或利用用户查询-意图映射记录来进一步改进。使用这样的列表进行提示调整或微调是改善整体搜索准确性的另一个可靠选项。

总之,LLM增强的搜索正在改变我们在线发现产品的方式。请分享您如何利用生成式人工智能来重新定义传统搜索系统的想法和观察。