1. 项目概述
作为一名长期从事推荐系统开发的工程师,我最近完成了一个基于深度学习的个性化携程美食推荐系统。这个项目让我深刻体会到,在旅游场景下做好美食推荐远比想象中复杂——不仅要考虑用户的口味偏好,还要结合行程安排、地理位置、消费水平等多维因素。
传统的美食推荐系统往往只关注"用户-物品"的二维关系,而旅游场景下的美食推荐需要处理更复杂的时空维度。比如,用户中午在景区游玩时可能想要快捷的当地小吃,晚上回酒店后则更倾向正餐;商务旅客和家庭游客的饮食需求也截然不同。这正是我们选择深度学习技术的原因——它能更好地捕捉这些非线性、高维度的特征关联。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 整体技术栈选型
经过多次技术论证,我们最终确定了以下技术方案:
前端:Vue.js + Element UI
- 选择理由:组件化开发效率高,Element UI提供了丰富的表单和表格组件,非常适合管理后台开发
- 实际使用中发现:需要特别注意Vuex的状态管理,当用户频繁切换页面时,推荐结果的缓存策略直接影响用户体验
后端:Django + Django REST framework
- 版本选择:Python 3.8 + Django 3.2
- 特别配置:启用了Django的异步视图(async views)来处理高并发的推荐请求
- 经验之谈:在开发中期我们发现,直接使用Django ORM处理大规模用户行为数据时性能堪忧,后来引入了Django的select_related和prefetch_related进行优化
数据库:MySQL 5.7 + Redis
- MySQL配置:采用了InnoDB集群部署,字符集统一为utf8mb4以支持emoji评论
- Redis作用:用于缓存热门美食数据和用户特征向量,将推荐响应时间从800ms降低到200ms以内
2.2 深度学习模型选型
我们对比了多种深度学习模型后,最终选择了LSTM+Attention的混合架构:
python复制class RecommendationModel(nn.Module):
def __init__(self, user_dim, item_dim, hidden_size):
super().__init__()
self.user_embedding = nn.Embedding(num_users, user_dim)
self.item_embedding = nn.Embedding(num_items, item_dim)
self.lstm = nn.LSTM(item_dim, hidden_size, batch_first=True)
self.attention = nn.Sequential(
nn.Linear(hidden_size, hidden_size),
nn.Tanh(),
nn.Linear(hidden_size, 1, bias=False)
)
self.fc = nn.Linear(hidden_size + user_dim, num_items)
def forward(self, user_ids, item_seqs):
user_emb = self.user_embedding(user_ids)
item_emb = self.item_embedding(item_seqs)
lstm_out, _ = self.lstm(item_emb)
attn_weights = F.softmax(self.attention(lstm_out), dim=1)
context = (attn_weights * lstm_out).sum(dim=1)
combined = torch.cat([context, user_emb], dim=1)
return self.fc(combined)
这个模型的关键创新点在于:
- 使用LSTM捕捉用户行为序列的时序特征
- 引入Attention机制让模型能够关注关键历史行为
- 将用户静态特征(如 demographics)与动态行为特征融合
实际训练中发现:当用户行为序列长度超过50时,模型效果提升不明显但计算成本显著增加。最终我们将序列长度截断到最近的30个行为。
3. 核心功能实现
3.1 用户行为数据采集
我们设计了多维度的事件埋点方案:
| 事件类型 | 采集字段 | 用途说明 |
|---|---|---|
| 浏览 | 美食ID, 停留时长, 滚动深度 | 计算兴趣权重 |
| 收藏 | 美食ID, 收藏时间 | 强偏好信号 |
| 下单 | 订单ID, 美食列表, 价格 | 转化率分析 |
| 评价 | 评分, 文字内容, 图片 | 情感分析 |
python复制# 埋点数据示例
{
"user_id": "u12345",
"event_type": "view",
"item_id": "f67890",
"timestamp": "2023-07-15T14:30:00Z",
"duration": 45, # 停留秒数
"position": {"lat": 31.2304, "lng": 121.4737}, # 用户位置
"device": "iOS/15.5"
}
3.2 实时推荐引擎
推荐系统架构分为离线训练和在线服务两部分:
离线训练流程:
- 每天凌晨从Hadoop导出用户行为数据
- 使用Spark进行特征工程
- 训练PyTorch模型并导出参数
- 将模型部署到TensorFlow Serving
在线服务流程:
- 用户请求到达API网关
- 从Redis获取用户最近行为
- 实时计算推荐分数
- 结合业务规则过滤(如营业时间、地理位置)
- 返回个性化推荐列表
python复制def generate_recommendations(user_id, location=None, top_k=10):
# 获取用户特征
user_feature = get_user_features(user_id)
# 获取候选集
candidates = get_nearby_items(location) if location else get_top_items()
# 实时预测
scores = model.predict(user_feature, candidates)
# 业务规则过滤
filtered = apply_business_rules(candidates, scores)
# 多样性控制
return diversify(filtered[:top_k*3])[:top_k]
重要经验:在线服务必须做好超时控制和降级策略。当推荐模型响应超时(我们设置为300ms)时,会自动切换基于热榜的兜底推荐。
4. 效果优化与AB测试
4.1 关键指标定义
我们建立了多层次的评估体系:
离线指标:
- AUC: 0.82 → 0.89 (经过3个月优化)
- Recall@10: 从0.15提升到0.23
在线指标:
- 点击率(CTR): 提升35%
- 下单转化率: 提升28%
- 用户停留时长: 增加42%
4.2 特征工程优化
经过多次迭代,最终保留的核心特征包括:
用户特征:
- 基础属性:年龄、性别、职业
- 行为统计:7日/30日浏览次数、收藏率
- 偏好标签:菜系偏好、价格敏感度
美食特征:
- 静态特征:菜系、价格段、辣度
- 动态特征:近期销量、评分趋势
- 时空特征:与用户当前位置距离、是否在营业
交互特征:
- 用户历史相似行为
- 协同过滤相似用户偏好
4.3 AB测试方案
我们设计了分阶段的测试方案:
| 测试阶段 | 分组 | 样本量 | 持续时间 | 主要发现 |
|---|---|---|---|---|
| 初版 | 全量 | 100% | 2周 | 新用户效果差 |
| V1 | 50% | 50% | 3周 | 加入位置特征提升18% CTR |
| V2 | 20% | 20% | 4周 | 价格敏感度特征带来7%转化提升 |
5. 部署与性能调优
5.1 服务部署架构
最终的生产环境部署方案:
code复制用户请求 → Nginx(负载均衡) →
→ Django应用集群(8核16G × 4)
→ TensorFlow Serving(GPU P4 × 2)
→ Redis集群(16G × 3)
→ MySQL集群(主从复制)
5.2 关键性能优化
-
模型轻量化:
- 将原始1.2GB的模型通过知识蒸馏压缩到300MB
- 使用TensorRT加速,推理时间从120ms降到45ms
-
缓存策略:
- 用户特征缓存:TTL=15分钟
- 热门美食缓存:TTL=1小时,LRU策略
- 使用Redis管道(pipeline)批量获取数据
-
数据库优化:
- 为行为表添加复合索引(user_id, timestamp)
- 对大表进行分库分表(按user_id哈希分片)
python复制# 缓存装饰器示例
def cache_user_features(ttl=15*60):
def decorator(func):
@wraps(func)
def wrapper(user_id):
cache_key = f"user:{user_id}:features"
data = redis.get(cache_key)
if data:
return json.loads(data)
result = func(user_id)
redis.setex(cache_key, ttl, json.dumps(result))
return result
return wrapper
return decorator
6. 典型问题排查
在实际运行中,我们遇到了几个棘手问题:
问题1:新用户冷启动效果差
- 现象:新用户首屏点击率只有老用户的30%
- 解决方案:
- 引入基于内容的相似推荐
- 添加热门榜单作为兜底
- 使用人口统计学特征填充
- 效果:新用户CTR提升至老用户的85%
问题2:位置漂移导致推荐不准
- 现象:用户位置频繁变化时推荐质量下降
- 排查:发现是移动端GPS采样频率设置不合理
- 修复:
- 增加位置平滑算法
- 设置最小移动距离阈值(500米)
- 对历史位置进行聚类去噪
问题3:模型服务内存泄漏
- 现象:TF Serving内存使用量每天增长10%
- 诊断:使用pprof发现是请求日志未及时清理
- 修复:
- 配置日志轮转
- 限制最大日志文件数
- 增加内存监控告警
7. 项目总结与展望
这个项目从技术选型到最终上线历时6个月,期间最大的收获是认识到推荐系统在实际业务中的复杂性远超过理论模型。以下几点经验特别值得分享:
-
特征工程比模型结构更重要:我们尝试了多种复杂模型,最终发现70%的效果提升来自特征优化而非模型结构调整。
-
业务理解是关键:旅游场景下的美食推荐需要考虑时间、位置、行程等多种因素,纯技术方案很难cover所有场景。
-
系统健壮性不容忽视:推荐系统作为核心业务链路,必须设计完善的降级策略和监控体系。
未来我们计划在以下方向继续优化:
- 引入图神经网络挖掘用户-美食-地点的高阶关系
- 尝试多任务学习同时优化点击率和停留时长
- 开发可解释性模块增强用户信任度
整个项目中最让我自豪的是,系统上线后用户的美食订单量提升了40%,这证明技术确实能为业务创造真实价值。如果你也在开发推荐系统,欢迎交流实践中遇到的挑战和解决方案。
