基于T5模型的电商搜索意图生成实战:提升商品可发现性

📅 2026/8/15 2:15:04
基于T5模型的电商搜索意图生成实战:提升商品可发现性
在电商搜索场景中用户输入的查询词往往简短、模糊甚至存在拼写错误这给搜索引擎准确理解用户意图、返回相关商品带来了巨大挑战。例如用户搜索“跑步鞋 男”其背后可能隐藏着“缓震跑步鞋”、“竞速跑鞋”、“夏季透气网面跑步鞋”等多种细分需求。传统的搜索系统主要依赖查询词本身进行匹配难以充分挖掘这些潜在的“相关意图”导致搜索结果不够精准用户需要多次翻页或修改查询才能找到心仪商品严重影响了购物体验和转化率。本文将深入探讨一种通过“相关意图生成”来提升电商搜索商品可发现性的技术方案。我们将从问题背景出发拆解其核心原理并提供一个从数据准备、模型构建到系统集成的完整实战流程。无论你是搜索算法工程师、推荐系统开发者还是对NLP应用感兴趣的后端工程师都能通过本文掌握一套可落地的、用于扩展和丰富用户查询、从而提升搜索效果的系统性方法。1. 背景与核心概念为什么需要相关意图生成在深入技术细节之前我们首先要明确“相关意图生成”在电商搜索中的定位和价值。1.1 电商搜索的痛点电商平台的搜索引擎是流量分发的核心入口。其核心目标是理解用户查询 - 召回相关商品 - 精准排序。然而用户查询Query通常信息量有限简短模糊如“裙子”、“手机”。表述多样同一商品可能有多种叫法如“卫衣”和“套头衫”。存在歧义“苹果”可能指水果也可能指手机品牌。隐含需求“跑步鞋”背后可能隐含对“轻便”、“透气”、“耐磨”等属性的要求。传统基于词匹配如BM25或简单向量化的方法难以应对这些挑战容易导致召回不全漏掉相关商品或召回不准引入不相关商品。1.2 什么是相关意图生成相关意图生成Related Intent Generation是一种查询扩展Query Expansion或查询理解Query Understanding的进阶技术。它不再是简单地寻找同义词或进行拼写纠错而是利用自然语言生成NLG技术根据原始查询自动生成一系列在语义上相关、但在表述上可能不同、且能指向更具体或更丰富商品集合的新查询。输入原始用户查询例如“男士皮鞋”。输出一组生成的相关意图查询例如“商务正装男士皮鞋”“休闲系带男士皮鞋”“男士乐福鞋”“透气防滑男士皮鞋”1.3 核心价值与应用场景生成的相关意图可以应用于搜索系统的多个环节显著提升商品的可发现性召回阶段将原始查询和所有生成的相关意图一起送入召回器如倒排索引或向量检索引擎大幅增加召回池的多样性和覆盖率避免因查询表述单一而遗漏优质商品。排序阶段可以将相关意图作为特征帮助排序模型更深入地理解查询的语义构成。搜索引导与推荐在搜索框下拉提示、搜索结果页的“相关搜索”或“猜你想搜”等区域展示这些生成的高质量意图主动引导用户发现更精准的需求提升用户体验。广告匹配为搜索广告提供更丰富的关键词匹配选项。2. 环境准备与版本说明本实战案例将使用Python作为主要开发语言并依托PyTorch深度学习框架和Hugging Face Transformers库来构建生成模型。同时我们会使用Elasticsearch作为搜索引擎来演示召回效果。2.1 基础软件环境操作系统Linux (Ubuntu 20.04) 或 macOS Windows建议使用WSL2。Python: 3.8 或 3.9。包管理pip 或 conda。2.2 核心Python库及版本建议创建一个新的虚拟环境并安装以下依赖。版本号以常见稳定版本为例实际开发中请根据兼容性调整。# 创建并激活虚拟环境以conda为例 conda create -n search_intent_gen python3.8 conda activate search_intent_gen # 安装核心依赖 pip install torch1.13.1cu117 --extra-index-url https://download.pytorch.org/whl/cu117 pip install transformers4.26.1 pip install datasets2.10.1 pip install sentencepiece0.1.97 pip install pandas1.5.3 pip install scikit-learn1.2.2 pip install tqdm4.65.0 # 用于ES操作和HTTP请求 pip install elasticsearch8.8.0 pip install requests2.28.22.3 外部服务Elasticsearch: 8.x 版本。需要提前安装并启动服务。可以下载并运行其Docker镜像docker run -d --name es01 -p 9200:9200 -e discovery.typesingle-node -e xpack.security.enabledfalse docker.elastic.co/elasticsearch/elasticsearch:8.8.0Hugging Face Model Hub: 需要网络连接以下载预训练模型。2.4 项目目录结构建议按如下结构组织代码保持清晰。ecommerce_intent_generation/ ├── data/ │ ├── raw/ # 原始数据 │ ├── processed/ # 处理后的数据 │ └── sample_queries.txt # 示例查询词 ├── src/ │ ├── __init__.py │ ├── data_preprocess.py # 数据预处理脚本 │ ├── model.py # 模型定义 │ ├── trainer.py # 训练逻辑 │ ├── generator.py # 意图生成脚本 │ └── es_utils.py # Elasticsearch工具类 ├── configs/ │ └── config.yaml # 配置文件 ├── outputs/ # 模型输出、生成结果 ├── requirements.txt └── README.md3. 核心原理与模型选型相关意图生成本质上是一个条件文本生成任务。我们需要一个能够理解原始查询语义并生成流畅、相关、多样新查询的模型。3.1 模型架构选择目前基于Transformer的Seq2Seq模型是此类任务的主流选择。我们有两种主要方案微调预训练Seq2Seq模型如T5、BART。这些模型在大量文本上进行了预训练具有强大的语言理解和生成能力。通过在我们特定的电商查询对上微调可以快速获得高质量模型。这是本文推荐的首选方案平衡了效果和开发成本。基于Decoder-only模型的提示学习如GPT系列。通过设计合适的提示模板Prompt引导大模型生成相关意图。这种方法无需训练或只需少量训练但对提示工程要求高且API调用成本或本地部署开销较大。3.2 T5模型简介T5 (Text-To-Text Transfer Transformer) 将所有NLP任务都统一为“文本到文本”的格式。对于我们的任务输入“generate related search queries: 男士皮鞋”输出“商务正装男士皮鞋; 休闲系带男士皮鞋; 男士乐福鞋”这种统一框架使得模型适配非常简单。我们将采用google/mt5-small多语言T5的小型版本作为基础模型进行微调。3.3 技术路线图我们的完整流程如下数据准备收集或构建(原始查询 相关意图列表)的训练数据对。模型微调使用Hugging Face Trainer微调T5模型。意图生成用微调好的模型为新的查询生成相关意图。搜索集成将生成的意图用于扩展召回并在Elasticsearch中验证效果。4. 完整实战案例从数据到搜索集成4.1 数据准备与预处理高质量的训练数据是模型成功的基石。数据可以来源于搜索日志。来源1同一Session内用户连续发出的搜索查询可以互为相关意图。来源2点击了同一个商品的不同查询词。来源3人工标注的查询-意图对。这里我们模拟一个简单的数据集创建过程。创建示例数据文件data/raw/train_pairs.csvoriginal_query,related_intents 男士皮鞋,商务正装男士皮鞋;休闲系带男士皮鞋;男士乐福鞋 连衣裙,碎花雪纺连衣裙;法式复古收腰连衣裙;夏季短袖连衣裙 智能手机,5G全网通智能手机;大屏长续航手机;高性能游戏手机 跑步鞋,轻便透气跑步鞋;专业马拉松跑鞋;男士缓震跑步鞋 蓝牙耳机,真无线蓝牙耳机;主动降噪运动耳机;入耳式高音质耳机编写数据预处理脚本src/data_preprocess.pyimport pandas as pd from datasets import Dataset from transformers import AutoTokenizer import yaml import os def load_config(config_pathconfigs/config.yaml): with open(config_path, r) as f: config yaml.safe_load(f) return config def preprocess_data(data_path, tokenizer, max_input_length64, max_target_length128): 读取CSV数据并将其处理成T5模型需要的格式。 格式input_text generate related search queries: {original_query} target_text {intent1}; {intent2}; ... df pd.read_csv(data_path) input_texts [] target_texts [] for _, row in df.iterrows(): original str(row[original_query]).strip() # 构造T5任务前缀 input_text fgenerate related search queries: {original} input_texts.append(input_text) # 相关意图用分号连接 target_texts.append(str(row[related_intents]).strip()) # 使用datasets库创建Dataset对象 dataset_dict { input_text: input_texts, target_text: target_texts } dataset Dataset.from_dict(dataset_dict) # 定义tokenization函数 def tokenize_function(examples): model_inputs tokenizer( examples[input_text], max_lengthmax_input_length, paddingmax_length, truncationTrue ) # 为标签设置tokenizer with tokenizer.as_target_tokenizer(): labels tokenizer( examples[target_text], max_lengthmax_target_length, paddingmax_length, truncationTrue ) model_inputs[labels] labels[input_ids] # 将padding的标签部分设置为-100以便在计算损失时忽略 model_inputs[labels] [ [(l if l ! tokenizer.pad_token_id else -100) for l in label] for label in model_inputs[labels] ] return model_inputs # 应用tokenization tokenized_dataset dataset.map(tokenize_function, batchedTrue) # 移除原始文本列只保留模型需要的列 tokenized_dataset tokenized_dataset.remove_columns([input_text, target_text]) return tokenized_dataset if __name__ __main__: config load_config() tokenizer AutoTokenizer.from_pretrained(config[model_name]) train_dataset preprocess_data( config[train_data_path], tokenizer, max_input_lengthconfig[max_input_length], max_target_lengthconfig[max_target_length] ) eval_dataset preprocess_data( config[eval_data_path], tokenizer, max_input_lengthconfig[max_input_length], max_target_lengthconfig[max_target_length] ) # 保存处理后的数据集可选 train_dataset.save_to_disk(config[processed_train_path]) eval_dataset.save_to_disk(config[processed_eval_path]) print(f数据预处理完成训练集大小{len(train_dataset)}验证集大小{len(eval_dataset)})配置文件configs/config.yamlmodel_name: google/mt5-small train_data_path: data/raw/train_pairs.csv eval_data_path: data/raw/eval_pairs.csv # 需准备评估集 processed_train_path: data/processed/train_dataset processed_eval_path: data/processed/eval_dataset max_input_length: 64 max_target_length: 128 num_beams: 4 # 生成时的beam search参数 training_args: output_dir: ./outputs/mt5-finetuned num_train_epochs: 10 per_device_train_batch_size: 8 per_device_eval_batch_size: 8 warmup_steps: 500 weight_decay: 0.01 logging_dir: ./logs logging_steps: 50 evaluation_strategy: epoch save_strategy: epoch load_best_model_at_end: True metric_for_best_model: eval_loss greater_is_better: False save_total_limit: 24.2 模型定义与训练我们使用Hugging FaceTrainerAPI来简化训练流程。编写训练脚本src/trainer.pyfrom transformers import AutoModelForSeq2SeqLM, DataCollatorForSeq2Seq, Seq2SeqTrainingArguments, Seq2SeqTrainer from datasets import load_from_disk import yaml import os def load_config(config_pathconfigs/config.yaml): with open(config_path, r) as f: config yaml.safe_load(f) return config def compute_metrics(eval_pred, tokenizer): 计算评估指标例如生成文本的BLEU或ROUGE此处简化 predictions, labels eval_pred # 解码predictions和labels decoded_preds tokenizer.batch_decode(predictions, skip_special_tokensTrue) # 将labels中的-100替换为pad_token_id以便解码 labels np.where(labels ! -100, labels, tokenizer.pad_token_id) decoded_labels tokenizer.batch_decode(labels, skip_special_tokensTrue) # 这里可以引入rouge_score等库计算ROUGE # 为简单起见先打印几个样本 for i in range(min(3, len(decoded_preds))): print(fSample {i}: Pred - {decoded_preds[i]}, Label - {decoded_labels[i]}) # 返回一个空的metrics字典实际应用中应填充ROUGE等分数 return {} def main(): config load_config() # 1. 加载分词器和模型 from transformers import AutoTokenizer tokenizer AutoTokenizer.from_pretrained(config[model_name]) model AutoModelForSeq2SeqLM.from_pretrained(config[model_name]) # 2. 加载处理后的数据集 train_dataset load_from_disk(config[processed_train_path]) eval_dataset load_from_disk(config[processed_eval_path]) # 3. 数据收集器 data_collator DataCollatorForSeq2Seq(tokenizer, modelmodel) # 4. 定义训练参数 training_args Seq2SeqTrainingArguments( **config[training_args] ) # 5. 初始化Trainer trainer Seq2SeqTrainer( modelmodel, argstraining_args, train_datasettrain_dataset, eval_dataseteval_dataset, data_collatordata_collator, tokenizertokenizer, # compute_metricslambda eval_pred: compute_metrics(eval_pred, tokenizer) # 可启用 ) # 6. 开始训练 trainer.train() # 7. 保存最终模型 trainer.save_model() tokenizer.save_pretrained(training_args.output_dir) print(f模型训练完成已保存至{training_args.output_dir}) if __name__ __main__: main()运行训练命令cd /path/to/ecommerce_intent_generation python src/trainer.py4.3 相关意图生成模型训练完成后我们可以用它来为新的查询生成相关意图。编写生成脚本src/generator.pyfrom transformers import AutoTokenizer, AutoModelForSeq2SeqLM import yaml import torch def load_generator(model_path, config_pathconfigs/config.yaml): 加载微调好的模型和分词器 with open(config_path, r) as f: config yaml.safe_load(f) tokenizer AutoTokenizer.from_pretrained(model_path) model AutoModelForSeq2SeqLM.from_pretrained(model_path) device torch.device(cuda if torch.cuda.is_available() else cpu) model.to(device) model.eval() return model, tokenizer, device, config def generate_related_intents(query, model, tokenizer, device, config, num_return_sequences3): 为单个查询生成相关意图 input_text fgenerate related search queries: {query} inputs tokenizer( input_text, return_tensorspt, max_lengthconfig[max_input_length], truncationTrue, paddingTrue ).to(device) with torch.no_grad(): outputs model.generate( **inputs, max_lengthconfig[max_target_length], num_beamsconfig[num_beams], num_return_sequencesnum_return_sequences, early_stoppingTrue, do_sampleTrue, # 可以开启采样以获得更多样性 temperature0.8, ) generated_intents [] for output in outputs: decoded tokenizer.decode(output, skip_special_tokensTrue) # 生成的文本可能是用分号连接的多个意图我们拆分成列表 intents [i.strip() for i in decoded.split(;) if i.strip()] generated_intents.extend(intents) # 去重并返回前N个 unique_intents list(dict.fromkeys(generated_intents))[:num_return_sequences] return unique_intents if __name__ __main__: # 加载模型假设模型保存在 outputs/mt5-finetuned model, tokenizer, device, config load_generator(outputs/mt5-finetuned) test_queries [蓝牙耳机, 连衣裙 夏季, 游戏笔记本] for query in test_queries: intents generate_related_intents(query, model, tokenizer, device, config, num_return_sequences3) print(f原始查询: {query}) print(f生成的相关意图: {intents}) print(- * 50)运行生成示例python src/generator.py预期输出类似原始查询: 蓝牙耳机 生成的相关意图: [真无线运动蓝牙耳机, 头戴式降噪蓝牙耳机, 入耳式高音质蓝牙耳机] -------------------------------------------------- 原始查询: 连衣裙 夏季 生成的相关意图: [碎花雪纺连衣裙, 法式复古短袖连衣裙, 宽松休闲连衣裙] --------------------------------------------------4.4 搜索集成与效果验证生成意图的最终价值要在搜索系统中检验。我们将演示如何用Elasticsearch实现意图扩展召回。首先向Elasticsearch索引一些模拟商品数据# src/es_utils.py from elasticsearch import Elasticsearch import json def connect_es(): 连接Elasticsearch es Elasticsearch( hosts[http://localhost:9200], request_timeout30 ) if es.ping(): print(成功连接Elasticsearch) return es else: raise ConnectionError(无法连接到Elasticsearch) def create_index(es, index_nameecommerce_products): 创建商品索引如果不存在 if not es.indices.exists(indexindex_name): mapping { mappings: { properties: { product_id: {type: keyword}, title: {type: text, analyzer: ik_max_word}, # 使用IK中文分词器 category: {type: keyword}, price: {type: float}, attributes: {type: text, analyzer: ik_smart} } } } es.indices.create(indexindex_name, bodymapping) print(f索引 {index_name} 创建成功) else: print(f索引 {index_name} 已存在) def index_sample_products(es, index_nameecommerce_products): 索引一些示例商品 products [ {product_id: 1, title: 索尼真无线蓝牙耳机 降噪运动, category: 数码, price: 899.0, attributes: 蓝牙5.2 降噪 入耳式}, {product_id: 2, title: 苹果AirPods Pro 第二代, category: 数码, price: 1899.0, attributes: 主动降噪 空间音频}, {product_id: 3, title: Beats Studio Buds 运动耳机, category: 数码, price: 1099.0, attributes: 真无线 降噪 苹果安卓通用}, {product_id: 4, title: 夏季碎花雪纺连衣裙, category: 女装, price: 299.0, attributes: 碎花 雪纺 收腰}, {product_id: 5, title: 法式复古短袖连衣裙, category: 女装, price: 359.0, attributes: 复古 收腰 棉质}, ] for i, product in enumerate(products): es.index(indexindex_name, idproduct[product_id], documentproduct) print(f已索引 {len(products)} 个商品) es.indices.refresh(indexindex_name) if __name__ __main__: es connect_es() create_index(es) index_sample_products(es)然后实现基于意图扩展的搜索函数# 在 src/es_utils.py 中添加函数 def search_with_intent_expansion(es, index_name, original_query, generated_intents, boost_original2.0): 使用原始查询和生成的相关意图进行搜索。 通过bool查询的should子句同时匹配多个查询词。 可以给原始查询更高的权重(boost)。 should_clauses [] # 1. 原始查询更高权重 should_clauses.append({ match: { title: { query: original_query, boost: boost_original } } }) # 2. 每个生成的相关意图 for intent in generated_intents: should_clauses.append({ match: { title: { query: intent, boost: 1.0 # 相关意图权重 } } }) query_body { query: { bool: { should: should_clauses, minimum_should_match: 1 # 至少匹配一个子句 } }, size: 10 } response es.search(indexindex_name, bodyquery_body) return response[hits][hits] # 主程序示例 from generator import load_generator, generate_related_intents def main(): # 1. 连接ES并准备数据 es connect_es() create_index(es) index_sample_products(es) # 2. 加载意图生成模型 model, tokenizer, device, config load_generator(outputs/mt5-finetuned) # 3. 测试查询 test_query 蓝牙耳机 print(f\n 测试查询: {test_query} ) # 4. 生成相关意图 related_intents generate_related_intents(test_query, model, tokenizer, device, config, num_return_sequences2) print(f生成的相关意图: {related_intents}) # 5. 执行意图扩展搜索 print(f\n--- 使用意图扩展进行搜索 ---) results search_with_intent_expansion(es, ecommerce_products, test_query, related_intents) for i, hit in enumerate(results): source hit[_source] print(f{i1}. [{source[category]}] {source[title]} (价格: {source[price]}) - 得分: {hit[_score]:.2f}) # 6. 对比仅使用原始查询搜索 print(f\n--- 仅使用原始查询进行搜索 ---) query_body_simple { query: { match: { title: test_query } }, size: 10 } simple_results es.search(indexecommerce_products, bodyquery_body_simple)[hits][hits] for i, hit in enumerate(simple_results): source hit[_source] print(f{i1}. [{source[category]}] {source[title]} (价格: {source[price]}) - 得分: {hit[_score]:.2f}) if __name__ __main__: main()运行此集成脚本你将看到使用意图扩展后召回的商品列表可能更丰富一些通过相关意图匹配到的商品如“运动耳机”也被召回从而提升了商品的可发现性。5. 常见问题与排查思路在实际开发和部署中你可能会遇到以下典型问题。问题现象可能原因排查与解决思路生成的相关意图不相关或质量差1. 训练数据量少或噪声大。2. 模型训练不充分epoch太少。3. 生成参数如temperature设置不当。1.检查数据人工审核训练数据对的质量确保(query, intent)强相关。2.增加数据通过搜索日志挖掘、人工标注扩充数据集。3.调整训练增加训练轮数监控验证集损失。4.调整生成尝试不同的temperature(0.7~1.0)num_beams(3~5) 或使用核采样(top-p)。生成意图重复或多样性不足1. Beam Search导致解码结果趋同。2. 训练数据本身多样性不足。1.改用采样设置do_sampleTrue并配合temperature和top_p。2.多样性惩罚使用diversity_penalty参数如果模型支持。3.后处理去重对生成结果进行语义或字符串去重。模型无法生成中文或出现乱码1. 分词器不支持中文。2. 预训练模型语料中文占比低。1.更换模型使用明确支持中文的预训练模型如Langboat/mengzi-t5-base或imxly/t5-pegasus。2.检查分词确保分词器能正确编码和解码中文字符。集成搜索后结果相关性下降1. 生成的部分意图与原始查询语义漂移。2. 搜索查询中各意图的权重boost设置不合理。1.意图过滤对生成的意图进行相关性打分过滤例如使用一个交叉编码器模型计算原始查询与生成意图的相似度过滤低分结果。2.调整权重降低生成意图的boost值或使用更复杂的加权策略如根据生成置信度加权。3.A/B测试线上进行小流量A/B测试以点击率、转化率为指标优化策略。线上服务延迟高1. 模型推理速度慢。2. 对每个查询生成意图数量过多。1.模型优化使用模型量化、ONNX Runtime或TensorRT加速推理。2.缓存策略对高频查询的生成结果进行缓存。3.异步生成非实时路径如更新搜索索引可采用异步生成。训练时GPU内存不足1. 批次大小batch size过大。2. 序列长度max_length设置过长。1.减小批次降低per_device_train_batch_size。2.梯度累积使用gradient_accumulation_steps模拟大批次。3.混合精度训练启用fp16。4.缩短序列根据数据情况合理设置max_input_length和max_target_length。6. 最佳实践与工程建议将相关意图生成技术成功应用于生产环境需要超越基础模型训练关注整个工程链路的稳健性和效果。6.1 数据质量是天花板多源构建训练数据结合Session数据、点击数据、人工标注、同义词典等构建大规模、高质量的(query, related_intents)对。持续数据迭代将线上用户对生成意图的反馈如点击、下单作为信号回流到训练数据中形成闭环。数据清洗过滤掉包含敏感词、无效字符、过长过短的噪声数据。6.2 模型优化与迭代领域自适应在通用预训练模型基础上使用海量电商标题、query日志进行继续预训练让模型更“懂”电商语言。多任务学习可以联合训练意图生成和查询分类、实体识别等任务共享底层语义表示相互促进。可控生成在生成时引入控制信号如指定生成意图的“属性”如“品牌”、“材质”、“风格”使生成结果更具导向性。这可以通过在输入前缀中添加控制令牌实现例如“generate related search queries about [style]: 男士皮鞋”。6.3 搜索系统集成策略分层召回不要将所有生成意图无差别地用于召回。可以设计分层策略第一层用原始query召回第二层用高置信度的生成意图召回最后进行混合排序。意图权重动态计算不要给所有生成意图固定权重。可以根据生成模型的置信度分数、意图与原始query的语义相似度分数动态计算其在搜索查询中的权重。实时性与缓存对于搜索下拉提示等实时性要求高的场景需要预计算或缓存高频query的生成结果。对于商品索引更新等场景可以采用离线批量生成的方式。6.4 效果评估与监控离线评估生成质量使用BLEU、ROUGE、BERTScore等评估生成文本与参考文本的相似度。相关性人工评估生成意图与原始query的相关性相关、弱相关、不相关。搜索指标在离线测试集上对比使用意图扩展前后的召回率、NDCG等排序指标。在线A/B测试核心指标点击率CTR、转化率CVR、平均停留时长、翻页率。观测指标搜索无结果率、首次点击位置分布。线上监控服务健康度模型服务延迟、错误率、QPS。意图质量抽样监控生成意图的相关性设置报警机制。6.5 安全与合规内容安全过滤在生成意图的输出端必须接入内容安全过滤器防止生成涉黄、涉政、暴恐等违规查询词。偏见与公平性检查模型生成的意图是否隐含性别、地域等偏见并进行纠偏。可控与可解释对于重要的电商品类或促销活动可能需要人工配置或干预部分相关意图确保业务可控。系统应记录每次搜索所使用的意图来源便于问题追溯。通过系统性地实施上述最佳实践你可以构建一个不仅技术先进而且稳定、可靠、有效果的电商搜索相关意图生成系统切实提升用户的搜索体验和平台的商业效率。