Skip to content
Learn Agentic AI
Learn Agentic AI14 min read0 views

Building a Personal Shopper Agent: Style Profiles, Curated Selections, and Wish Lists

Learn how to build an AI personal shopper agent that creates style profiles, curates product selections based on preferences, manages wish lists, and sends personalized alerts for new arrivals and price drops.

What Makes a Great Personal Shopper Agent

A human personal shopper remembers your preferences, anticipates your needs, and curates selections you would not have found on your own. An AI personal shopper agent replicates this by building a structured style profile, matching products against it, managing a wish list with price tracking, and proactively alerting customers to relevant new arrivals or sales.

Building the Style Profile System

The style profile captures explicit preferences (stated by the customer) and implicit signals (derived from browsing and purchase history).

flowchart TD
    START["Building a Personal Shopper Agent: Style Profiles…"] --> A
    A["What Makes a Great Personal Shopper Age…"]
    A --> B
    B["Building the Style Profile System"]
    B --> C
    C["Product Curation Engine"]
    C --> D
    D["Wish List Management with Price Alerts"]
    D --> E
    E["Assembling the Personal Shopper Agent"]
    E --> F
    F["FAQ"]
    F --> DONE["Key Takeaways"]
    style START fill:#4f46e5,stroke:#4338ca,color:#fff
    style DONE fill:#059669,stroke:#047857,color:#fff
from agents import Agent, Runner, function_tool
from typing import Optional
import json

# Style profile storage
STYLE_PROFILES = {}

@function_tool
def create_style_profile(customer_id: str, preferred_colors: str,
                         preferred_styles: str, budget_range: str,
                         sizes: str, avoid: str = "") -> str:
    """Create or update a customer's style profile."""
    profile = {
        "colors": [c.strip() for c in preferred_colors.split(",")],
        "styles": [s.strip() for s in preferred_styles.split(",")],
        "budget": budget_range,
        "sizes": {s.split(":")[0].strip(): s.split(":")[1].strip()
                  for s in sizes.split(",")},
        "avoid": [a.strip() for a in avoid.split(",") if a.strip()],
        "purchase_history": [],
        "wish_list": [],
    }
    STYLE_PROFILES[customer_id] = profile
    return (
        f"Style profile created for {customer_id}.\n"
        f"Colors: {', '.join(profile['colors'])}\n"
        f"Styles: {', '.join(profile['styles'])}\n"
        f"Budget: {profile['budget']}\n"
        f"Sizes: {profile['sizes']}\n"
        f"Avoiding: {', '.join(profile['avoid']) if profile['avoid'] else 'nothing specified'}"
    )

@function_tool
def update_style_preferences(customer_id: str,
                              field: str, value: str) -> str:
    """Update a specific field in the customer's style profile."""
    profile = STYLE_PROFILES.get(customer_id)
    if not profile:
        return "No style profile found. Let us create one first."

    if field == "colors":
        profile["colors"] = [c.strip() for c in value.split(",")]
    elif field == "styles":
        profile["styles"] = [s.strip() for s in value.split(",")]
    elif field == "budget":
        profile["budget"] = value
    elif field == "avoid":
        profile["avoid"] = [a.strip() for a in value.split(",")]
    else:
        return f"Unknown field: {field}. Valid: colors, styles, budget, avoid."

    return f"Updated {field} to: {value}"

Product Curation Engine

The curation tool scores products against the customer's style profile and returns ranked matches.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

PRODUCT_CATALOG = [
    {"id": "P-101", "name": "Navy Linen Blazer", "price": 159.99,
     "colors": ["navy"], "style": "classic", "category": "tops",
     "new_arrival": True},
    {"id": "P-102", "name": "Black Slim Jeans", "price": 89.99,
     "colors": ["black"], "style": "modern", "category": "bottoms",
     "new_arrival": False},
    {"id": "P-103", "name": "Olive Chino Shorts", "price": 59.99,
     "colors": ["olive", "green"], "style": "casual", "category": "bottoms",
     "new_arrival": True},
    {"id": "P-104", "name": "White Oxford Shirt", "price": 79.99,
     "colors": ["white"], "style": "classic", "category": "tops",
     "new_arrival": False},
    {"id": "P-105", "name": "Burgundy Wool Sweater", "price": 129.99,
     "colors": ["burgundy", "red"], "style": "classic", "category": "tops",
     "new_arrival": True},
]

@function_tool
def curate_selections(customer_id: str,
                      category: str = "all",
                      occasion: str = "") -> str:
    """Curate product selections based on the customer's style profile."""
    profile = STYLE_PROFILES.get(customer_id)
    if not profile:
        return "No style profile found. Please create one first."

    scored_products = []
    for product in PRODUCT_CATALOG:
        if category != "all" and product["category"] != category:
            continue

        score = 0
        reasons = []

        # Color match
        color_match = any(c in profile["colors"]
                         for c in product["colors"])
        if color_match:
            score += 3
            reasons.append("matches your color preferences")

        # Style match
        if product["style"] in profile["styles"]:
            score += 3
            reasons.append(f"fits your {product['style']} style")

        # Avoid filter
        if any(a.lower() in product["name"].lower()
               for a in profile["avoid"]):
            continue

        # New arrival bonus
        if product["new_arrival"]:
            score += 1
            reasons.append("new arrival")

        # Budget check
        budget_parts = profile["budget"].replace("$", "").split("-")
        if len(budget_parts) == 2:
            budget_max = float(budget_parts[1])
            if product["price"] <= budget_max:
                score += 1

        if score > 0:
            scored_products.append({
                "product": product,
                "score": score,
                "reasons": reasons,
            })

    scored_products.sort(key=lambda x: x["score"], reverse=True)
    if not scored_products:
        return "No products match your current preferences."

    lines = ["Curated selections for you:"]
    for sp in scored_products[:5]:
        p = sp["product"]
        why = ", ".join(sp["reasons"])
        lines.append(
            f"  {p['id']}: {p['name']} - ${p['price']:.2f} "
            f"({why})"
        )
    return "\n".join(lines)

Wish List Management with Price Alerts

@function_tool
def add_to_wish_list(customer_id: str, product_id: str,
                     target_price: Optional[float] = None) -> str:
    """Add a product to the customer's wish list with optional price alert."""
    profile = STYLE_PROFILES.get(customer_id)
    if not profile:
        return "No profile found."

    product = next((p for p in PRODUCT_CATALOG if p["id"] == product_id), None)
    if not product:
        return "Product not found."

    wish_entry = {
        "product_id": product_id,
        "product_name": product["name"],
        "current_price": product["price"],
        "target_price": target_price,
        "added_date": "2026-03-17",
    }
    profile["wish_list"].append(wish_entry)

    msg = f"Added {product['name']} to your wish list."
    if target_price:
        msg += f" You will be notified when the price drops to ${target_price:.2f}."
    return msg

@function_tool
def view_wish_list(customer_id: str) -> str:
    """View the customer's wish list with current prices."""
    profile = STYLE_PROFILES.get(customer_id)
    if not profile:
        return "No profile found."

    if not profile["wish_list"]:
        return "Your wish list is empty."

    lines = ["Your Wish List:"]
    for item in profile["wish_list"]:
        price_info = f"${item['current_price']:.2f}"
        if item.get("target_price"):
            price_info += f" (alert at ${item['target_price']:.2f})"
        lines.append(f"  {item['product_name']} - {price_info}")
    return "\n".join(lines)

@function_tool
def check_new_arrivals(customer_id: str) -> str:
    """Check for new arrivals that match the customer's profile."""
    profile = STYLE_PROFILES.get(customer_id)
    if not profile:
        return "No profile found."

    new_items = [p for p in PRODUCT_CATALOG if p["new_arrival"]]
    matching = []
    for product in new_items:
        color_match = any(c in profile["colors"] for c in product["colors"])
        style_match = product["style"] in profile["styles"]
        if color_match or style_match:
            matching.append(product)

    if not matching:
        return "No new arrivals match your style profile right now."

    lines = ["New arrivals matching your style:"]
    for p in matching:
        lines.append(f"  {p['id']}: {p['name']} - ${p['price']:.2f}")
    return "\n".join(lines)

Assembling the Personal Shopper Agent

shopper_agent = Agent(
    name="Personal Shopper",
    instructions="""You are a personal shopping assistant.

    First interaction: Build a style profile by asking about colors,
    styles (classic, modern, casual, bohemian), budget range, sizes
    by category (tops:M, bottoms:32), and anything they want to avoid.

    Ongoing interactions:
    - Curate selections tailored to their profile
    - Suggest complete outfits for specific occasions
    - Manage their wish list with price drop alerts
    - Notify about new arrivals matching their taste
    - Learn from feedback to refine recommendations

    Be opinionated but not pushy. Explain why you recommend
    each item. If they dislike a suggestion, update preferences.""",
    tools=[create_style_profile, update_style_preferences,
           curate_selections, add_to_wish_list,
           view_wish_list, check_new_arrivals],
)

FAQ

How do I improve curation accuracy over time?

Track three signals: explicit feedback (customer says "I don't like this"), implicit positive signals (items added to cart or wish list), and implicit negative signals (items shown but ignored). Use these to adjust scoring weights in the curation engine. After 10 to 15 interactions, the agent should have enough data to significantly outperform generic recommendations.

Should the agent suggest items outside the customer's stated preferences?

Yes, occasionally. Introduce a "discovery" slot in curated selections — one item that stretches beyond stated preferences but scores well on complementary attributes. For example, if a customer prefers classic styles, occasionally suggest a modern piece that matches their color and budget preferences. Frame it as a suggestion rather than a recommendation to manage expectations.

How do I handle seasonal transitions in the style profile?

Build season awareness into the curation engine. Tag products with seasonality (spring, summer, fall, winter) and prioritize in-season items. Do not delete off-season preferences — instead, reduce their weight temporarily. When a customer interacts at the start of a new season, proactively ask if their preferences have changed and suggest seasonal updates to their profile.


#PersonalShopper #StyleAI #ProductCuration #WishList #RetailPersonalization #AgenticAI #LearnAI #AIEngineering

Share
C

Written by

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.

Related Articles You May Like

Learn Agentic AI

Understanding Memory Constraints in LLM Inference: Key Strategies

Memory for Inference: Why Serving LLMs Is Really a Memory Problem

Learn Agentic AI

The 2027 AI Agent Landscape: 10 Predictions for the Next Wave of Autonomous AI

Forward-looking analysis of the AI agent landscape in 2027 covering agent-to-agent economies, persistent agents, regulatory enforcement, hardware specialization, and AGI implications.

Learn Agentic AI

The Rise of Agent-to-Agent Ecosystems: How MCP and A2A Are Creating Agent Marketplaces

How protocols like Anthropic's MCP and Google's A2A enable agents to discover and interact with each other, creating agent marketplaces and service networks in 2026.

Learn Agentic AI

Agent Gateway Pattern: Rate Limiting, Authentication, and Request Routing for AI Agents

Implementing an agent gateway with API key management, per-agent rate limiting, intelligent request routing, audit logging, and cost tracking for enterprise AI systems.

Learn Agentic AI

Fine-Tuning LLMs for Agentic Tasks: When and How to Customize Foundation Models

When fine-tuning beats prompting for AI agents: dataset creation from agent traces, SFT and DPO training approaches, evaluation methodology, and cost-benefit analysis for agentic fine-tuning.

Learn Agentic AI

Agent A/B Testing: Comparing Model Versions, Prompts, and Architectures in Production

How to A/B test AI agents in production: traffic splitting, evaluation metrics, statistical significance, prompt version comparison, and architecture experiments.