ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

教培AI推荐结果多样性优化:MMR最大边际相关性算法在教培场景的实现

教培AI推荐结果多样性优化:MMR最大边际相关性算法在教培场景的实现 导读当家长问AI有什么好的培训机构时如果推荐结果全是同类型、同价位的机构家长的体验会很差。本文介绍如何使用MMRMaximal Marginal Relevance最大边际相关性算法在保持推荐相关性的同时提升结果多样性并提供面向教培场景的完整Python实现。一、为什么推荐结果需要多样性1.1 单一推荐的困境假设家长问本地有什么好的培训机构如果只按相关性排序可能返回1. XX数学教育数学小班200元/课时 2. YY数学培训数学小班180元/课时 3. ZZ数学辅导数学一对一300元/课时 4. AA数学中心数学大班100元/课时 5. BB数学空间数学小班220元/课时全是数学机构。如果家长其实想看看英语或其他科目呢1.2 多样性的价值引入多样性后1. XX数学教育数学小班200元/课时← 最高相关性 2. CC英语学习英语互动式150元/课时← 科目多样性 3. DD综合辅导全科一对一250元/课时← 模式多样性 4. EE语文工作坊语文写作专项180元/课时← 科目多样性 5. FF编程教室编程项目制200元/课时← 品类多样性家长能一眼看到不同类型的选择体验更好。二、MMR算法原理2.1 核心公式MMRarg⁡max⁡d∈D∖S[λ⋅Relevance(d,Q)−(1−λ)⋅max⁡d′∈SSim(d,d′)]MMR \arg\max_{d \in D \setminus S} \left[ \lambda \cdot \text{Relevance}(d, Q) - (1 - \lambda) \cdot \max_{d \in S} \text{Sim}(d, d) \right]MMRargmaxd∈D∖S​[λ⋅Relevance(d,Q)−(1−λ)⋅maxd′∈S​Sim(d,d′)]其中$D$候选文档集合$S$已选文档集合$Q$查询$\lambda$平衡参数0-1控制相关性与多样性的权重$\text{Relevance}(d, Q)$文档$d$与查询$Q$的相关性得分$\text{Sim}(d, d)$文档$d$与已选文档$d$的相似度2.2 直觉理解第一项$\lambda \cdot \text{Relevance}$选择与查询最相关的文档第二项$(1-\lambda) \cdot \max \text{Sim}$惩罚与已选文档太相似的文档$\lambda$接近1更重视相关性结果更相似$\lambda$接近0更重视多样性结果更不同2.3 贪心选择流程初始化S {} 循环k次 对每个候选文档d 计算 MMR(d) λ × Relevance(d,Q) - (1-λ) × max_{d∈S} Sim(d,d) 选择MMR值最大的文档d* S S ∪ {d*} 返回 S三、教培场景的多样性维度3.1 定义教培机构的特征向量from dataclasses import dataclass, field from typing import List, Dict, Optional, Set import numpy as np from enum import Enum class Subject(Enum): MATH math ENGLISH english CHINESE chinese SCIENCE science PROGRAMMING programming ART art MUSIC music class TeachingStyle(Enum): ONE_ON_ONE one_on_one SMALL_GROUP small_group # 8 MEDIUM_GROUP medium_group # 9-20 LARGE_GROUP large_group # 20 class PriceLevel(Enum): BUDGET budget # 100/课时 STANDARD standard # 100-200/课时 PREMIUM premium # 200/课时 dataclass class TutoringInstitution: 教培机构 id: str name: str subjects: List[Subject] teaching_style: TeachingStyle price_level: PriceLevel grade_levels: List[str] # [g1_g3, g4_g6, junior, senior] embedding: np.ndarray # 语义向量用于相关性计算 # 用于多样性计算的特征 property def feature_vector(self) - np.ndarray: 构建用于相似度计算的特征向量 features [] # 科目one-hot7维 for s in Subject: features.append(1.0 if s in self.subjects else 0.0) # 教学风格one-hot4维 for ts in TeachingStyle: features.append(1.0 if ts self.teaching_style else 0.0) # 价格等级one-hot3维 for pl in PriceLevel: features.append(1.0 if pl self.price_level else 0.0) # 年级one-hot4维 for gl in [g1_g3, g4_g6, junior, senior]: features.append(1.0 if gl in self.grade_levels else 0.0) return np.array(features)3.2 多样性维度在教培场景中多样性体现在3个维度维度说明特征表示科目多样性推荐结果覆盖不同科目Subject one-hot教学风格多样性小班/一对一/大班交替TeachingStyle one-hot价格区间多样性高端/中端/平价分布PriceLevel one-hot四、MMR实现4.1 相似度计算def cosine_similarity(a: np.ndarray, b: np.ndarray) - float: 余弦相似度 dot np.dot(a, b) norm_a np.linalg.norm(a) norm_b np.linalg.norm(b) if norm_a 0 or norm_b 0: return 0.0 return dot / (norm_a * norm_b) def feature_similarity(inst1: TutoringInstitution, inst2: TutoringInstitution) - float: 基于特征的相似度用于多样性惩罚 return cosine_similarity(inst1.feature_vector, inst2.feature_vector) def relevance_score(inst: TutoringInstitution, query_embedding: np.ndarray) - float: 机构与查询的相关性得分 return cosine_similarity(inst.embedding, query_embedding)4.2 MMR选择器class MMRSelector: MMR推荐结果选择器 def __init__(self, lambda_param: float 0.7): Args: lambda_param: 相关性vs多样性的平衡参数 1.0 纯相关性 0.0 纯多样性 0.7 推荐默认值 self.lambda_param lambda_param def select(self, candidates: List[TutoringInstitution], query_embedding: np.ndarray, top_k: int 5) - List[TutoringInstitution]: 使用MMR算法从候选集中选择top_k个多样化结果 Args: candidates: 候选机构列表 query_embedding: 查询向量 top_k: 返回数量 if len(candidates) top_k: return candidates selected: List[TutoringInstitution] [] remaining list(candidates) for _ in range(top_k): best_inst None best_mmr -float(inf) for inst in remaining: # 相关性得分 rel relevance_score(inst, query_embedding) # 多样性惩罚与已选文档的最大相似度 if selected: max_sim max( feature_similarity(inst, s) for s in selected ) else: max_sim 0.0 # MMR得分 mmr self.lambda_param * rel - (1 - self.lambda_param) * max_sim if mmr best_mmr: best_mmr mmr best_inst inst selected.append(best_inst) remaining.remove(best_inst) return selected4.3 带约束的MMR在教培场景中我们可能还需要一些硬性约束class ConstrainedMMRSelector(MMRSelector): 带约束的MMR选择器 def select(self, candidates: List[TutoringInstitution], query_embedding: np.ndarray, top_k: int 5, must_include_subjects: Optional[Set[Subject]] None, max_same_subject: int 2) - List[TutoringInstitution]: 带约束的MMR选择 Args: must_include_subjects: 必须包含的科目 max_same_subject: 同一科目最多出现几次 if len(candidates) top_k: return candidates selected: List[TutoringInstitution] [] remaining list(candidates) # 第一轮确保必须包含的科目 if must_include_subjects: for subject in must_include_subjects: # 找到该科目中相关性最高的 subject_candidates [c for c in remaining if subject in c.subjects] if subject_candidates: best max(subject_candidates, keylambda x: relevance_score(x, query_embedding)) selected.append(best) remaining.remove(best) # 第二轮MMR选择剩余位置 for _ in range(top_k - len(selected)): best_inst None best_mmr -float(inf) for inst in remaining: # 约束检查同一科目不超过上限 if max_same_subject: subject_count sum( 1 for s in selected if set(s.subjects) set(inst.subjects) ) if subject_count max_same_subject: continue # 跳过不选这个 # MMR计算 rel relevance_score(inst, query_embedding) if selected: max_sim max(feature_similarity(inst, s) for s in selected) else: max_sim 0.0 mmr self.lambda_param * rel - (1 - self.lambda_param) * max_sim if mmr best_mmr: best_mmr mmr best_inst inst if best_inst: selected.append(best_inst) remaining.remove(best_inst) return selected五、完整使用示例# 创建教培机构数据 institutions [ TutoringInstitution( id1, name数学思维训练中心, subjects[Subject.MATH], teaching_styleTeachingStyle.SMALL_GROUP, price_levelPriceLevel.STANDARD, grade_levels[g1_g3, g4_g6], embeddingnp.random.rand(768) ), TutoringInstitution( id2, name英语启蒙工作坊, subjects[Subject.ENGLISH], teaching_styleTeachingStyle.SMALL_GROUP, price_levelPriceLevel.STANDARD, grade_levels[preschool, g1_g3], embeddingnp.random.rand(768) ), TutoringInstitution( id3, name奥数精英班, subjects[Subject.MATH], teaching_styleTeachingStyle.MEDIUM_GROUP, price_levelPriceLevel.PREMIUM, grade_levels[g4_g6, junior], embeddingnp.random.rand(768) ), TutoringInstitution( id4, name编程启蒙教室, subjects[Subject.PROGRAMMING], teaching_styleTeachingStyle.SMALL_GROUP, price_levelPriceLevel.STANDARD, grade_levels[g4_g6, junior], embeddingnp.random.rand(768) ), TutoringInstitution( id5, name语文写作工坊, subjects[Subject.CHINESE], teaching_styleTeachingStyle.ONE_ON_ONE, price_levelPriceLevel.PREMIUM, grade_levels[g4_g6, junior, senior], embeddingnp.random.rand(768) ), TutoringInstitution( id6, name数学一对一辅导, subjects[Subject.MATH], teaching_styleTeachingStyle.ONE_ON_ONE, price_levelPriceLevel.PREMIUM, grade_levels[g1_g3, g4_g6, junior], embeddingnp.random.rand(768) ), TutoringInstitution( id7, name科学实验班, subjects[Subject.SCIENCE], teaching_styleTeachingStyle.MEDIUM_GROUP, price_levelPriceLevel.BUDGET, grade_levels[g1_g3, g4_g6], embeddingnp.random.rand(768) ), TutoringInstitution( id8, name美术创意工作室, subjects[Subject.ART], teaching_styleTeachingStyle.SMALL_GROUP, price_levelPriceLevel.STANDARD, grade_levels[preschool, g1_g3, g4_g6], embeddingnp.random.rand(768) ), ] # 模拟查询向量找好的培训机构 query_embedding np.random.rand(768) # 纯相关性排序无多样性 selector_pure MMRSelector(lambda_param1.0) result_pure selector_pure.select(institutions, query_embedding, top_k5) print( 纯相关性排序 ) for i, inst in enumerate(result_pure, 1): print(f{i}. {inst.name} ({[s.value for s in inst.subjects]}, {inst.teaching_style.value})) # MMR排序带多样性 selector_mmr MMRSelector(lambda_param0.7) result_mmr selector_mmr.select(institutions, query_embedding, top_k5) print(\n MMR排序 (λ0.7) ) for i, inst in enumerate(result_mmr, 1): print(f{i}. {inst.name} ({[s.value for s in inst.subjects]}, {inst.teaching_style.value})) # 带约束的MMR selector_constrained ConstrainedMMRSelector(lambda_param0.7) result_constrained selector_constrained.select( institutions, query_embedding, top_k5, must_include_subjects{Subject.MATH}, # 必须包含数学 max_same_subject2 # 同一科目最多2个 ) print(\n 带约束MMR (必须含数学,同科目≤2) ) for i, inst in enumerate(result_constrained, 1): print(f{i}. {inst.name} ({[s.value for s in inst.subjects]}, {inst.teaching_style.value}))六、λ参数调优建议λ值效果适用场景0.9-1.0几乎纯相关性查询非常具体三年级数学小班0.7-0.8以相关性为主适度多样通用推荐默认推荐值0.5-0.6相关性和多样性均衡探索式推荐0.3-0.4以多样性为主家长没有明确需求时动态调整策略如果查询包含具体条件科目年级班型λ调高如果查询很模糊有什么好的机构λ调低可以根据用户反馈动态调整七、总结组件作用关键技术特征向量将机构信息编码为可计算的特征One-hot编码科目/风格/价格/年级相关性计算衡量机构与查询的匹配程度语义向量余弦相似度多样性计算衡量机构与已选机构的差异特征向量余弦相似度MMR选择器平衡相关性和多样性贪心选择惩罚项约束MMR满足硬性业务约束前置选择约束过滤对开发者的启示推荐系统不应只追求相关性多样性同样重要MMR是一个简洁有效的多样性优化算法λ参数需要根据查询类型动态调整对教培机构的启示如果你的机构和同区域其他机构高度同质化MMR可能会跳过你差异化科目、教学风格、价格区间能让你在多样性维度上被选中不只是做得好还要做得不一样
返回列表