关于 personalization-engine
personalization-engine 是面向电商团队的个性化推荐实施指南,涵盖平台选型、推荐逻辑、排除规则和效果衡量。内容也介绍自定义及无头商店方案。
主要功能
- 01按电商平台选择推荐工具
- 02配置协同过滤与相似商品推荐
- 03排除缺货、已购及当前商品
- 04通过点击和加购数据评估效果
适用场景
- 01为商品页添加“经常一起购买”推荐
- 02为回访顾客设置个性化首页
- 03为无头商店构建推荐 API
- 04测试推荐对收入和加购率的影响
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ finsilabs/ awesome-ecommerce-skills --skill personalization-engine安装后在 Claude Code 中输入/personalization-engine确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
tile.jsonevals/browsing-history-recommendations-with-co/criteria.jsontask.mdevals/co-purchase-matrix-and-fbt-recommendatio/criteria.jsontask.mdevals/unified-recommendation-api-with-redis-ca/criteria.jsontask.md详细介绍
个性化引擎
概述
通过为每位客户展示最相关的商品,个性化商品推荐可以提高平均订单金额和会话深度。“经常一起购买”“你可能还喜欢”和个性化首页版块都属于推荐形式。各大平台都有可在无需自定义代码的情况下处理协同过滤和推荐算法的应用。只有当商品目录规模、流量或推荐逻辑超出应用解决方案的支持范围时,才需要构建自定义推荐引擎。
何时使用此技能
- 在商品页面添加“经常一起购买”或“你可能还喜欢”轮播时
- 为回访客户实现个性化首页时
- 为移动应用或无头店面构建推荐 API 时
- 冷启动推荐(无历史记录)返回的商品不相关时
- 对个性化对平均订单金额和每次会话收入的影响进行 A/B 测试时
核心说明
第 1 步:确定平台并选择合适的推荐工具
| 平台 | 推荐工具 | 原因 |
|---|---|---|
| Shopify | LimeSpot 或 Frequently Bought Together by Code Black Belt | LimeSpot 提供由机器学习驱动的个性化首页、商品详情页、购物车和购后推荐;Frequently Bought Together 专为商品详情页打造 |
| WooCommerce | YITH WooCommerce Frequently Bought Together 或 LimeSpot | YITH 最受欢迎;LimeSpot 支持 WooCommerce,并提供基于机器学习的推荐 |
| BigCommerce | LimeSpot 或 Boost AI Search & Discovery | 两者都提供个性化推荐,且可在 BigCommerce 应用市场使用 |
| Custom / Headless | 使用共同购买矩阵 + 余弦相似度构建 | 如需完全控制算法、排除逻辑和 API 响应格式,则必须采用此方案 |
第 2 步:平台专属设置
Shopify
选项 A:LimeSpot(推荐 — 全套个性化方案)
- 从 Shopify 应用商店安装 LimeSpot Personalizer
- LimeSpot 会自动分析订单历史记录和浏览数据,以构建推荐模型
- 配置推荐组件的展示位置:
- 前往 LimeSpot → Recommendations → Configure placements
- 启用:商品详情页(“经常一起购买”)、购物车(“其他客户也购买了”)、首页(“为你推荐”)
- 为每个展示位置选择推荐算法:
- Frequently Bought Together:商品-商品协同过滤(基于订单中商品的共同出现情况)
- Recommended for You:用户-商品协同过滤(基于浏览历史记录)
- Similar Products:基于内容的过滤(相同类别、相近价格、相似属性)
- 配置排除项:始终排除缺货商品和近期购买过的商品
选项 B:Frequently Bought Together by Code Black Belt(侧重商品详情页)
- 从应用商店安装
- 此应用会分析过往订单,并自动识别最常被一起购买的商品
- 在商品详情页展示“经常一起购买”版块,并提供捆绑折扣选项
- 无需手动配置 — 模型会根据订单数据自动刷新
测试与衡量:
- 在 LimeSpot 中:前往 Analytics → A/B Tests,比较不同推荐算法
- 按推荐位跟踪点击率和加入购物车率
- 每项测试至少运行 2 周,并确保流量充足,再得出结论
WooCommerce
YITH WooCommerce Frequently Bought Together(免费版/高级版):
- 从 WordPress 插件目录安装
- 前往 YITH → Frequently Bought Together → Settings
- 选择推荐方式:自动(根据订单历史记录)或手动(为每件商品指定产品)
- 配置显示方式(PDP 上的位置、要显示的商品数量、折扣类型,如有)
- 免费版支持手动指定商品;高级版则根据订单历史记录生成自动推荐
LimeSpot for WooCommerce:
- 安装 LimeSpot Personalizer for WooCommerce
- 配置方式与 Shopify 版本相同,可为首页、PDP 和购物车提供完整的商品推荐
WooCommerce 内置的交叉销售和追加销售:
- 在任意商品页面,前往 Linked Products tab
- 手动添加追加销售商品(显示在 PDP 上)和交叉销售商品(显示在购物车中)
- 这种方式需要手动操作,但对于熟悉商品关联关系的小型目录来说很有效
BigCommerce
LimeSpot for BigCommerce:
- 从 BigCommerce App Marketplace 安装
- 配置方式和功能与 Shopify/WooCommerce 版本相同
Boost AI Search & Discovery:
- 从 App Marketplace 安装
- 除搜索功能外,还包含推荐组件
- 配置“Frequently Bought Together”和“Similar Products”版块
自定义/无头架构
对于无头商店,可使用预先计算的相似度矩阵构建推荐流程,以实现快速响应:
// lib/recommendations.ts
// Step 1: Pre-compute co-purchase matrix nightly (run as a cron job)
// PostgreSQL: count how often each product pair appears in the same order
export const coPurchaseMatrixSQL = `
INSERT INTO product_co_purchases (product_a_id, product_b_id, co_purchase_count, updated_at)
SELECT
a.product_id AS product_a_id,
b.product_id AS product_b_id,
COUNT(DISTINCT a.order_id) AS co_purchase_count,
NOW() AS updated_at
FROM order_items a
JOIN order_items b ON a.order_id = b.order_id AND a.product_id < b.product_id
GROUP BY a.product_id, b.product_id
HAVING COUNT(DISTINCT a.order_id) >= 3 -- Minimum confidence threshold
ON CONFLICT (product_a_id, product_b_id)
DO UPDATE SET co_purchase_count = EXCLUDED.co_purchase_count, updated_at = NOW();
`;
// Step 2: Serve "Frequently Bought Together" from the pre-computed matrix
export async function getFrequentlyBoughtTogether(
productId: string, limit = 6, excludeProductIds: string[] = []
): Promise<Product[]> {
const pairs = await db.productCoPurchases.findMany({
where: {
OR: [{ productAId: productId }, { productBId: productId }],
NOT: { OR: [{ productAId: { in: excludeProductIds } }, { productBId: { in: excludeProductIds } }] },
},
orderBy: { coPurchaseCount: 'desc' },
take: limit * 2, // Fetch extra to filter out-of-stock
});
const relatedIds = pairs.map(p => p.productAId === productId ? p.productBId : p.productAId);
const products = await db.products.findMany({ where: { id: { in: relatedIds }, status: 'active', inventoryQuantity: { gt: 0 } } });
return products.slice(0, limit);
}
// Step 3: Browsing history recommendations using product vectors
function buildProductVector(product: Product, allCategoryIds: string[], allTags: string[]): number[] {
const categoryEncoding = allCategoryIds.map(id => product.categoryId === id ? 1 : 0);
const priceNormalized = product.priceInCents / 100000; // Normalize to 0-1
const tagEncoding = allTags.map(tag => product.tags.includes(tag) ? 1 : 0);
return [...categoryEncoding, priceNormalized, ...tagEncoding];
}
export async function getRecommendationsFromBrowsingHistory(
sessionProductIds: string[], limit = 8
): Promise<Product[]> {
if (sessionProductIds.length === 0) return getBestSellers(limit);
const [browsedProducts, allProducts, allCategoryIds, allTags] = await Promise.all([
db.products.findMany({ where: { id: { in: sessionProductIds } } }),
db.products.findMany({ where: { status: 'active', inventoryQuantity: { gt: 0 }, id: { notIn: sessionProductIds } }, take: 500 }),
db.categories.findMany({ select: { id: true } }).then(cats => cats.map(c => c.id)),
db.productTags.findMany({ distinct: ['tag'] }).then(tags => tags.map(t => t.tag)),
]);
// Build "taste vector" by averaging vectors of browsed products
const vectors = browsedProducts.map(p => buildProductVector(p, allCategoryIds, allTags));
const tasteVector = vectors[0].map((_, i) => vectors.reduce((sum, v) => sum + v[i], 0) / vectors.length);
// Rank all products by cosine similarity to taste vector
const ranked = allProducts
.map(p => {
const vec = buildProductVector(p, allCategoryIds, allTags);
const dot = tasteVector.reduce((sum, val, i) => sum + val * vec[i], 0);
const mag = Math.sqrt(tasteVector.reduce((s, v) => s + v * v, 0)) * Math.sqrt(vec.reduce((s, v) => s + v * v, 0));
return { product: p, score: mag > 0 ? dot / mag : 0 };
})
.sort((a, b) => b.score - a.score);
return ranked.slice(0, limit).map(r => r.product);
}
// Step 4: Unified recommendation API with caching
export async function getRecommendations(context: 'pdp' | 'homepage' | 'cart', productId?: string, sessionProductIds: string[] = []) {
const cacheKey = `recs:${context}:${productId ?? 'none'}:${sessionProductIds.slice(0, 3).join('-')}`;
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
let products: Product[];
switch (context) {
case 'pdp':
products = await getFrequentlyBoughtTogether(productId!, 6, [productId!]);
if (products.length < 4) {
const extra = await getRecommendationsFromBrowsingHistory(sessionProductIds, 4 - products.length);
products = [...products, ...extra];
}
break;
case 'homepage':
products = sessionProductIds.length > 0
? await getRecommendationsFromBrowsingHistory(sessionProductIds, 12)
: await getBestSellers(12);
break;
default:
products = await getBestSellers(8);
}
await redis.setex(cacheKey, 300, JSON.stringify(products)); // 5-minute cache
return products;
}
对于拥有 10k+ 客户的商店: 使用 BG/NBD + ALS 协同过滤(Python implicit 库),与余弦相似度方法相比,可显著提高用户—商品推荐的准确性。
第 3 步:配置推荐排除项
每个推荐引擎都必须排除:
- 缺货商品 — 切勿推荐客户无法购买的商品
- 当前正在查看的商品 — 在商品自身的 PDP 上显示“Related Products”时,排除当前商品
- 近期购买过的商品 — 向客户展示他们上周买过的商品,会带来糟糕的体验
在 LimeSpot 中: 在 Settings → Exclusions 下配置排除项;缺货商品会自动排除。
在 Frequently Bought Together 中: 应用会自动隐藏捆绑推荐中的缺货变体。
对于自定义构建: 在每个推荐函数中传入包含当前商品和客户近期购买商品的 excludeProductIds。
第 4 步:衡量推荐效果
每周跟踪以下指标:
| 指标 | 良好基准 | 查看位置 |
|---|---|---|
| “Frequently Bought Together”的点击率 | 5–15% | LimeSpot Analytics 或自定义跟踪 |
| 推荐带来的加入购物车率 | 3–8% | LimeSpot Analytics |
| 推荐带来的营收 | 总营收的 5–20% | LimeSpot/Tidio 归因报告 |
最佳实践
- 先使用应用,再从头构建 — LimeSpot 和 Frequently Bought Together 已经过充分调优,并能处理各种边缘情况(冷启动、缺货、排除近期购买商品);正确构建这些功能需要数周时间
- 每晚刷新共同购买矩阵 — 新订单会改变哪些商品经常被一起购买;过时的数据会降低推荐质量
- 在查询时过滤缺货商品,而不是在构建模型时过滤 — 库存变化速度比推荐模型的刷新速度更快
- 将推荐轮播的商品数量限制在 6–8 件 — 超过 8 件会导致选择困难,并降低点击率
- 建立反馈闭环 — 跟踪每个推荐位的点击率和加入购物车率,以便随时间比较不同算法变体
常见陷阱
| 问题 | 解决方案 |
|---|---|
| 推荐结果总是显示相同的热门产品 | 添加多样性约束——将任一类别在推荐位中的占比限制在 30%;覆盖不同价格区间,增加多样性 |
| 冷启动用户看到的畅销产品不相关 | 即使只有一次页面浏览,也将其作为信号;使用用户首次浏览的产品类别来限制畅销产品回退结果 |
| 推荐结果包含当前正在浏览的产品 | 始终将当前产品 ID 作为排除项传递给推荐函数 |
| 共同购买矩阵受到捆绑促销的影响 | 过滤掉所有商品都来自同一促销捆绑的订单——这些订单无法反映真实的共同购买倾向 |
相关技能
- @customer-segmentation
- @customer-lifetime-value
- @product-reviews-ratings
- @user-generated-content