资讯动态

Python智能推荐算法在全屋定制平台的设计与实践

发布时间:2026/10/16 2:16:01 来源:尧图企业网站定制
1. 项目概述与核心需求拆解1.1 这个项目到底在解决什么问题接到Python基于智能推荐算法的全屋定制平台这个项目需求时我第一反应是这不就是又一个电商网站套了个推荐模块吗但真正梳理完需求才发现全屋定制和普通电商的推荐逻辑完全是两码事。全屋定制行业有个很特殊的地方——它是一个重度决策、低频消费、高客单价的领域。用户在电商平台买件衣服从浏览到下单可能只要几分钟但定制一套橱柜或全屋家具用户往往要反复对比几十个方案考虑材质、空间尺寸、风格搭配、预算上限甚至还要和设计师来回沟通好几轮。这种场景下如果平台只是简单给用户推你可能喜欢的产品基本没什么用。用户真正需要的是我的户型适合什么风格我这个预算能做哪些组合别人家的同户型方案是怎么设计的。所以我给这个项目定下的核心方向是做一套以房型数据和用户偏好为核心输入、以整体空间方案而非单品为推荐单元的智能推荐系统。平台的数据模型不只是用户—商品的二元关系而是用户—房型—空间—方案—单品的多层嵌套关系。1.2 项目代号与范围说明项目代号用了07y1pcxm作为内部标识这个代号在整个项目文档、数据库表前缀和接口路由里都保留着方便团队成员引用。项目本身覆盖了几个大模块前台用户端房型录入、方案浏览、智能推荐、在线预约设计师后台管理端商品管理、方案管理、用户行为日志查看推荐引擎服务独立部署的推荐服务负责从用户行为、房型数据、风格标签中计算推荐结果后面的正文我会围绕推荐系统的设计与实现展开把完整的搭建思路和踩过的坑都写清楚。如果你手头也在做类似的平台类项目这套设计思路可以直接迁移过去。2. 推荐算法选型与核心设计思路2.1 为什么不能用传统电商的协同过滤最早我们用的是业界最常见的 ItemCF物品协同过滤——先算物品相似度再根据用户历史行为推荐相似物品。跑了一轮离线评测结果很惨精确率不到 12%推荐出来的东西用户点击率很低。原因也简单。全屋定制场景有三高一低的特征特征对推荐算法的影响高客单价用户决策周期长行为数据稀疏高定制化每个用户的需求差异大很难用别人买了什么推断高关联性用户要的是整体空间方案不是孤立单品低购买频次一个用户一生可能就定制一两次历史行为几乎为零协同过滤的本质是物以类聚人以群分它依赖大量历史行为数据。但全屋定制用户的行为太稀疏了尤其是新用户来到平台往往连一条浏览记录都没有。这时候协同过滤就成了无源之水。2.2 基于内容与规则混合的推荐策略最终我采用了一套**基于内容的推荐Content-Based 规则引擎 协同过滤补位**的混合方案第一层基于内容的匹配。用户录入自己的房型比如三室一厅、建筑面积 120 平米和风格偏好比如现代简约系统从方案库中提取特征向量计算相似度优先推荐与用户画像匹配的方案。第二层规则约束。全屋定制有硬性规则限制。比如一个 8 平米的厨房台面长度不能超过 4.5 米预算 3 万以内就不能推荐用进口岩板的方案。这些规则必须在推荐之前过滤掉否则推荐结果再精准用户也没法下单。第三层协同过滤补位。当用户行为积累到一定程度比如收藏了 5 个以上方案引入 ItemCF 做个性化扩展。用户看中了某个现代风格的客厅方案系统会找到同风格、同户型、预算相近的其他方案推荐。这套混合方案的推荐命中率用户在推荐位点击且停留超过 30 秒的比例提升到了 37% 左右效果还算理想。2.3 房型数据的特征工程处理推荐效果的差距很大程度上取决于特征工程。在全屋定制场景里最核心的特征就是房型数据。怎么把三室一厅 120 平米变成一个算法能计算的向量我做了这么几步数值特征建筑面积、客厅面积、卧室数量、卫生间数量、阳台数量类别特征户型结构横厅/竖厅/方厅、采光朝向南/北/东西、装修风格现代/北欧/中式/轻奢文本特征把户型描述文本用 TF-IDF 做向量化比如喜欢开放式厨房需要老人房无障碍设计2.4 为什么选择 Python 技术栈技术选型上Python 算是这个项目的最优解。推荐算法的原型验证、特征处理、模型调参Python 的生态实在方便——pandas 处理表格数据scikit-learn 算相似度Flask 起服务基本上一个人两天就能把推荐服务的骨架搭完。从项目交付的角度Python 也降低了后续维护门槛团队里任何一个人都能快速接手。当然Python 在性能上不如 Go 或 Java但推荐服务的 QPS 本来就不高这个平台日均 UV 也就几千瓶颈根本不在语言层面。我测过单机 Flask numpy 的推荐服务单次推荐请求响应时间在 120ms 左右完全够用。3. 系统架构与核心模块实现3.1 整体架构分层整个平台采用的是前后端分离 独立推荐服务的设计。前端是常规的单页应用后端提供 RESTful 接口推荐引擎独立成一个微服务。顶层架构分四层数据层MySQL 存业务数据Redis 存缓存和实时行为日志向量特征单独存成 numpy 二进制文件定期加载。业务服务层用户管理、商品管理、订单管理这一层是常规的 Web 后端。推荐服务层独立部署的推荐引擎对外提供/api/recommend接口。前端展示层用户录入户型、浏览推荐结果、与设计师沟通。这种分层最大的好处是推荐逻辑可以独立迭代。我调算法参数的时候不需要重新部署整个后端改完推荐服务单独重启就行。再加上推荐服务挂了也不影响用户浏览商品——这很重要推荐只是辅助功能不能成为系统瓶颈。3.2 数据库模型设计数据库设计是这个项目最花时间的地方之一。全屋定制平台的核心实体有用户、房型、方案、商品家具单品、设计师、预约单。其中方案这个实体很关键——它不是简单地把几个商品放一起而是包含了一整套空间设计数据平面布局图、效果图、商品清单、总价、适配房型 ID。核心数据表结构如下-- 用户表 CREATE TABLE user ( id int PRIMARY KEY AUTO_INCREMENT, nickname varchar(50), phone varchar(20), province varchar(20), city varchar(50), created_at datetime ); -- 房型表 CREATE TABLE house_type ( id int PRIMARY KEY AUTO_INCREMENT, user_id int, area_total float, room_count int, living_count int, bathroom_count int, layout_type varchar(20), orientation varchar(10), style_preference varchar(20), budget_range float, description text ); -- 设计方案表 CREATE TABLE design_scheme ( id int PRIMARY KEY AUTO_INCREMENT, title varchar(100), style_tag varchar(20), suitable_area_min float, suitable_area_max float, suitable_room varchar(20), total_price float, cover_image varchar(200), designer_id int, view_count int DEFAULT 0 ); -- 方案-商品关联表 CREATE TABLE scheme_item ( scheme_id int, item_id int, item_count int, scene_tag varchar(20) );设计这套表结构的时候有个教训house_type表一开始没有单独拆出来而是直接存在user表里。后来发现推荐服务和用户系统都需要频繁查房型数据耦合在一起导致接口调用很别扭最后还是拆出来独立建表了。凡是多模块都要用的数据一开始就要独立成表这是这次项目里印象很深的一个原则。3.3 推荐服务的核心代码实现推荐服务是整个项目的核心我拆成三个步骤构建用户画像 → 候选集生成 → 排序输出。第一步构建用户画像。用户录入户型信息后系统将房型参数标准化成一个多维向量import numpy as np def build_user_profile(house_type): 根据房型信息构建用户特征向量 特征维度[面积, 房间数, 卫生间数, 风格编码, 预算等级] style_dict {现代简约: 0, 北欧风: 1, 新中式: 2, 轻奢: 3, 工业风: 4} budget_level 0 if house_type[budget] 200000: budget_level 3 elif house_type[budget] 100000: budget_level 2 elif house_type[budget] 50000: budget_level 1 profile np.array([ house_type[area_total] / 200.0, # 面积归一化 house_type[room_count] / 5.0, # 房间数归一化 house_type[bathroom_count] / 3.0, style_dict.get(house_type[style_preference], 0) / 5.0, budget_level / 3.0 ]) return profile对面积做归一化处理是性能改进的关键点。最初直接用原始面积做向量计算结果 120 平米和 140 平米的方案在欧氏距离上差了很大但其实这两个面积段对用户来说非常接近。归一化之后相似度计算才真正反映了用户感知的差异。第二步候选集生成和相似度计算def compute_similarity(user_profile, scheme_features): 计算用户画像与候选方案特征的相似度 采用加权欧氏距离面积权重 0.3风格权重 0.4预算权重 0.3 weights np.array([0.3, 0.2, 0.1, 0.4, 0.3]) diff (user_profile - scheme_features) * weights sim 1.0 / (1.0 np.sqrt(np.sum(diff**2))) return sim def generate_candidates(user_profile, scheme_list, top_k10): # 先规则过滤面积适配、房间数匹配、预算范围内 candidates [] for s in scheme_list: if s[suitable_area_min] user_profile[0]*200 s[suitable_area_max]: if s[suitable_room] 三室 and user_profile[1]*5 3: candidates.append(s) # 再按相似度排序 scored [(compute_similarity(user_profile, s[feature_vec]), s) for s in candidates] scored.sort(keylambda x: x[0], reverseTrue) return [s for _, s in scored[:top_k]]这里为什么用加权欧氏距离而不是余弦相似度我一开始用的是余弦相似度但效果不理想。原因在于余弦相似度对方向一致敏感但不关心距离大小。在全屋定制的场景里用户说120 平米方案库里一个 60 平米的方案和一个 150 平米的方案有可能和用户画像的余弦相似度一样高但这两个方案对用户来说意义完全不同。加权欧氏距离能更好地表达每个维度上的差距都在什么范围内这反而更符合业务直觉。第三步混合协同过滤补位。当用户的收藏行为超过阈值时启用 ItemCF 扩展推荐def itemcf_recommend(user_id, user_behavior_records, item_similarity_matrix, top_k5): 基于物品协同过滤的扩展推荐 user_behavior_records: {item_id: score} item_similarity_matrix: 预计算的物品相似度矩阵 scores {} for item_id, score in user_behavior_records.items(): similar_items item_similarity_matrix[item_id] for sim_item, sim_val in similar_items.items(): if sim_item not in scores: scores[sim_item] 0 scores[sim_item] sim_val * score sorted_items sorted(scores.items(), keylambda x: x[1], reverseTrue) return [item_id for item_id, s in sorted_items[:top_k]]3.4 规则引擎的设计要点规则引擎是这个项目里容易被低估的模块。推荐算法算得再准如果推荐了一个超出用户预算 3 倍的方案用户只会觉得平台不靠谱。规则的实现不需要复杂的技术就是一个可配置的过滤器链。举几个实际用到的规则面积规则方案适配面积包含用户房型面积预算规则方案总价不超过用户预算的 120%留一点浮动空间风格规则用户未选风格时不限制已选风格时只推荐同风格方案空间规则三室户型必须覆盖客厅、主卧、次卧至少两个空间规则引擎用 Python 的装饰器模式实现每个规则是一个独立函数新增规则只需要添加一个装饰器函数def rule_area_match(func): wraps(func) def wrapper(user_profile, candidate): area user_profile[0] * 200 if not (candidate.suitable_area_min area candidate.suitable_area_max): return None return func(user_profile, candidate) return wrapper如果一个方案被任何一条规则过滤掉推荐列表里就不会出现。这样设计的好处是产品经理后续加了新规则比如2024 年流行奶油风优先展示我只需要新增一个规则装饰器不需要改动推荐主流程。4. 推荐效果评估与调优实录4.1 离线评估先跑通指标推荐系统做完之后不能直接上线就完事了得先做离线评估。我们在方案库中随机抽取了 500 个方案构造了 200 组模拟用户数据从房型面积、风格偏好、预算三个维度模拟真实用户。评估指标我重点看三个指标计算公式本项目实测值精确率PrecisionK推荐列表中用户真实点击的方案数 / K0.41召回率RecallK推荐列表中用户真实点击的方案数 / 用户点击的总方案数0.28覆盖率Coverage被推荐过的方案数 / 方案库总数0.67精确率 0.41 的意思是给用户推荐 10 个方案平均有 4 个是用户会点击甚至预约的。做推荐系统的都知道这个数字在低频消费场景算很不错了。4.2 线上效果一次失败的 A/B 测试离线指标跑得不错但上线前我还是有点不安。推荐系统的惯例是离线指标不等于线上效果我特意搭了一套简单的 A/B 测试把用户分成两组实验组看到的是新版智能推荐对照组看到的是简单的热销榜。跑了一周结果让我有点意外新版推荐位的点击率CTR确实比热销榜高了 18%但用户在平台上的平均停留时长反而下降了 9%。这个结果很反直觉。后来复盘发现了原因推荐太精准了用户很快就找到了自己想要的东西没有经历那种随便逛逛、看看别人家怎么装的探索过程。对全屋定制平台来说用户浏览本身就是一种想获取灵感的行为停留时间长反而意味着用户对平台内容的认可度高。这个案例提醒我一个很重要的道理推荐系统的目标不一定是把所有指标都拉满而是要服务于业务的真实价值。如果平台靠广告变现停留时长就很重要如果平台靠成交转化点击率就很重要。每个平台都应该先想清楚自己的北极星指标是什么。4.3 调参过程记录调参阶段我经历了不少反复。先记录一下最有价值的几组参数实验实验一权重调整对精确率的影响初始权重是我拍脑袋定的面积 0.3房间数 0.2卫生间 0.1风格 0.4预算 0.3离线测试精确率 0.38。后来我把预算权重调高到 0.5风格降到 0.2精确率掉到了 0.31。原因很直接用户嘴上说喜欢某种风格但真到掏钱的时候第一道关卡永远是预算。风格可以在预算满足之后再讲。重新调回风格 0.4、预算 0.3精确率回到 0.39说明初始的权重已经接近一个不错的局部最优了。实验二规则过滤是否应该放在相似度计算之前有一次我调整了流程让规则过滤发生在相似度计算之后结果发现线上用户点击率降了约 15%。原因不难理解如果考虑相似度的那批方案里混入大量不符合规则的结果用户看到的第一屏推荐就失去了针对性。规则前置相当于先把不合适的方案挡在门外相似度排序只是对剩余方案精排。实验三K 值的选择推荐列表长度 K我从 6 调到 10 再调到 15。K15 时点击率明显下降因为用户浏览精力有限超过 8-10 个方案后基本就不往下滑了。K10 和 K8 差不多最终选了 10——给足用户选择空间又不会因为选项过多导致疲劳。4.4 冷启动问题的处理方案全屋定制平台的新用户冷启动是个绕不开的问题。用户刚注册没有任何历史行为推荐系统完全不知道给他推什么。我做了两件事用房型数据做首次画像用户在第一次录入户型信息时我们就认为已经获得了足够的画像特征。因为全屋定制的推荐强依赖物理空间数据房型录入本身就是最强的一次用户意图声明。用地域特征混排兜底如果用户连房型都没填推荐列表就用同省份、同城市的热门方案兜底。比如一线城市的用户默认推荐 90-130 平米的现代简约方案三四线城市的用户默认推荐 110-150 平米的轻奢或新中式方案。数据证明这种粗粒度的画像已经能带来不错的点击率。5. 常见问题与排查技巧实录5.1 推荐结果加载慢的问题上线第二周运营反馈推荐页打开很慢平均要 3 秒以上。排查后发现问题出在候选集生成阶段——每次请求都实时遍历全量方案库计算相似度时又把所有方案的特征向量读了一遍。优化方案很简单缓存 预计算。把方案库的特征向量加载到 Redis 中用户画像不变的情况下缓存推荐结果 30 分钟。同时把规则过滤的结果也缓存下来因为大部分用户的房型参数在短时间内不会变。优化后接口响应时间从 3 秒降到 150ms效果立竿见影。做推荐系统一定要记住能预计算的绝不在线计算能缓存的绝不实时生成。5.2 相似度计算中的维度灾难初期特征工程加了太多维度包括文本向量化后的几十个维度。一开始总觉得特征越多越准确结果排序效果反而变差了。这就是典型的维度灾难——维度越多样本在高维空间里的分布就越稀疏距离计算的区分度会急剧下降。后来做了特征筛选把主特征压缩到 5-8 个核心维度排序效果反而上升了。这个经验很实用做特征工程的第一原则不是越多越好而是越准越好。每个特征入口都要问一句这个特征真的影响用户的定制决策吗5.3 推荐结果太像了的问题测试阶段我们发现推荐列表里的方案同质化严重——10 个方案里有 6 个看起来是同一个风格的同一类型。这个问题来自相似度排序的天然倾向和用户画像最相似的方案往往聚集在一起。解决方式是引入一个简单的多样度惩罚MMRMaximal Marginal Relevance。每次选入一个新方案时不仅看它和用户画像的相似度还看它和已经在推荐列表里的方案的相似度两者做差def mmr_ranking(user_profile, candidates, lambda_val0.7, top_k10): MMR多样度算法 lambda越大越偏向相关度lambda越小越偏向多样度 selected [] remaining candidates[:] while len(selected) top_k and remaining: score_list [] for cand in remaining: related compute_similarity(user_profile, cand.feature_vec) if selected: max_similar max(compute_similarity(cand.feature_vec, s.feature_vec) for s in selected) else: max_similar 0 final_score lambda_val * related - (1 - lambda_val) * max_similar score_list.append((final_score, cand)) score_list.sort(keylambda x: x[0], reverseTrue) selected.append(score_list[0][1]) remaining.remove(score_list[0][1]) return selectedlambda 设为 0.7 时相关度和多样度平衡得最好。上线后用户对推荐位的满意度评分提升了约 20%。5.4 行为数据采集的坑推荐系统的数据依赖用户行为但我们一开始并没有埋点。结果就是系统上线了却拿不到任何用户点击了哪个推荐位的数据——推荐效果根本没法评估。后来紧急补了一套埋点方案在推荐位的每个方案卡片上加上position参数标记是推荐列表的第几个点击事件上报后和推荐请求 ID 关联。这样就能精确统计到推荐了哪些位置、用户点了哪些位置。这件事给了我一个教训埋点应该在推荐系统开发的第一天就做好而不是等系统上线后补。5.5 模型评估中自欺欺人的陷阱做离线评估的时候要特别小心不能拿参与过训练的数据去评估。我第一次评估时直接用了训练集的数据测试模型精确率高得吓人0.78差点以为推荐效果已经完美了。后来对照业务数据才发现模型是在背答案——刚才训练的样本当然能被记住。正确的做法是划分训练集和测试集比如 8:2 随机切分保证测试集里的数据是模型没见过的。再严格一点还可以按时间划分——用前 6 个月的数据训练用后 2 个月的数据测试模拟真实世界的推荐场景。6. 项目交付与扩展思考6.1 当前版本的落地效果从开发到上线这个项目经历了大约 4 个月的时间核心推荐系统上线后跑了两周。目前平台的整体数据大概是这样的推荐位点击率32%37%相比静态热销榜提升约 45%推荐方案预约率9%每 100 次点击约产生 9 次设计师预约用户平均浏览方案数量从 4 个提升到 7.5 个后端接口平均响应时间150ms 左右预约率 9% 是运营团队最看重的指标因为在全屋定制行业预约设计师可以理解为意向客户产生。推荐系统能直接带动这个指标说明它触达的是真实需求而不只是让页面多几个点击。6.2 后续可以做的几个扩展方向现在这套系统只能说完成了 80%还有几个方向值得继续深耕引入图像识别辅助很多用户会在平台上找参考图我就要这种效果。如果让用户直接上传喜欢的装修效果图系统通过图像识别提取风格、配色、家具布局特征画像精度会提升一个量级。协同过滤升级为图神经网络推荐算法目前的协同过滤还是最基础的版本。等到用户行为积累到一定程度可以考虑引入图神经网络建模更复杂的用户—方案—设计师交互关系。价格弹性和敏感度分析现在预算是一个硬编码的规则约束。实际上不同用户的预算弹性差异很大有些用户说 20 万预算但对质量和风格更在意有些用户说 20 万就真的是 19 万都不行。分析用户的预算弹性可以让推荐结果更贴近真实。6.3 给同行的几点建议这个项目做完有几个体会是拿真金白银换来的写在这里供参考推荐效果不要只看点击率。点击率高可能只是说明用户好奇并不代表他愿意下单。全屋定制这种行业预约、询价、到店才算有效转化。技术要服务业务目标。我们最后把推荐系统的核心指标定义为预约率而不是点击率整个优化方向才真正聚焦。可控性比算法先进更重要。推荐逻辑里留下人工干预的入口运营活动可以临时置顶某些方案这种灵活性在业务初期尤为重要。过度依赖纯算法运营会觉得系统不可控反过来会阻碍推荐系统的落地。关于整个项目我自己最大的收获倒不是技术层面的而是意识到推荐系统在全屋定制这类垂直领域真正的挑战在于如何把行业知识结构化、规则化、可计算化。算法本身并不神秘难的是理解行业的每一个隐性规则然后把它一点点拆成代码能理解的特征和约束。如果你也在做类似的行业平台希望这套思路能帮你少走一些弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑