ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

基于大模型意图识别的智能推荐系统架构与工程实践

基于大模型意图识别的智能推荐系统架构与工程实践 1. 项目缘起当推荐系统开始“听懂”人话最近在做一个智能内容平台的升级项目老板提了个听起来挺“玄”的需求能不能让推荐系统别光看用户点了什么而是去“猜”他当时到底在想什么比如一个用户搜索了“周末放松”系统如果只推荐“周末电影”那可能就窄了。他可能想的是“周边短途游”、“家庭聚餐好去处”甚至是“如何高效补觉”。这个需求的本质就是希望推荐系统能理解用户表达背后的真实意图而不仅仅是匹配关键词。这让我想起了几年前做传统推荐系统的经历。那时候我们重度依赖协同过滤和基于内容的推荐。协同过滤看“相似用户喜欢什么”基于内容的推荐看“物品本身的标签”。效果有但天花板也很明显冷启动问题、兴趣挖掘的滞后性、以及无法应对用户复杂多变的即时意图。用户输入“想学做蛋糕给女朋友过生日”系统可能因为“蛋糕”这个关键词推荐一堆烘焙教程却完全忽略了“生日”、“礼物”、“浪漫”这些更深层的语义和情感意图。所以当“大模型”这股风刮起来的时候我第一时间就意识到这可能是解决上述痛点的钥匙。大模型特别是经过海量文本训练的语言模型拥有强大的语义理解和上下文推理能力。它不仅能看懂字面意思还能联系上下文揣摩出用户的潜台词、情感倾向和真实目标。这个项目就是尝试将大模型的意图识别能力与传统推荐系统的排序、召回模块进行深度结合构建一个更“聪明”的智能推荐系统。它不是要完全取代现有系统而是作为一个强大的“意图理解引擎”为整个推荐链路注入新的、更精准的驱动力。2. 系统架构设计意图引擎如何嵌入推荐链路一个能理解语义意图的推荐系统其核心变化在于增加了一个“意图理解层”。传统的推荐链路大致是“用户行为/画像 - 召回 - 粗排 - 精排 - 重排”物品库相对静态。而我们的新架构则变成了“用户输入查询/上下文 - 意图识别与解析 - 意图向量化 - 动态物品召回与增强 - 融合排序”。2.1 核心模块拆解整个系统可以划分为四个核心模块它们协同工作将一句模糊的用户表达转化为精准的推荐列表。第一模块多粒度意图识别与抽取这是整个系统的“大脑”。我们利用大模型如ChatGLM、Qwen、Baichuan或通过API调用的大型模型来处理用户输入的原始文本。这个过程不是简单的分类而是分层次的解析领域识别判断用户查询属于哪个大的领域如电商、内容、旅游、本地生活。这有助于后续调用不同的领域知识库或物品库。核心意图抽取提取用户最直接的目标。例如“帮我找一款续航长的轻薄笔记本”中核心意图是“寻找笔记本电脑”。属性与约束条件解析从语句中解析出具体的限定条件。如上例中的“续航长”、“轻薄”就是关键属性。此外还包括价格区间、品牌偏好、使用场景如“办公用”、“玩游戏”等。隐式意图与情感挖掘这是大模型的优势所在。分析文本的情感色彩积极、消极、急切、探索性和潜在需求。比如“最近工作好累想找个地方放松一下”其显式意图是“找地方”但隐式意图是“缓解压力”、“寻求治愈”情感是“疲惫的”。这直接影响推荐物品的调性是推荐刺激的游乐场还是安静的温泉酒店。为了实现这一点我们通常采用Prompt Engineering提示词工程来引导大模型进行结构化输出。例如我们设计一个提示词模板你是一个专业的意图解析助手。请分析以下用户查询并严格按照JSON格式输出结果。 用户查询{user_query} 请分析 1. 领域如3C数码、美妆、旅游、知识内容等。 2. 核心意图用户最想完成的动作如购买、查询、比较、寻找灵感等。 3. 显式属性从查询中直接提到的条件如品牌、型号、颜色、价格范围等。 4. 隐式需求用户可能未明说但隐含的需求如性价比高、彰显身份、便捷省时、情感慰藉等。 5. 情感倾向积极、消极、中性、急切、犹豫等。大模型会返回一个结构化的JSON对象这为后续处理提供了清晰的输入。第二模块意图向量化与物品池关联识别出的意图尤其是核心意图、属性和隐式需求需要被转化为机器可以计算的形式。这里我们使用嵌入模型Embedding Model如text-embedding-3-small、BGE-M3或M3E。我们将解析后的意图文本例如“续航长的轻薄笔记本用于移动办公希望性价比高”输入嵌入模型得到一个高维度的语义向量例如1536维。与此同时我们的物品库商品、文章、视频等的元数据标题、描述、标签、类别也需要通过同样的嵌入模型转化为向量并存入向量数据库如Milvus, Weaviate, Qdrant或Elasticsearch的向量搜索功能。关键在这里我们不仅存储物品本身的向量还会根据意图识别的结果动态生成或增强物品的向量表示。例如对于一个“笔记本电脑”商品除了其本身的“标题描述”向量当系统识别到“移动办公”意图时可以将其与“便携”、“续航”、“办公软件兼容性”等概念向量进行加权融合生成一个针对“移动办公”意图的增强向量。第三模块基于意图的动态召回与增强传统的召回可能依赖于用户历史行为协同过滤或物品分类标签基于内容。在我们的系统中首要的召回通道是基于意图向量的语义召回。系统使用从用户查询中提取的意图向量在向量数据库中进行近似最近邻搜索召回一批语义上最相关的物品。但这还不够。我们还需要解决意图的多样性和物品的冷启动问题。因此我们设计了混合召回策略主通道语义召回用意图向量直接召回Top-K物品。辅助通道一属性过滤召回利用解析出的“显式属性”如价格范围、品牌在传统数据库中进行过滤查询召回符合条件的物品再与语义召回结果取交集或并集根据业务逻辑。辅助通道二隐式意图扩展召回对于“隐式需求”如“彰显身份”、“情感慰藉”我们可能有一个预定义的“概念-物品”映射表或使用大模型生成一批与隐式需求相关的关键词再用这些关键词进行二次搜索召回。辅助通道三协同过滤保底对于新用户或意图非常模糊的情况降级使用基于热门或用户群的协同过滤进行保底召回。第四模块融合排序与理由生成召回阶段会产生一个多源的候选物品集合。排序阶段的任务是给这些物品打分决定最终展示的顺序。我们采用多目标融合排序模型。模型的输入特征不仅包括传统的特征用户画像、物品热度、历史点击率更重要的是加入了意图相关度特征语义相似度分候选物品向量与意图向量的余弦相似度。属性匹配分物品属性与解析出的显式约束条件的匹配程度如价格是否在区间内是否包含指定品牌。隐式需求满足度分这个分数可能通过一个小型模型或规则来判断。例如对于“彰显身份”的需求奢侈品、限量版、高单价物品的分数会更高。多样性控制为了避免结果同质化需要在排序中引入多样性惩罚因子确保同一意图下推荐结果能覆盖不同的子类型或角度。最终排序模型综合这些特征输出每个物品的最终得分。此外利用大模型为每个推荐结果生成一句简短的推荐理由能极大提升用户体验和说服力。例如“为您推荐此款笔记本因为它重量仅1.2kg续航达12小时完美匹配您‘移动办公’的需求。”2.2 技术栈选型与考量在实际搭建中技术选型需要平衡效果、性能、成本和工程复杂度。大模型服务云端API如OpenAI GPT-4o, Anthropic Claude, 国内各大厂的API开发快效果稳定但存在持续成本、网络延迟和数据隐私考量。适合快速验证原型或对效果要求极高的核心场景。本地部署开源模型如ChatGLM3-6B, Qwen1.5-7B, Baichuan2-7B数据可控无网络延迟长期成本可能更低。但对计算资源GPU有要求且需要团队有一定的模型优化和运维能力。对于意图识别任务7B-13B参数量的模型在精心设计Prompt后通常已经能达到不错的效果。我们的选择在内部验证阶段我们使用了云端API进行快速迭代和Prompt调优。在系统上线时出于数据安全和成本考虑我们选择了量化后的Qwen1.5-7B-Chat模型部署在内部GPU服务器上专门用于意图识别响应速度在200ms以内完全满足实时推荐的需求。嵌入模型与向量数据库嵌入模型text-embedding-3-small在通用语义表征上效果一流但同样是API调用。我们最终选择了开源的BGE-M3模型它在中文语义匹配任务上表现优异且支持多向量混合检索非常适合我们的多属性意图匹配场景。向量数据库Qdrant因其出色的性能、丰富的过滤条件和相对简单的运维成为我们的选择。Milvus功能更强大但更重。对于中小规模物品库百万级Elasticsearch的向量搜索插件也是一个可靠的选择。排序模型初期为了快速上线我们采用了梯度提升决策树模型如LightGBM。它的特征重要性可解释性强能很好地处理我们混合的数值型和类别型特征。后续计划探索深度排序模型如DeepFM以更好地捕捉特征间的复杂交互。注意模型并非越大越好。在意图识别这个特定任务上经过指令微调SFT的中等规模模型7B-13B其表现往往不逊于超大参数模型但推理成本和速度却有数量级的优势。关键在于Prompt的设计和任务定义的清晰性。3. 实战从零搭建一个简易语义推荐原型理论讲完了我们来动手搭建一个最小可行系统。假设我们是一个“数字生活内容平台”物品库是10万篇科技、生活、旅游类文章。我们的目标是用户输入一段自然语言描述系统返回最相关的5篇文章。3.1 环境准备与数据预处理首先我们需要一个处理好的物品文章向量库。# 环境安装示例 (requirements.txt) # transformers4.35.0 # sentence-transformers # 或者使用 FlagEmbedding 库 # qdrant-client # pandas # 以及其他依赖... import pandas as pd from sentence_transformers import SentenceTransformer from qdrant_client import QdrantClient from qdrant_client.models import Distance, VectorParams, PointStruct # 1. 加载文章数据 # 假设我们有 articles.csv包含字段id, title, content, category df pd.read_csv(articles.csv) # 为了更好的语义表征我们将标题和部分关键内容拼接成文本 df[text_for_embedding] df[title] 。 df[content].str.slice(0, 200) # 取前200字内容 # 2. 加载嵌入模型 # 使用 BGE-M3 模型它支持多向量检索这里我们先使用稠密向量 model SentenceTransformer(BAAI/bge-m3, trust_remote_codeTrue) # 如果你的环境无法加载也可以使用较小的模型如 BAAI/bge-small-zh-v1.5 # 3. 生成文章向量 print(正在生成文章向量...) corpus_embeddings model.encode( df[text_for_embedding].tolist(), batch_size64, show_progress_barTrue, normalize_embeddingsTrue # 归一化方便计算余弦相似度 ) print(f向量生成完成形状{corpus_embeddings.shape}) # 4. 连接并创建Qdrant集合 client QdrantClient(hostlocalhost, port6333) # 假设Qdrant本地运行 collection_name article_vectors # 检查集合是否存在不存在则创建 if not client.collection_exists(collection_name): client.create_collection( collection_namecollection_name, vectors_configVectorParams(sizecorpus_embeddings.shape[1], distanceDistance.COSINE), ) print(f集合 {collection_name} 创建成功。) # 5. 上传向量点 points [] for idx, row in df.iterrows(): points.append( PointStruct( ididx, vectorcorpus_embeddings[idx].tolist(), payload{ article_id: int(row[id]), title: row[title], category: row[category], content_preview: row[content][:100] # 存储前100字用于预览 } ) ) # 分批上传避免单次请求过大 batch_size 100 for i in range(0, len(points), batch_size): client.upsert( collection_namecollection_name, pointspoints[i:ibatch_size] ) print(文章向量数据已全部导入Qdrant。)3.2 意图识别服务实现接下来我们实现一个简单的意图识别服务。这里为了演示我们使用一个轻量级的本地模型并设计一个简单的Prompt。# intent_parser.py from transformers import AutoTokenizer, AutoModelForCausalLM import torch import json class IntentParser: def __init__(self, model_nameQwen/Qwen1.5-1.8B-Chat): # 使用一个更小的模型做演示 self.tokenizer AutoTokenizer.from_pretrained(model_name, trust_remote_codeTrue) self.model AutoModelForCausalLM.from_pretrained( model_name, torch_dtypetorch.float16, # 半精度节省显存 device_mapauto, trust_remote_codeTrue ) self.prompt_template 你是一个智能推荐系统的意图分析模块。请分析用户输入并输出一个JSON对象。 用户输入{user_input} 请输出包含以下键的JSON - core_intent: 用户的核心意图总结一句话。 - explicit_keywords: 从输入中提取的显式关键词列表如名词、形容词。 - implicit_tone: 隐含的语气或情感如求知、休闲、寻求解决、比较。 - possible_category: 最可能的内容分类如科技评测、旅游攻略、生活技巧、数码购买。 请确保只输出JSON不要有其他任何文字。 def parse(self, user_input): prompt self.prompt_template.format(user_inputuser_input) messages [{role: user, content: prompt}] text self.tokenizer.apply_chat_template( messages, tokenizeFalse, add_generation_promptTrue ) model_inputs self.tokenizer([text], return_tensorspt).to(self.model.device) generated_ids self.model.generate( **model_inputs, max_new_tokens256, do_sampleFalse # 为了稳定性关闭随机采样 ) generated_ids [ output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids) ] response self.tokenizer.batch_decode(generated_ids, skip_special_tokensTrue)[0] # 尝试从响应中提取JSON try: # 模型可能输出 Markdown 代码块需要清理 if json in response: response response.split(json)[1].split()[0].strip() elif in response: response response.split()[1].split()[0].strip() intent_data json.loads(response) return intent_data except json.JSONDecodeError as e: print(fJSON解析失败原始响应{response}) # 返回一个兜底结构 return { core_intent: user_input, explicit_keywords: [], implicit_tone: neutral, possible_category: unknown } # 示例使用 if __name__ __main__: parser IntentParser() test_input 想买一个拍照效果好、续航又长的手机主要用来旅行和拍vlog。 result parser.parse(test_input) print(json.dumps(result, indent2, ensure_asciiFalse))运行上述代码可能会得到类似这样的输出{ core_intent: 购买一款适合旅行和拍摄vlog的、拍照效果好且续航长的手机。, explicit_keywords: [拍照效果好, 续航长, 手机, 旅行, 拍vlog], implicit_tone: 有明确购买目标注重实用性和体验, possible_category: 数码购买 }3.3 语义检索与推荐流程串联最后我们将意图解析和向量检索串联起来形成完整的推荐流程。# recommender.py from intent_parser import IntentParser from sentence_transformers import SentenceTransformer from qdrant_client import QdrantClient from qdrant_client.models import Filter, FieldCondition, MatchValue class SemanticRecommender: def __init__(self, qdrant_hostlocalhost, qdrant_port6333, collection_namearticle_vectors): self.intent_parser IntentParser() self.embedding_model SentenceTransformer(BAAI/bge-m3, trust_remote_codeTrue) self.client QdrantClient(hostqdrant_host, portqdrant_port) self.collection_name collection_name def recommend(self, user_query, top_k5): 主推荐函数 # 1. 意图解析 print(f用户查询: {user_query}) intent self.intent_parser.parse(user_query) print(f解析意图: {intent}) # 2. 构建搜索向量 # 将核心意图和显式关键词组合成搜索文本 search_text intent[core_intent] .join(intent[explicit_keywords]) query_vector self.embedding_model.encode(search_text, normalize_embeddingsTrue) # 3. 在向量数据库中进行语义搜索 search_result self.client.search( collection_nameself.collection_name, query_vectorquery_vector.tolist(), limittop_k * 2, # 多召回一些用于后续过滤或重排 with_payloadTrue, with_vectorsFalse ) # 4. 可选基于分类等属性进行过滤 # 如果意图中明确了分类可以过滤 filtered_results [] for hit in search_result: payload hit.payload # 这里可以添加更复杂的过滤逻辑例如匹配 possible_category # if intent[possible_category] in payload.get(category, ): # filtered_results.append(hit) # else: # # 也可以不严格过滤而是作为排序的一个特征 # pass filtered_results.append(hit) # 简单起见我们取相似度最高的前 top_k 个 final_results filtered_results[:top_k] # 5. 格式化输出 recommendations [] for res in final_results: rec { article_id: res.payload[article_id], title: res.payload[title], category: res.payload[category], score: res.score, # 余弦相似度得分 preview: res.payload[content_preview] } recommendations.append(rec) return recommendations # 运行示例 if __name__ __main__: recommender SemanticRecommender() query 周末想去近郊徒步有什么风景好、难度不大的路线推荐吗 recs recommender.recommend(query, top_k3) print(\n 推荐结果 ) for i, rec in enumerate(recs, 1): print(f{i}. [{rec[category]}] {rec[title]} (相似度: {rec[score]:.3f})) print(f 预览: {rec[preview]}...\n)这个原型系统虽然简单但已经具备了“理解-检索-推荐”的核心闭环。当用户输入“周末想去近郊徒步有什么风景好、难度不大的路线推荐吗”时系统能理解其核心意图是“寻找徒步路线”并提取出“近郊”、“风景好”、“难度不大”等关键属性最终从文章库中召回相关的徒步攻略文章而不是泛泛的旅游文章。4. 工业级优化与踩坑实录将原型系统升级为能承受生产环境流量、稳定可靠的工业级系统中间有大量的坑需要填。这里分享几个我们实践中遇到的关键问题和解决方案。4.1 意图识别的稳定性与兜底策略大模型的输出具有不确定性尽管我们要求输出JSON但它偶尔还是会“说胡话”输出非结构化文本或格式错误的JSON。此外对于某些模糊或极短的查询如“好无聊”意图解析可能不准确。我们的解决方案输出规范化与校验在解析模型响应后增加一个强大的后处理校验层。使用json5库比标准json更宽松进行解析尝试。如果失败则触发以下流程尝试用正则表达式从乱码中提取可能的结构。如果仍失败则启动一个轻量级规则引擎或关键词匹配作为兜底。例如查询中包含“怎么”、“如何”则识别为“教程”意图包含“推荐”、“哪个好”则识别为“比较”意图。记录解析失败的案例用于后续优化Prompt或模型微调。意图分类器融合除了生成式大模型我们并行部署了一个微调过的文本分类模型如基于BERT的模型专门用于识别有限的、预定义的几十个核心意图类别如“购买决策”、“寻求教程”、“问题解答”、“休闲浏览”。将生成式模型的“核心意图”字段与分类器的结果进行对比和投票提高稳定性。查询改写与扩展对于过于简短的查询系统会自动尝试进行“查询扩展”。例如输入“手机”结合用户历史行为如果他常看摄影内容可能将其扩展为“摄影功能强的手机评测与推荐”。这可以通过一个轻量级的Seq2Seq模型或基于规则的模板来实现。4.2 语义检索的相关性与多样性博弈直接使用意图向量进行最近邻搜索经常遇到两个问题一是结果过于同质化都是标题和描述最匹配的几篇内容角度单一二是对于某些抽象或情感化意图如“治愈心情”检索结果可能不直接。我们的优化措施多向量混合检索不只用“核心意图”向量去搜。我们为每个物品计算多个向量title_vector: 标题向量。content_vector: 摘要或关键段落向量。tag_vector: 将物品的标签集合转化为一个向量。对于关键物品还可以用大模型生成其“卖点向量”或“适用场景向量”。 在检索时将用户查询向量与这多个物品向量分别计算相似度然后加权求和作为最终相关性分数。权重可以根据意图类型动态调整例如购买意图更看重tag_vector探索意图更看重content_vector。基于聚类的多样性打散在召回阶段先召回较多的候选物品如Top 100。然后对这些物品的向量进行快速聚类如K-Means。在最终选取Top K时不是简单按分排序而是从不同的聚类簇中按比例选取分数最高的物品保证结果覆盖不同的主题或方面。引入知识图谱对于“治愈心情”这类抽象意图语义向量可能不够。我们构建了一个小型的领域知识图谱将“治愈心情”与“温馨电影”、“舒缓音乐”、“自然风光散文”、“萌宠视频”等概念节点关联。当识别到此类意图时系统会从图谱中获取相关概念并用这些概念作为关键词进行二次召回与语义召回结果融合。4.3 系统性能与成本控制大模型推理和向量检索都是计算密集型操作直接影响接口响应时间RT和服务器成本。我们的实战经验模型量化与推理优化对于本地部署的意图识别模型必须进行量化如使用GPTQ、AWQ或GGUF格式。我们将Qwen-7B模型量化到INT4精度模型大小缩小至约4GB在单张消费级GPU如RTX 4090上推理速度提升3-5倍精度损失在可接受范围内。使用vLLM或TGI等高性能推理框架可以进一步优化吞吐量。向量检索的索引优化Qdrant、Milvus等向量数据库支持多种索引类型如HNSW、IVF。对于千万级以下的向量库HNSW索引在召回率和速度上是一个很好的平衡选择。需要根据数据规模和查询QPS调整ef_construction和ef_search参数。定期对向量索引进行重建非常重要因为随着新物品的加入数据分布可能发生变化。多级缓存策略意图缓存相同的用户查询或经过归一化后的查询其意图解析结果在短时间内是稳定的。可以缓存query - intent_json的结果TTL设置为几分钟到几小时能极大减轻大模型服务的压力。语义检索缓存对于高频或热门的查询意图其对应的召回结果也可以缓存。但要注意物品库更新的问题可以设置较短的TTL或监听物品更新事件来清除相关缓存。热点物品缓存将最终排序后Top K的物品的完整信息图片、详情等缓存在应用层加速页面渲染。异步与流式处理对于推荐流程并非所有步骤都需要同步实时完成。例如“理由生成”可以异步进行先返回推荐列表理由稍后通过WebSocket或轮询推送。召回阶段也可以并行执行语义召回和属性过滤召回。4.4 效果评估与持续迭代如何衡量这个“更智能”的推荐系统是否真的更好不能只靠感觉。我们建立的评估体系离线评估意图识别准确率构建一个标注好的测试集包含各种用户查询及其正确的意图标注领域、核心意图、属性等计算模型输出的准确率、召回率。语义检索相关性采用人工标注或利用点击数据构造“查询-相关物品”对计算NDCGK、MAP等指标对比纯关键词搜索和语义搜索的效果。在线A/B测试这是黄金标准。将用户流量随机分成实验组使用语义推荐和对照组使用旧推荐系统。核心观察指标点击率、转化率、人均停留时长、推荐结果的点击分布基尼系数衡量多样性、下单率如果是电商。特别注意新系统可能因为推荐更精准、更小众导致初期点击率CTR下降因为推的都是用户真正可能点的但数量少了但转化率或深度阅读率会上升。需要综合多个指标来看。人工评测与bad case分析定期抽样检查推荐结果尤其是那些在线指标表现差的case。分析是意图识别错了还是物品向量没建好或者是排序模型的特征权重有问题。建立bad case库用于驱动后续的模型迭代和策略优化。踩坑心得不要试图用大模型解决所有问题。初期我们曾想用一个大模型端到端地完成从理解到推荐的全部工作但发现其响应慢、成本高、输出不可控。最终合理的架构是“各司其职”大模型专注于它最擅长的语义理解与结构化解析Embedding模型负责高效的语义向量化向量数据库负责快速的相似性检索传统的机器学习/深度学习排序模型负责综合多特征的精排。这个混合架构在效果、性能和成本之间取得了最佳平衡。从意图识别到个性化推荐这条路远不止是接上一个大模型API那么简单。它涉及对传统推荐链路的深刻重构需要我们在自然语言处理、向量检索、机器学习排序以及系统工程等多个方面进行深度融合与创新。过程中最大的挑战不是技术本身而是如何让这些技术组件像齿轮一样精密咬合稳定、高效地服务于业务目标。当系统第一次准确识别出用户那句“有点闷想看点轻松不用动脑的”背后是“寻求轻度娱乐、缓解压力”的意图并推出一系列有趣的短视频和轻松短文时那种“它真的懂了”的感觉是对所有投入最好的回报。这个系统的价值正在于它让机器推荐从“猜你喜欢”迈向了“懂你所需”。
返回列表