claudecodeui/claude-skills/recommendation-systems.md

4.1 KiB

name description
recommendation-systems Design and build recommendation systems. Use when adding "you might also like", personalization, content ranking, or collaborative filtering to a product.

Recommendation Systems Skill

Use when: building personalized recommendations, content ranking, "similar items", or any system that suggests things to users.

Choose the Right Approach First

Approach When to use Cold start? Needs user data?
Popularity/Trending New product, no data Works No
Content-Based Rich item metadata Works Minimal
Collaborative Filtering Established user base Problem Yes (lots)
Hybrid Best results Partial Yes

Approach 1: Popularity-Based (Start Here)

Good for: new products, anonymous users, trending sections.

SELECT item_id, COUNT(*) as interactions
FROM user_interactions
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY item_id
ORDER BY interactions DESC
LIMIT 20;

Approach 2: Content-Based Filtering

Match items by their attributes. Good when you have item metadata.

Key steps:

  1. Vectorize item features (category, tags, text embeddings)
  2. Build user profile from their interaction history
  3. Score unvisited items by cosine similarity to user profile
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np

def get_recommendations(user_profile, item_vectors, item_ids, n=10):
    scores = cosine_similarity([user_profile], item_vectors)[0]
    top_indices = np.argsort(scores)[::-1][:n]
    return [item_ids[i] for i in top_indices]

Approach 3: Collaborative Filtering

"Users like you also liked..." — needs significant interaction data (1000+ users).

Matrix Factorization (SVD):

from surprise import SVD, Dataset, Reader
from surprise.model_selection import cross_validate

reader = Reader(rating_scale=(1, 5))
data = Dataset.load_from_df(df[['user_id', 'item_id', 'rating']], reader)
model = SVD(n_factors=50, n_epochs=20)
model.fit(data.build_full_trainset())
prediction = model.predict(user_id, item_id)

Simpler: item-item similarity from co-occurrence:

-- Items frequently viewed together
SELECT a.item_id as item_a, b.item_id as item_b, COUNT(*) as co_views
FROM user_interactions a
JOIN user_interactions b ON a.session_id = b.session_id AND a.item_id != b.item_id
GROUP BY a.item_id, b.item_id
HAVING COUNT(*) > 10
ORDER BY co_views DESC;

Approach 4: Embedding-Based (Modern, Scalable)

Use vector embeddings + pgvector or Pinecone for semantic similarity.

-- pgvector: find similar items
SELECT id, title, embedding <-> $1::vector AS distance
FROM items
ORDER BY embedding <-> $1::vector
LIMIT 10;

System Design Checklist

  • Logging first — instrument all interactions (views, clicks, purchases, skips) BEFORE building recommendations
  • Baseline first — ship popularity-based before ML models
  • A/B test — measure CTR, conversion, engagement vs control
  • Filter seen items — don't recommend what user already has/viewed
  • Diversity — avoid echo chambers; add exploration (epsilon-greedy or MMR)
  • Freshness — decay old interactions, boost new content
  • Cold start plan — what do new users/items see before data exists?
  • Explainability — "Because you watched X" improves trust

Postgres Schema for Interaction Logging

CREATE TABLE user_interactions (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id     UUID REFERENCES users(id),
    item_id     UUID REFERENCES items(id),
    event_type  TEXT NOT NULL CHECK (event_type IN ('view','click','purchase','skip','rate')),
    rating      NUMERIC(3,2),  -- NULL unless event_type = 'rate'
    session_id  UUID,
    context     JSONB DEFAULT '{}',  -- page, position, query, etc.
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_interactions_user_id ON user_interactions(user_id);
CREATE INDEX idx_interactions_item_id ON user_interactions(item_id);
CREATE INDEX idx_interactions_created_at ON user_interactions(created_at DESC);