HarmonyOS 6.1 全场景实战|《灵犀厨房》实战(番外篇):【AI 推荐】场景优先的智能推荐引擎——从“偏好不可靠“到“食材即真理“

📅 2026/6/24 2:18:16
HarmonyOS 6.1 全场景实战|《灵犀厨房》实战(番外篇):【AI 推荐】场景优先的智能推荐引擎——从“偏好不可靠“到“食材即真理“
HarmonyOS 6.1 全场景实战《灵犀厨房》实战番外篇【AI 推荐】场景优先的智能推荐引擎——从偏好不可靠到食材即真理摘要上一篇我们为《灵犀厨房》接入了 AI 食材识别用户拍照即可识别冰箱里的蔬菜肉类。但推荐结果却让人哭笑不得明明识别出西兰花、白菜推荐列表却全是青椒肉丝、脆皮五花肉、酱骨架——用户偏好标签高蛋白完全绑架了推荐逻辑本篇我们将重构推荐引擎的核心算法建立场景优先偏好辅助的评分体系通过食材分类表、类型一致性检查、偏好冲突检测三大机制让推荐结果真正贴合用户的实际烹饪场景。一、引言当 AI 识别遇上用户偏好经过前 19 篇的积累《灵犀厨房》已经掌握了语音播报、声控操作、通知提醒、元服务直达、桌面卡片等核心能力。但在 AI 推荐这个招牌功能上却存在一个致命缺陷场景用户操作识别结果推荐结果问题冰箱有蔬菜拍照识别西兰花、白菜青椒肉丝、脆皮五花肉❌ 偏好高蛋白绑架推荐冰箱有肉类拍照识别猪肉、鸡肉蒜蓉西兰花、醋溜白菜❌ 偏好快手菜误导推荐用户改偏好切换到素食西兰花、白菜蒜蓉西兰花、香菇青菜✅ 但用户可能只是试试问题根源旧版推荐引擎的评分权重中偏好标签权重30分高于食材匹配权重20分导致用户随意修改的偏好标签完全主导了推荐结果而真正反映用户意图的食材识别结果反而成了配角。二、核心原理场景优先的评分体系2.1 权重重构食材为王// ---- 评分权重常量新版----constSCORE_INGREDIENT_BASE50;// 食材匹配基础权重最高constSCORE_INGREDIENT_FULL30;// 全匹配奖励constSCORE_PREF_TAG20;// 偏好标签基础权重降级constSCORE_PREF_CONFLICT-25;// 偏好冲突惩罚constSCORE_SEASON15;// 季节权重constSCORE_TYPE_MISMATCH-30;// 类型不一致惩罚constRECENT_PENALTY-20;// 历史惩罚权重对比维度旧版权重新版权重变化食材匹配2050⬆️ 150%全匹配奖励-30 新增偏好标签3020⬇️ -33%类型不一致--30 新增偏好冲突--25 新增2.2 食材分类表建立 7 大类食材分类表用于识别食材类型和检测类型一致性constFOOD_CATEGORIESnewMapstring,string[]([[vegetables,[西兰花,白菜,菠菜,生菜,番茄,黄瓜,茄子,土豆,胡萝卜,洋葱,蒜,姜,青椒,豆芽,蘑菇,香菇,青菜,芹菜,韭菜,豆角]],[meat,[猪肉,牛肉,鸡肉,羊肉,鸭肉,排骨,里脊,五花肉,肘子,骨架,肉末,肉丝,肉片,鸡块,鸡翅,鸡腿]],[seafood,[鱼,虾,蟹,龙虾,鱿鱼,扇贝,带鱼,鲈鱼,鲫鱼,鲤鱼]],[eggs,[鸡蛋,鸭蛋,鹌鹑蛋,蛋]],[dairy,[牛奶,奶酪,黄油,奶油]],[staples,[米饭,面条,面包,饺子,包子,馒头,饼,粥,粉]],[fruits,[苹果,香蕉,橙子,柠檬,草莓,葡萄,西瓜,梨,桃,菠萝]]]);2.3 偏好冲突检测定义偏好标签与食材类型的冲突关系constPREFERENCE_CONFLICTSnewMapstring,string[]([[高蛋白,[vegetables,fruits]],// 高蛋白不适合纯蔬菜/水果场景[低脂,[meat]],// 低脂不适合纯肉类场景[素食,[meat,seafood]],// 素食不适合肉类/海鲜场景[清淡,[meat]],// 清淡不适合重口味肉类场景]);三、分层架构推荐引擎在 HSP 中的位置按照《灵犀厨房》四层架构推荐引擎位于共享库HSP的 Business 层 数据源 共享库Shared HSP 主应用Entry HAP️ Foundation 层 Business 层import from sharedimport读取读取查询HomeViewModel.etsUI 状态管理HomeTabContent.ets首页 UIRecommendEngine.ets核心推荐算法场景优先评分Recipe.ets菜谱模型UserPreference.ets用户偏好模型RelationalStore菜谱数据库图一解读推荐引擎位于共享库的 Business 层主应用通过import { recommendEngine } from shared导入。这种架构确保主应用和元服务使用同一套推荐逻辑避免代码重复和不一致问题。四、关键实现步骤Step 1食材类型识别/** * 识别食材类型集合 * returns 返回食材类型集合如 {vegetables, meat} */privateidentifyIngredientTypes(ingredients:string[]):Setstring{consttypesnewSetstring();for(constingofingredients){FOOD_CATEGORIES.forEach((list:string[],type:string){if(list.some((item:string)ing.includes(item)||item.includes(ing))){types.add(type);}});}returntypes;}Step 2菜谱主要类型识别/** * 识别菜谱的主要食材类型 * returns 返回主要类型如 meat、vegetables */privategetRecipeMainType(recipe:Recipe):string|null{consttypeScoresnewMapstring,number();for(constingofrecipe.ingredients){FOOD_CATEGORIES.forEach((list:string[],type:string){if(list.some((item:string)ing.includes(item)||item.includes(ing))){constcurrentScoretypeScores.get(type)??0;typeScores.set(type,currentScore1);}});}// 返回得分最高的类型letmaxScore0;letmainType:string|nullnull;typeScores.forEach((score:number,type:string){if(scoremaxScore){maxScorescore;mainTypetype;}});returnmainType;}Step 3偏好冲突检测/** * 检查偏好标签与食材类型是否冲突 */privateisPreferenceConflict(tag:string,ingredientTypes:Setstring):boolean{constconflictsPREFERENCE_CONFLICTS.get(tag);if(!conflicts)returnfalse;// 如果识别的食材类型全部在冲突列表中则判定为冲突for(consttypeofingredientTypes){if(!conflicts.includes(type)){returnfalse;// 有不冲突的类型}}returningredientTypes.size0;// 只有当有识别食材时才判定冲突}Step 4核心评分逻辑privatecalcScore(recipe:Recipe,pref:UserPreference,ingredients:string[]):number{letscore0;constdebugParts:string[][];// 1. 食材匹配评分场景核心权重最高if(ingredientsingredients.length0){constmatchCountingredients.filter((ing:string)recipe.ingredients.some((ri:string)ri.includes(ing)||ing.includes(ri))).length;if(matchCount0){constingredientScorematchCount*SCORE_INGREDIENT_BASE;scoreingredientScore;debugParts.push(食材匹配${ingredientScore}(${matchCount}/${ingredients.length}));// 全匹配奖励if(matchCountingredients.length){scoreSCORE_INGREDIENT_FULL;debugParts.push(全匹配奖励${SCORE_INGREDIENT_FULL});}}}// 2. 食材类型一致性检查if(ingredientsingredients.length0){constingredientTypesthis.identifyIngredientTypes(ingredients);constrecipeMainTypethis.getRecipeMainType(recipe);// 如果识别的是蔬菜/水果但菜谱主要是肉类/海鲜惩罚if((ingredientTypes.has(vegetables)||ingredientTypes.has(fruits))(recipeMainTypemeat||recipeMainTypeseafood)){scoreSCORE_TYPE_MISMATCH;debugParts.push(类型不一致${SCORE_TYPE_MISMATCH}(蔬菜→肉类));}// 如果识别的是肉类但菜谱主要是蔬菜轻微惩罚if(ingredientTypes.has(meat)recipeMainTypevegetables){scoreMath.floor(SCORE_TYPE_MISMATCH/2);debugParts.push(类型不一致${Math.floor(SCORE_TYPE_MISMATCH/2)}(肉类→蔬菜));}}// 3. 偏好标签评分动态权重constingredientTypesingredientsingredients.length0?this.identifyIngredientTypes(ingredients):newSetstring();for(consttagofpref.favoriteTags){if(recipe.tags?.includes(tag)){// 检查偏好标签与食材类型是否冲突if(this.isPreferenceConflict(tag,ingredientTypes)){scoreSCORE_PREF_CONFLICT;debugParts.push(偏好冲突${SCORE_PREF_CONFLICT}(${tag}));}else{scoreSCORE_PREF_TAG;debugParts.push(偏好匹配${SCORE_PREF_TAG}(${tag}));}}}// 4. 季节匹配评分constseasonthis.getSeason();if(recipe.seasonTags?.includes(season)){scoreSCORE_SEASON;debugParts.push(季节匹配${SCORE_SEASON}(${season}));}// 5. 历史惩罚if(this.recentIds.has(recipe.id)){scoreRECENT_PENALTY;debugParts.push(历史惩罚${RECENT_PENALTY});}returnscore;}五、评分示例场景对比场景 1识别蔬菜西兰花、白菜菜谱食材匹配类型检查偏好匹配总分排名蒜蓉西兰花50(1/2)-20(快手菜)70醋溜白菜50(1/2)-20(快手菜)70香菇青菜--20(快手菜)20青椒肉丝--30(蔬菜→肉类)20(快手菜)-25(高蛋白冲突)-35❌脆皮五花肉--30(蔬菜→肉类)20(高蛋白)-10❌场景 2识别肉类猪肉、鸡肉菜谱食材匹配类型检查偏好匹配总分排名红烧肉100(2/2)30(全匹配)-20(高蛋白)150青椒肉丝50(1/2)-20(快手菜)20(高蛋白)90口水鸡50(1/2)-20(高蛋白)70蒜蓉西兰花--15(肉类→蔬菜)--15❌六、代码交付清单文件修改职责shared/src/main/ets/business/RecommendEngine.ets重构场景优先评分、食材分类、类型检查、冲突检测shared/Index.ets保持导出 RecommendEngine 和 recommendEngineentry/src/main/ets/viewmodel/HomeViewModel.ets修改从 shared 导入推荐引擎entry/src/main/ets/business/RecommendEngine.ets删除移除主应用中的重复实现七、架构优化统一推荐引擎7.1 问题发现原架构中存在推荐引擎重复实现entry/src/main/ets/business/RecommendEngine.ets ← 主应用版本 shared/src/main/ets/business/RecommendEngine.ets ← 共享库版本主应用导入的是自己的版本导致共享库中的优化无法生效。7.2 修复方案// 修复前主应用导入自己的推荐引擎import{recommendEngine}from../business/RecommendEngine;// 修复后主应用导入共享库的推荐引擎import{recommendEngine}fromshared;八、设计决策决策选择理由食材匹配权重50 分最高食材是用户意图的最直接表达应作为推荐的核心依据偏好标签权重20 分降级用户偏好可能随意修改不应主导推荐结果类型不一致惩罚-30 分识别蔬菜却推荐肉类严重违背用户意图偏好冲突惩罚-25 分高蛋白偏好与蔬菜场景冲突时降低偏好权重推荐引擎位置Shared HSP主应用和元服务共用一套逻辑避免重复和不一致九、总结与下篇预告本篇我们重构了《灵犀厨房》的推荐引擎建立了场景优先偏好辅助的评分体系。通过食材分类表、类型一致性检查、偏好冲突检测三大机制让推荐结果真正贴合用户的实际烹饪场景。核心成就食材匹配权重提升至 50 分成为推荐的核心依据类型一致性检查避免识别蔬菜却推荐肉类的尴尬偏好冲突检测当偏好与场景冲突时自动降权统一到 Shared HSP主应用和元服务共用一套逻辑 本系列持续更新中敬请关注。专栏入口[《HarmonyOS6.1全场景实战》合集] 获取基线版本源码包包括第1-15篇所有代码 架构文档 Flask 后端**如果你发现本文还有任何不严谨之处欢迎随时指出我们一起共建最优质的 HarmonyOS 6.1 学习内容如果觉得有帮助请不要吝啬你的点赞 、收藏 ⭐ 和评论 !纯血鸿蒙用心造厨。我们下一篇见