1. 项目概述:当推荐系统“活”了过来
最近在跟几个做推荐系统的朋友聊天,大家普遍有个感觉:现在的推荐系统越来越“卷”了,但用户好像越来越“挑”了。我们投入大量算力去拟合用户的历史行为,模型越做越复杂,但用户点“不感兴趣”的频率似乎并没有降低。这背后其实是一个根本性的矛盾:静态的、被动的推荐模型,如何去理解动态的、主动的用户意图?
这让我开始关注一个正在从学术界走向工业界的前沿方向:Agentic Recommendation Systems(智能体驱动的推荐系统)。这个项目标题——“Entropy Guided Diversification and Preference Elicitation in Agentic Recommendation Systems”——恰好精准地戳中了这个领域的两个核心痛点:如何主动探索用户未知的兴趣(偏好启发),以及如何在探索与利用之间找到最佳平衡(熵引导的多样化)。简单来说,它探讨的是如何让推荐系统从一个“被动的历史记录分析员”,转变为一个“主动的、会聊天的购物顾问”。
想象一下这个场景:你打开一个音乐App,它不再只是根据你上周听的歌单给你推类似的歌。它会像一个懂音乐的朋友一样问你:“今天是想发现点新风格,还是继续听你喜欢的乐队?” 当你选择“想试试新的”,它可能会先给你几首风格迥异的歌曲片段(高熵、高多样性),然后观察你的反应。如果你对其中一首布鲁斯风格多听了几秒,它就会捕捉到这个信号,接着问:“看来你对这种带点忧郁的吉他旋律感兴趣?我这儿还有一些融合了爵士的布鲁斯,要不要听听看?” 这个过程,就是Preference Elicitation(偏好启发)与Entropy Guided Diversification(熵引导的多样化)在协同工作。
而最近在技术社区里被频繁讨论的“solr available entropy is low”这个热词,虽然源自具体的搜索引擎(Solr)日志告警,但它背后反映的“熵值过低”问题,恰恰是传统推荐系统陷入“信息茧房”的技术表征——系统可用的、能带来信息增益的“不确定性”(熵)太低了,导致推荐结果越来越同质化。我们这个项目要解决的,就是如何系统性地注入和利用“熵”,打破这个僵局。
所以,这篇文章,我想从一个一线实践者的角度,深入拆解这个项目标题背后的技术逻辑、实现路径以及那些在论文里可能不会写的“坑”。无论你是正在构建下一代交互式推荐产品的工程师,还是对强化学习、信息论在推荐场景应用感兴趣的研究者,希望这些来自实战的思考能给你带来一些启发。
2. 核心理念拆解:为什么需要“智能体”与“熵”?
在深入技术细节之前,我们必须先统一思想:为什么传统的推荐范式不够用了?以及“熵”在这里到底扮演什么角色?
2.1 从被动响应到主动会话:智能体推荐系统的范式转移
传统的推荐系统,无论是协同过滤还是深度学习模型,本质都是一个“静态映射函数”。输入是用户-物品交互历史,输出是一个得分排序列表。它的核心假设是:用户偏好是静态的、可以从历史中完全归纳的。但现实是,用户偏好是情境化的、动态演化的、且常常无法自我完全认知的。
Agentic Recommendation System引入了一个根本性的改变:将推荐系统建模为一个智能体。这个智能体与用户处于一个连续的交互循环中,其目标不是一次性预测得分,而是通过一系列动作(如展示一组物品、提出一个问题)来最大化长期的用户满意度或商业目标。这构成了一个典型的序列决策问题,非常适合用强化学习框架来建模。
在这个框架下:
- 状态:是当前对用户偏好的估计以及交互上下文。
- 动作:是推荐系统可以采取的操作,例如“推荐列表A”、“询问你对属性X的偏好”。
- 奖励:是用户的即时反馈(点击、购买、停留时长)或长期价值。
- 策略:就是我们要学习的模型,它根据当前状态决定采取什么动作。
Preference Elicitation就是这个智能体的关键动作之一。与其猜测用户可能喜欢什么,不如设计巧妙的交互来“问”出来。这可以是非常直接的(“你喜欢动作片还是喜剧片?”),也可以是隐式的(通过观察用户在一组多样化推荐中的反应来推断)。
2.2 熵:衡量不确定性与多样性的统一标尺
“熵”这个概念来自信息论,本质是衡量一个系统的不确定性或信息含量。在推荐系统中,熵可以从两个层面理解,而这正是项目标题中“Entropy Guided”的精妙之处:
模型认知的不确定性:在贝叶斯或概率推荐模型中,系统对用户是否喜欢某个物品的预测不是一个确定值,而是一个概率分布。这个分布的方差或熵,就代表了系统对该预测的“不确定程度”。高熵意味着系统“心里没底”,这恰恰是需要通过探索(Exploration)来获取信息的地方。
推荐列表的多样性:一个推荐列表的熵,可以衡量其内容的多样性。如果推荐的10个物品都属于同一类别,其熵值很低;如果10个物品均匀分布在10个不同类别,其熵值很高。“solr available entropy is low”所警示的,正是系统可推荐候选池的多样性枯竭问题,导致无法给用户提供有信息增量的选择。
“Entropy Guided”的核心思想,就是将这两者统一起来。系统利用对用户偏好的认知熵(哪里不确定)来指导生成推荐列表的呈现熵(如何多样化),从而在单次推荐动作中,同时实现高效的探索和令人满意的用户体验。例如,系统发现对用户“是否喜欢小众独立电影”的认知熵很高,那么它就可以在本次推荐中,提高独立电影在列表中的比例(增加呈现熵),同时观察用户反馈来降低认知熵。
3. 系统架构设计与核心模块
一个完整的、实现熵引导多样化与偏好启发的智能体推荐系统,其架构会比传统系统复杂。下图勾勒了其核心数据流与模块交互,我们可以将其视为一个持续运行的“感知-决策-行动-学习”循环。
graph TD A[用户] -->|交互行为| B[状态追踪器]; B --> C[用户状态表示]; C --> D[认知不确定性估计]; D --> E[熵计算模块]; F[物品池] --> G[多样性计算模块]; G --> E; E --> H[策略网络]; H --> I{决策}; I -->|动作1| J[偏好启发模块]; I -->|动作2| K[推荐列表生成]; J --> L[设计交互问题]; K --> M[实施多样化排序]; L --> A; M --> A; A -->|反馈| N[奖励计算]; N --> O[模型更新]; O --> D; O --> H;下面,我们来拆解图中的几个关键模块。
3.1 状态追踪与不确定性估计模块
这是系统的“感知”部分。目标是将原始的交互数据(点击、购买、评分、甚至鼠标移动)转化为一个动态的、包含不确定性度量的用户状态表示。
常见实现方案:
- 深度概率模型:如使用贝叶斯神经网络或深度高斯过程来建模用户对物品的偏好分数。模型的输出不是单一分数,而是分数的均值和方差。方差直接作为认知不确定性的量化指标。
- 集成学习:训练多个推荐模型(例如不同初始化或子样本训练),用这些模型预测的差异(如标准差)来估计不确定性。这种方法实现相对简单,且能捕捉模型本身的不确定性。
- 上下文Bandit模型:如LinUCB,其内置的上置信界算法本身就包含了不确定性估计。
实操要点:
- 不确定性估计需要校准。一个校准良好的模型,其声称的80%置信区间应当恰好包含80%的真实情况。可以使用负对数似然或Brier分数在验证集上评估校准度。
- 状态表示需要融合短期会话上下文和长期兴趣。通常使用RNN、Transformer或记忆网络来编码当前的会话序列,再与用户长期画像向量拼接。
3.2 熵计算与策略模块
这是系统的“大脑”。它接收状态信息(包含不确定性),并决定下一步行动:是进行显式的偏好启发,还是直接生成推荐列表?如果生成列表,如何平衡多样性和相关性?
策略网络设计:策略通常是一个神经网络,输入是用户状态,输出是动作空间上的概率分布。动作空间的设计是关键:
- 离散动作:例如,{“直接推荐列表A”, “直接推荐列表B”, “询问关于导演的偏好”, “询问关于价格的偏好”}。这种方式简单,但扩展性差。
- 连续动作:更灵活。例如,输出一个“探索权重”向量,用于调整推荐排序分数。或者输出一个“询问主题”的嵌入向量,系统再从中找到最接近的可询问主题。
如何实现“熵引导”?策略的奖励函数需要精心设计,以鼓励熵的合理利用。一个典型的奖励函数可能包含:
- 即时商业奖励:点击率、转化率。
- 长期兴趣探索奖励:基于信息增益。例如,选择那些能最大程度降低系统认知熵的物品或问题进行推荐/询问。
- 多样性奖励:衡量推荐列表的熵(如类别熵、标签熵),避免同质化。
策略的学习通常使用强化学习算法,如:
- 策略梯度方法:适用于连续或离散动作空间。
- 深度Q网络:适用于离散动作空间,需要设计好状态和动作的表示。
- 演员-评论家方法:结合两者优点,更稳定。
3.3 偏好启发模块
这是系统主动获取信息的“嘴”。它的目标是以最小的用户负担,获取能最大程度减少系统不确定性的信息。
启发方式:
- 主动学习式提问:
- 基于池的主动学习:从候选问题池中,选择那些模型最不确定(熵最高)的用户-问题对进行询问。例如,“你对‘科幻喜剧’这个组合感兴趣吗?”
- 基于模型的主动学习:如使用贝叶斯主动学习,直接选择能最大化期望信息增益的问题。
- 交互式排序与探索:
- 混合列表:在推荐列表中,混入少量高不确定性但可能高信息增益的物品,并观察用户的交互(如跳过、点击详情)。
- 分面浏览:引导用户通过筛选器(如价格区间、风格标签)来主动表达偏好,系统记录其选择路径。
设计原则:
- 问题要具体且易于回答。避免“你喜欢什么音乐?”这种宽泛问题,而是问“你喜欢节奏强的电子乐还是舒缓的古典乐?”
- 控制交互频率。频繁提问会严重干扰用户体验。策略网络需要学会在“信息价值”和“用户耐心”之间权衡。通常可以设置一个“询问预算”,或者将提问的负反馈(如用户忽略或关闭弹窗)作为一个负奖励。
- 利用多臂老虎机思想:将不同的提问策略或问题类型视为不同的“臂”,通过汤普森采样等算法动态选择最优的提问方式。
3.4 多样化推荐列表生成模块
这是系统的“手”,负责将策略的决策落地为最终呈现给用户的列表。
经典方法回顾:
- 最大边际相关性:贪心地选择与已选列表相似度最低,但与用户相关性最高的物品。
- 基于DPP的方法:将列表生成建模为行列式点过程,能同时保证质量和多样性,但计算复杂度高。
- 重排序:先用基础模型生成一个相关性的长列表,再用一个专门的多样化模型进行重排序。
“熵引导”的融入:我们的目标不是单纯追求高多样性,而是追求有信息价值的多样性。具体做法:
- 构建多目标排序函数:
最终分数 = α * 相关性分数 + β * 多样性分数 + γ * 信息增益分数其中,信息增益分数可以直接用该物品能带来的预期认知熵减少量来估算。 - 使用强化学习直接生成列表:将生成一个长度为K的列表视为一个序列决策问题(每一步选一个物品),使用策略梯度方法进行端到端优化,奖励函数中包含列表的整体信息增益。
- 基于不确定性的采样:在生成候选列表时,不仅考虑预测的均值(期望偏好),还考虑方差。可以按照
均值 + λ * 标准差的方式进行采样,其中λ是一个控制探索强度的超参数。
4. 核心算法实现与工程化细节
理论很美好,但落地到代码和线上系统,才是真正的挑战。这里我分享一个基于深度强化学习框架的实现思路和关键代码片段。
4.1 基于深度确定性策略梯度的连续控制策略
对于连续动作空间(如输出一个探索权重向量),DDPG是一个不错的选择。我们定义一个Actor网络来输出动作,一个Critic网络来评估状态-动作对的价值。
状态表示:
import torch import torch.nn as nn import torch.nn.functional as F class StateEncoder(nn.Module): def __init__(self, user_feat_dim, item_seq_dim, hidden_dim): super().__init__() # 长期兴趣编码 self.user_encoder = nn.Linear(user_feat_dim, hidden_dim) # 短期会话编码(使用GRU) self.session_encoder = nn.GRU(item_seq_dim, hidden_dim, batch_first=True) # 不确定性估计层(假设我们通过集成学习得到每个物品类别的预测方差) self.uncertainty_encoder = nn.Linear(num_categories, hidden_dim) def forward(self, user_feat, session_seq, category_uncertainty): user_rep = F.relu(self.user_encoder(user_feat)) _, session_rep = self.session_encoder(session_seq) # 取最后一个隐藏状态 session_rep = session_rep.squeeze(0) unc_rep = F.relu(self.uncertainty_encoder(category_uncertainty)) # 融合状态 combined_state = torch.cat([user_rep, session_rep, unc_rep], dim=-1) return combined_stateActor网络(策略网络):
class ActorNetwork(nn.Module): def __init__(self, state_dim, action_dim, hidden_dim=256): super().__init__() self.fc1 = nn.Linear(state_dim, hidden_dim) self.fc2 = nn.Linear(hidden_dim, hidden_dim) self.fc3 = nn.Linear(hidden_dim, action_dim) # 输出探索权重向量,维度=物品特征维度或类别数 # 使用Tanh将输出限制在[-1, 1],再映射到合适的范围 self.tanh = nn.Tanh() def forward(self, state): x = F.relu(self.fc1(state)) x = F.relu(self.fc2(x)) action = self.tanh(self.fc3(x)) # 例如,action在[-1,1],表示对各个维度的加强或减弱探索 return action动作执行:Actor网络输出的动作是一个连续向量,我们需要将其转化为实际的推荐列表。一种方法是修改排序分数:
def generate_ranked_list(user_embedding, candidate_items, actor_action): """ user_embedding: 用户向量 candidate_items: 候选物品矩阵,每行是一个物品的特征向量 actor_action: Actor网络输出的动作向量,与物品特征同维或与类别同维 """ # 1. 计算基础相关性分数(内积或神经网络) base_scores = torch.matmul(candidate_items, user_embedding.T).squeeze() # 2. 计算信息增益分数(这里用不确定性作为代理,假设每个物品有一个不确定性分数unc_score) # unc_score可以从不确定性估计模块获得 info_gain_scores = candidate_items_uncertainty # 高不确定性物品,信息增益潜力大 # 3. 计算多样性惩罚(与已选列表的相似度) # 这是一个简化的贪心算法示例 selected_indices = [] final_scores = [] for _ in range(top_k): # 对于每个候选物品,计算其与已选物品的最大相似度 diversity_penalty = torch.zeros(len(candidate_items)) if selected_indices: selected_features = candidate_items[selected_indices] # 计算余弦相似度 sim = torch.matmul(candidate_items, selected_features.T).max(dim=1).values diversity_penalty = sim # 相似度越高,惩罚越大 # 4. 融合分数:actor_action[0]控制相关性权重,actor_action[1]控制信息增益权重 # 这里假设actor_action是二维的,实际维度可根据需要设计 combined_scores = (actor_action[0] * base_scores + actor_action[1] * info_gain_scores - (1 - actor_action[0] - actor_action[1]) * diversity_penalty) # 选择分数最高的物品 # 注意:需要屏蔽已选物品 combined_scores[selected_indices] = -float('inf') chosen_idx = combined_scores.argmax().item() selected_indices.append(chosen_idx) final_scores.append(combined_scores[chosen_idx].item()) return selected_indices, final_scores4.2 偏好启发的具体实现:基于信息增益的主动提问
假设我们有一个可提问的属性集合,例如电影的风格、导演、年代。我们需要选择一个问题,使得提问后的预期信息增益最大。
import numpy as np from scipy.stats import entropy def select_best_question(user_state, question_pool, preference_model): """ 基于期望信息增益选择问题。 user_state: 当前用户状态 question_pool: 可提问的问题列表,每个问题对应一个属性(如‘genre’) preference_model: 预测用户偏好的概率模型 """ best_gain = -np.inf best_question = None for q in question_pool: attr = q['attribute'] possible_values = q['possible_values'] # 例如,对于‘genre’,可能是[‘action', 'comedy', 'drama'] # 计算当前系统对该属性各值的偏好分布熵(认知不确定性) current_probs = [] for val in possible_values: # 使用模型预测用户喜欢具有该属性值的物品的概率 prob = preference_model.predict_prob(user_state, attr, val) current_probs.append(prob) current_probs = np.array(current_probs) current_probs = current_probs / current_probs.sum() # 归一化 current_entropy = entropy(current_probs) # 计算提问后的期望熵 expected_entropy = 0.0 for val in possible_values: # 假设用户回答该值的概率即为当前预测概率 prob_answer = current_probs[possible_values.index(val)] # 模拟用户回答后的后验分布(这里简化处理,实际需用贝叶斯更新) # 假设用户选择val后,该值的概率提升,其他值概率降低 new_probs = current_probs.copy() new_probs[possible_values.index(val)] *= 2 # 强化 new_probs = new_probs / new_probs.sum() new_entropy = entropy(new_probs) expected_entropy += prob_answer * new_entropy # 信息增益 = 当前熵 - 期望熵 info_gain = current_entropy - expected_entropy if info_gain > best_gain: best_gain = info_gain best_question = q return best_question, best_gain4.3 工程化中的挑战与应对
在线学习与探索的风险:直接在线上用真实用户做探索,可能带来糟糕的体验和商业损失。
- 应对:采用Bandit算法或离线策略评估与学习。先在小流量(如1%的用户)上进行探索,或使用历史日志数据构建模拟器,在模拟环境中预训练策略。
动作空间巨大:推荐列表的组合空间是指数级的,连续动作空间也维度很高。
- 应对:使用分层策略或课程学习。先学习粗粒度动作(如决定本次推荐的主题倾向),再学习细粒度动作(如具体物品排序)。或者使用近端策略优化等更稳定的RL算法。
奖励稀疏与延迟:用户购买等核心奖励非常稀疏,且长期价值反馈延迟。
- 应对:设计稠密的代理奖励。例如,将点击、停留时长、页面浏览深度、甚至鼠标移动轨迹等中间行为设计为奖励信号。同时,使用优势演员-评论家等方法处理延迟奖励。
实时性要求:推荐系统要求毫秒级响应。
- 应对:策略网络离线推理,在线服务。将训练好的Actor网络导出为高性能服务,在线部分仅进行前向传播。复杂的熵计算和候选物品生成可以异步进行。
5. 评估体系与效果衡量
引入智能体和探索机制后,评估不能只看最终的CTR或GMV,需要一套更全面的指标体系。
5.1 核心评估维度
| 评估维度 | 具体指标 | 说明 |
|---|---|---|
| 推荐质量 | 点击率、转化率、人均观看时长 | 商业核心指标,需保证不下降。 |
| 探索效率 | 新品类/长尾物品的曝光与转化率、用户兴趣标签的丰富度 | 衡量系统打破信息茧房、发现新兴趣的能力。 |
| 系统不确定性 | 用户偏好模型预测的平均方差/熵 | 监控系统对用户认知的整体不确定性是否在健康下降。 |
| 交互体验 | 偏好启发问题的应答率、用户主动跳过推荐的比例、会话长度 | 衡量交互的自然度和用户接受度。 |
| 长期价值 | 用户留存率、长期活跃度、生命周期总价值 | 最终目标,验证系统是否能提升用户的长期满意度。 |
5.2 A/B测试设计要点
由于引入了探索和主动交互,A/B测试需要特别设计:
- 分组策略:实验组(使用智能体策略)和对照组(传统推荐策略)的用户必须随机分配,且保证长期追踪同一用户。
- 观察周期要长:探索带来的长期价值增益可能在短期内无法体现,甚至短期指标会略有下降(因为展示了更多不确定的内容)。测试周期应至少持续数周甚至数月。
- 分析细分群体:分析新用户、老用户、活跃用户、沉默用户等不同群体在实验中的表现差异。智能体系统对新用户和兴趣探索期用户可能收益最大。
- 监控探索成本:密切关注实验组中因探索导致的次优推荐比例,确保其在可控范围内。
6. 避坑指南与实战心得
在研究和尝试这类系统的过程中,我们踩过不少坑,也积累了一些未必写在论文里的经验。
坑一:把“熵”当成万能灵药,盲目追求高多样性。
- 现象:为了提升推荐列表的熵,系统开始推荐大量完全不相关的物品,用户体验骤降。
- 根因:只优化了呈现熵,没有与用户相关性进行约束。
- 解法:永远将相关性作为基础约束。在排序公式中,相关性分数的权重必须占主导(例如α>0.7),熵或信息增益作为“微调”因子。可以设置一个相关性阈值,只有高于阈值的候选物品才参与多样化排序。
坑二:偏好启发问题惹人烦。
- 现象:系统频繁弹出问题,用户感到被打扰,直接关闭页面。
- 根因:策略网络没有学会在合适的时机提问,或者问题设计得过于生硬。
- 解法:
- 设计优雅的交互:将问题融入自然交互流程。例如,在用户进行筛选或搜索时,顺势推荐几个相关筛选选项;在播放列表结束时,以“猜你喜欢”的形式给出两个风格迥异的选项让用户选择。
- 设置冷却机制:强制规定两次显式提问之间的最小时间间隔或会话步数。
- 奖励设计加入负反馈:将用户忽略或快速关闭提问界面的行为记为负奖励,让策略网络学会“察言观色”。
坑三:强化学习训练不稳定,难以收敛。
- 现象:策略表现时好时坏,训练曲线震荡剧烈。
- 根因:推荐场景的状态和奖励非常复杂,直接端到端训练RL策略非常困难。
- 解法:
- 模仿学习预热:先用历史日志中的优秀决策(可视为专家轨迹)对策略网络进行监督预训练,提供一个好的初始点。
- 世界模型模拟器:尝试构建一个用户行为模拟器,在模拟环境中进行大量低成本训练,再将策略迁移到线上。
- 从简单场景开始:不要一开始就做全量推荐。可以先在“猜你喜欢”模块、或“新用户冷启动”场景应用,这些场景状态相对简单,更容易成功。
坑四:线上服务延迟超标。
- 现象:引入复杂的熵计算和RL策略推理后,推荐接口响应时间从10ms增加到50ms以上。
- 根因:实时计算信息增益和多样性排序开销大。
- 解法:
- 预计算与缓存:对物品的信息增益分数进行离线预计算和周期性更新。对常见的用户状态分区,可以缓存其对应的Top-N动作或推荐列表。
- 两阶段检索:第一阶段用轻量级模型快速检索出上千候选,第二阶段再用复杂的智能体策略对百量级候选进行精排和重排。
- 模型蒸馏与量化:将大型的策略网络蒸馏为更小的网络,或使用量化技术降低推理耗时。
7. 未来展望与进阶思考
虽然这个领域挑战重重,但其代表的方向——构建与用户共同成长、具备对话能力的推荐系统——无疑是下一代推荐技术的核心。在项目实践中,我们还可以向更深处探索:
多模态偏好启发:目前的偏好启发多基于文本标签。未来可以结合视觉、语音甚至多轮对话。例如,让用户圈出图片中喜欢的部分,或者说“我想要像这样的,但颜色更亮一点”。
用户心智模型与可解释性:智能体不仅要知道用户喜欢什么,还要尝试理解“为什么”。构建可解释的用户心智模型,能让系统的探索和提问更具说服力。例如,系统可以告诉用户:“因为我发现你喜欢A和B,它们都有‘强节奏’和‘电子音效’的特点,所以尝试推荐了C,你觉得如何?”
社会性与群体智能:引入社交关系,探索如何通过观察用户在小群体中的行为,来更好地启发个人偏好,或者进行群体推荐。
与生成式AI的结合:利用大语言模型强大的自然语言理解和生成能力,来设计更自然的对话式偏好启发流程,甚至直接生成个性化的物品描述或推荐理由。
这条路还很长,但每一次让推荐系统更懂用户一点,每一次成功地帮助用户发现意料之外的惊喜,所带来的价值感,正是驱动我们不断探索的动力。从“熵”开始,让推荐系统不再只是流量的分配器,而真正成为用户探索世界的智能伙伴。