← Back to DevBytes

Building an E-commerce Support Agent That Converts

What Is an E-Commerce Support Agent That Converts?

An e-commerce support agent that converts is an AI-powered conversational system designed to do more than just answer questions. It actively guides shoppers through the buying journey — from product discovery to checkout — while handling objections, recommending products, and closing sales. Unlike traditional FAQ bots that deflect tickets, a conversion-focused agent is built with revenue generation as its primary metric.

These agents blend three core capabilities:

Under the hood, a conversion agent typically combines a large language model (LLM) with structured e-commerce data sources — product catalogs, real-time inventory, pricing engines, and CRM systems — to produce grounded, persuasive responses that respect business constraints.

Why It Matters

Every support interaction on an e-commerce site is a conversion opportunity. A customer asking "Does this jacket run large?" is signaling purchase intent. A traditional support setup might return a sizing chart link; a conversion agent returns the chart plus a tailored recommendation ("Based on your fit preference, the relaxed-fit version in medium would work well — it's in stock and ships free today").

The business impact is measurable across three dimensions:

For developers, building this agent means solving an interesting engineering challenge: orchestrating LLM reasoning with deterministic business logic so the system is both conversational and reliably on-brand.

Core Architecture Overview

Before diving into code, let's map the architecture. A production-grade conversion agent typically has these layers:

The diagram below illustrates the request flow:


User Message
      │
      ▼
┌──────────────────────────┐
│  Intent Classifier       │  → product_inquiry / order_status / general_chat
└──────────────────────────┘
      │
      ▼
┌──────────────────────────┐
│  Context Aggregator      │  → pulls session data, cart contents, browse history
└──────────────────────────┘
      │
      ▼
┌──────────────────────────┐
│  Tool Dispatcher         │  → calls search_product(), get_inventory(), etc.
└──────────────────────────┘
      │
      ▼
┌──────────────────────────┐
│  LLM Response Generator  │  → constructs final message with conversion hooks
└──────────────────────────┘
      │
      ▼
┌──────────────────────────┐
│  Output Validator        │  → checks prices, links, brand tone compliance
└──────────────────────────┘
      │
      ▼
    Response to User

Step 1: Setting Up the Tool Layer

The tool layer is the agent's connection to reality. Without it, the LLM hallucinates product names, prices, and availability. Start by building clean, typed functions that your agent can call.

Product Search Tool


# tools/product_tools.py
from typing import List, Optional, Dict, Any
from dataclasses import dataclass
import json

@dataclass
class Product:
    id: str
    name: str
    price: float
    currency: str
    in_stock: bool
    category: str
    attributes: Dict[str, Any]
    rating: float
    review_count: int
    image_url: str
    url: str

def search_products(
    query: str,
    category_filter: Optional[str] = None,
    max_price: Optional[float] = None,
    sort_by: str = "relevance",
    limit: int = 5
) -> List[Product]:
    """
    Search the product catalog. Returns a list of matching products
    with full metadata for the agent to reference.
    """
    # In production, this queries Elasticsearch, Algolia, or your search DB
    # Here we simulate with a mock catalog
    catalog = _load_catalog()  # your actual data source
    
    results = []
    query_lower = query.lower()
    
    for item in catalog:
        if query_lower in item["name"].lower() or query_lower in item.get("description", "").lower():
            if category_filter and item["category"] != category_filter:
                continue
            if max_price and item["price"] > max_price:
                continue
            results.append(Product(
                id=item["id"],
                name=item["name"],
                price=item["price"],
                currency=item.get("currency", "USD"),
                in_stock=item["inventory_count"] > 0,
                category=item["category"],
                attributes=item.get("attributes", {}),
                rating=item.get("rating", 0.0),
                review_count=item.get("review_count", 0),
                image_url=item.get("image_url", ""),
                url=f"https://store.example.com/products/{item['id']}"
            ))
    
    # Sort results
    if sort_by == "price_asc":
        results.sort(key=lambda p: p.price)
    elif sort_by == "price_desc":
        results.sort(key=lambda p: p.price, reverse=True)
    elif sort_by == "rating":
        results.sort(key=lambda p: p.rating, reverse=True)
    
    return results[:limit]

def _load_catalog() -> List[Dict[str, Any]]:
    """Mock catalog — replace with your actual data pipeline."""
    return [
        {
            "id": "prod_001",
            "name": "Trailblazer Hiking Boot",
            "description": "Waterproof leather hiking boot with Vibram sole",
            "price": 189.99,
            "currency": "USD",
            "inventory_count": 42,
            "category": "footwear",
            "attributes": {"color": "Brown", "sizes": ["7", "8", "9", "10", "11", "12"]},
            "rating": 4.7,
            "review_count": 384,
            "image_url": "/images/trailblazer-boot.jpg"
        },
        {
            "id": "prod_002",
            "name": "Summit Down Jacket",
            "description": "800-fill down jacket for extreme cold, packs into its own pocket",
            "price": 349.00,
            "currency": "USD",
            "inventory_count": 15,
            "category": "outerwear",
            "attributes": {"color": "Navy", "sizes": ["S", "M", "L", "XL"]},
            "rating": 4.9,
            "review_count": 127,
            "image_url": "/images/summit-jacket.jpg"
        }
    ]

Inventory and Pricing Tool


# tools/inventory_tools.py
from typing import Dict, Optional
import datetime

def check_inventory(product_id: str, size: Optional[str] = None, color: Optional[str] = None) -> Dict:
    """
    Returns real-time inventory status for a specific product/variant.
    Always call this before promising availability to a customer.
    """
    # In production, query your inventory management system or warehouse API
    inventory_data = {
        "prod_001": {
            "total_available": 42,
            "variants": {
                "7_Brown": 5, "8_Brown": 8, "9_Brown": 12,
                "10_Brown": 10, "11_Brown": 5, "12_Brown": 2
            },
            "low_stock_threshold": 3,
            "next_restock_date": "2025-02-01"
        },
        "prod_002": {
            "total_available": 15,
            "variants": {
                "S_Navy": 4, "M_Navy": 6, "L_Navy": 4, "XL_Navy": 1
            },
            "low_stock_threshold": 3,
            "next_restock_date": None
        }
    }
    
    if product_id not in inventory_data:
        return {"available": False, "error": "Product not found in inventory system"}
    
    product_inventory = inventory_data[product_id]
    
    if size and color:
        variant_key = f"{size}_{color}"
        variant_qty = product_inventory["variants"].get(variant_key, 0)
        return {
            "product_id": product_id,
            "variant": variant_key,
            "available": variant_qty > 0,
            "quantity": variant_qty,
            "low_stock": variant_qty <= product_inventory["low_stock_threshold"],
            "next_restock": product_inventory.get("next_restock_date")
        }
    
    return {
        "product_id": product_id,
        "total_available": product_inventory["total_available"],
        "variants": product_inventory["variants"],
        "low_stock_warning": product_inventory["total_available"] <= product_inventory["low_stock_threshold"]
    }

def get_current_price(product_id: str, customer_id: Optional[str] = None) -> Dict:
    """
    Returns the customer-eligible price, accounting for discounts,
    loyalty tiers, and active promotions.
    """
    base_prices = {"prod_001": 189.99, "prod_002": 349.00}
    
    if product_id not in base_prices:
        return {"error": "Product not found"}
    
    price = base_prices[product_id]
    discount_applied = None
    
    # Check customer-specific pricing (loyalty, abandoned-cart offers, etc.)
    if customer_id:
        loyalty_discount = _get_loyalty_discount(customer_id)
        if loyalty_discount:
            price = round(price * (1 - loyalty_discount), 2)
            discount_applied = f"Loyalty tier: {loyalty_discount*100}% off"
    
    return {
        "product_id": product_id,
        "list_price": base_prices[product_id],
        "customer_price": price,
        "discount": discount_applied,
        "currency": "USD"
    }

def _get_loyalty_discount(customer_id: str) -> Optional[float]:
    """Mock loyalty lookup — replace with your CRM integration."""
    loyal_customers = {"cust_abc123": 0.10}  # 10% off for VIP tier
    return loyal_customers.get(customer_id)

Cart Operations Tool


# tools/cart_tools.py
from typing import Dict, List, Optional
import uuid

def get_cart_contents(session_id: str) -> Dict:
    """
    Retrieves the current cart for a browsing session.
    Returns items, subtotal, and any applied promotions.
    """
    # In production, query your cart service or session store
    carts = {
        "sess_xyz789": {
            "items": [
                {"product_id": "prod_001", "name": "Trailblazer Hiking Boot", 
                 "variant": "9_Brown", "quantity": 1, "unit_price": 189.99},
            ],
            "subtotal": 189.99,
            "item_count": 1,
            "promotions": ["FREE_SHIPPING"],
            "estimated_total": 189.99
        }
    }
    return carts.get(session_id, {"items": [], "subtotal": 0, "item_count": 0})

def add_to_cart(
    session_id: str,
    product_id: str,
    variant: str,
    quantity: int = 1
) -> Dict:
    """
    Adds an item to the cart. Returns updated cart state.
    The agent should call this after customer confirms intent to purchase.
    """
    # In production, call your cart service API
    # This is a simplified mock
    current_cart = get_cart_contents(session_id)
    
    new_item = {
        "product_id": product_id,
        "variant": variant,
        "quantity": quantity,
        "unit_price": 189.99  # Would come from pricing service
    }
    
    current_cart["items"].append(new_item)
    current_cart["subtotal"] = sum(item["unit_price"] * item["quantity"] for item in current_cart["items"])
    current_cart["item_count"] = len(current_cart["items"])
    current_cart["estimated_total"] = current_cart["subtotal"]
    
    return {
        "success": True,
        "cart": current_cart,
        "action": f"Added {variant} of {product_id} to cart"
    }

Step 2: Building the Prompt Layer (The Conversion Playbook)

The system prompt is where you encode conversion behavior. It's the single most important piece of the agent — it defines the tone, the merchandising strategy, and the guardrails. Here's a battle-tested template:


# prompts/system_prompt.py

CONVERSION_AGENT_PROMPT = """
You are a knowledgeable shopping assistant for OutdoorGear Co., a premium outdoor equipment retailer.

## YOUR ROLE
You help customers find the right products, answer questions accurately, and guide them toward confident purchases. You are warm, enthusiastic, and never pushy. Your goal is to be so helpful that customers naturally want to buy.

## CONVERSATION RULES

### Always Do:
- Answer the customer's direct question FIRST, before any product suggestion
- Use tools to fetch live data — never guess prices, inventory, or product details
- When inventory is low on an item the customer wants, mention it gently ("This is popular — only 2 left in your size")
- After answering, offer ONE relevant next step: a product recommendation, a size check, or a cart action
- Use the customer's name if available in context
- Keep responses concise but warm — 2-4 sentences max before asking a question

### Never Do:
- Make up product specifications, prices, or availability
- Pressure the customer ("You should buy this now!")
- Recommend products that are out of stock without noting alternatives
- Suggest adding to cart unless the customer has shown clear purchase intent
- Use generic phrases like "How can I help you today?" after the first exchange

## MERCHANDISING PLAYBOOK

When the customer shows intent (asks about a product, compares options, or says "I'm looking for..."), follow this sequence:

1. **Validate** — Acknowledge their need ("Great choice — the Trailblazer is our best-rated boot")
2. **Inform** — Share a key detail that matters for their use case, pulled from product attributes
3. **Check** — Verify a preference ("Would you prefer something more lightweight, or is ankle support your priority?")
4. **Recommend** — Suggest a specific variant or complementary product, with reasoning
5. **Bridge to Cart** — If they respond positively, offer to add it: "Want me to add the size 9 Brown to your cart? It's in stock and ships free."

## OBJECTION HANDLING

When a customer expresses hesitation about price:
- Acknowledge the concern ("That's fair — it is an investment")
- Provide value context ("These boots use full-grain leather and a Vibram sole — customers typically get 4+ years of heavy use")
- Offer social proof ("They're rated 4.7 from 384 reviews")
- If available, mention any applicable discount or promotion
- Never argue with the customer's perception

## PRODUCT LINKING RULES
- When mentioning a product, always reference it by its exact name
- Cross-sells should be relevant to the primary product's use case
- The cross-sell ratio: after every 3 product-focused responses, offer 1 complementary item suggestion

## TONE
- Professional but friendly. Use "great," "perfect," "excellent" sparingly
- Match the customer's level of expertise (don't talk down to beginners, don't oversimplify for experts)
- Be specific, never vague. "This jacket has 800-fill down" not "This jacket is warm"
"""

Step 3: Orchestrating the Agent Loop

Now we wire everything together. The orchestrator manages the conversation loop: classify the intent, gather context, call tools, generate the response, validate it, and return it. Here's a production-ready implementation using the OpenAI API with tool calling:


# agent/orchestrator.py
import json
import uuid
from typing import Dict, List, Any, Optional
from dataclasses import dataclass, field
from datetime import datetime
import openai  # or your LLM provider of choice

from tools.product_tools import search_products, Product
from tools.inventory_tools import check_inventory, get_current_price
from tools.cart_tools import get_cart_contents, add_to_cart
from prompts.system_prompt import CONVERSION_AGENT_PROMPT


@dataclass
class ConversationState:
    session_id: str
    customer_id: Optional[str]
    customer_name: Optional[str]
    messages: List[Dict[str, Any]] = field(default_factory=list)
    cart_items: List[Dict] = field(default_factory=list)
    browse_context: Dict[str, Any] = field(default_factory=dict)
    last_product_viewed: Optional[str] = None
    conversion_stage: str = "discovery"  # discovery | consideration | decision | post_purchase


class ConversionAgent:
    def __init__(self, api_key: str, model: str = "gpt-4o"):
        self.client = openai.OpenAI(api_key=api_key)
        self.model = model
        self.tools = self._build_tool_definitions()
        
    def _build_tool_definitions(self) -> List[Dict]:
        """Define the tools the model can call, with strict schemas."""
        return [
            {
                "type": "function",
                "function": {
                    "name": "search_products",
                    "description": "Search the product catalog by query string. Returns matching products with prices, ratings, and stock status.",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "query": {
                                "type": "string",
                                "description": "Search terms (e.g., 'waterproof hiking boots')"
                            },
                            "category_filter": {
                                "type": "string",
                                "description": "Optional category to narrow results"
                            },
                            "max_price": {
                                "type": "number",
                                "description": "Optional maximum price filter"
                            },
                            "sort_by": {
                                "type": "string",
                                "enum": ["relevance", "price_asc", "price_desc", "rating"],
                                "description": "Sorting strategy"
                            },
                            "limit": {
                                "type": "integer",
                                "description": "Max results to return (default 5)"
                            }
                        },
                        "required": ["query"]
                    }
                }
            },
            {
                "type": "function",
                "function": {
                    "name": "check_inventory",
                    "description": "Check real-time inventory for a product, optionally filtered by size and color.",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "product_id": {"type": "string", "description": "The product ID to check"},
                            "size": {"type": "string", "description": "Optional size filter"},
                            "color": {"type": "string", "description": "Optional color filter"}
                        },
                        "required": ["product_id"]
                    }
                }
            },
            {
                "type": "function",
                "function": {
                    "name": "get_current_price",
                    "description": "Get the customer-specific price for a product, including any applicable discounts.",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "product_id": {"type": "string"},
                            "customer_id": {"type": "string", "description": "Optional customer ID for loyalty pricing"}
                        },
                        "required": ["product_id"]
                    }
                }
            },
            {
                "type": "function",
                "function": {
                    "name": "get_cart_contents",
                    "description": "Retrieve the current contents of the customer's shopping cart.",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "session_id": {"type": "string"}
                        },
                        "required": ["session_id"]
                    }
                }
            },
            {
                "type": "function",
                "function": {
                    "name": "add_to_cart",
                    "description": "Add a product variant to the customer's cart. Only call when the customer explicitly agrees.",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "session_id": {"type": "string"},
                            "product_id": {"type": "string"},
                            "variant": {"type": "string", "description": "Variant identifier like '9_Brown'"},
                            "quantity": {"type": "integer", "description": "Quantity to add (default 1)"}
                        },
                        "required": ["session_id", "product_id", "variant"]
                    }
                }
            }
        ]
    
    def _execute_tool(self, tool_name: str, arguments: Dict) -> Any:
        """Dispatch tool calls to the appropriate function."""
        if tool_name == "search_products":
            return search_products(**arguments)
        elif tool_name == "check_inventory":
            return check_inventory(**arguments)
        elif tool_name == "get_current_price":
            return get_current_price(**arguments)
        elif tool_name == "get_cart_contents":
            return get_cart_contents(**arguments)
        elif tool_name == "add_to_cart":
            return add_to_cart(**arguments)
        else:
            return {"error": f"Unknown tool: {tool_name}"}
    
    def process_message(
        self,
        user_message: str,
        state: ConversationState
    ) -> Dict[str, Any]:
        """
        Process a single user message through the agent loop.
        Returns the assistant's response and updated conversation state.
        """
        # Build the messages array for the LLM call
        system_message = self._build_system_message(state)
        
        messages = [{"role": "system", "content": system_message}]
        messages.extend(state.messages[-20:])  # Keep context window manageable
        messages.append({"role": "user", "content": user_message})
        
        # First LLM call — may request tool usage
        response = self.client.chat.completions.create(
            model=self.model,
            messages=messages,
            tools=self.tools,
            tool_choice="auto",
            temperature=0.7,
            max_tokens=600
        )
        
        response_message = response.choices[0].message
        
        # Handle tool calls if the model requested them
        if response_message.tool_calls:
            # Process each tool call
            tool_results = []
            for tool_call in response_message.tool_calls:
                tool_name = tool_call.function.name
                arguments = json.loads(tool_call.function.arguments)
                
                result = self._execute_tool(tool_name, arguments)
                tool_results.append({
                    "tool_call_id": tool_call.id,
                    "role": "tool",
                    "content": json.dumps(result),
                    "name": tool_name
                })
            
            # Add the assistant's tool-call message and all tool results
            messages.append(response_message)
            messages.extend(tool_results)
            
            # Second LLM call to synthesize tool results into a natural response
            final_response = self.client.chat.completions.create(
                model=self.model,
                messages=messages,
                temperature=0.7,
                max_tokens=400
            )
            
            assistant_text = final_response.choices[0].message.content
        else:
            assistant_text = response_message.content
        
        # Validate output before returning
        validated_text = self._validate_output(assistant_text)
        
        # Update conversation state
        state.messages.append({"role": "user", "content": user_message})
        state.messages.append({"role": "assistant", "content": validated_text})
        
        # Detect conversion stage transitions
        state.conversion_stage = self._detect_stage(user_message, validated_text, state)
        
        return {
            "response": validated_text,
            "conversation_state": state,
            "conversion_stage": state.conversion_stage
        }
    
    def _build_system_message(self, state: ConversationState) -> str:
        """Enrich the system prompt with live context."""
        context_blocks = []
        
        if state.customer_name:
            context_blocks.append(f"Current customer: {state.customer_name}")
        if state.last_product_viewed:
            context_blocks.append(f"Last product customer viewed: {state.last_product_viewed}")
        if state.cart_items:
            item_names = [item.get("name", item.get("product_id")) for item in state.cart_items]
            context_blocks.append(f"Items currently in cart: {', '.join(item_names)}")
        
        context_blocks.append(f"Conversion stage: {state.conversion_stage}")
        context_blocks.append(f"Session ID: {state.session_id}")
        
        if context_blocks:
            context_section = "\n\n## CURRENT CONTEXT\n" + "\n".join(f"- {block}" for block in context_blocks)
            return CONVERSION_AGENT_PROMPT + context_section
        
        return CONVERSION_AGENT_PROMPT
    
    def _validate_output(self, text: str) -> str:
        """
        Guardrails: ensure the output is safe and compliant.
        In production, add price regex validation, link checking, PII scanning.
        """
        if not text or len(text.strip()) < 5:
            return "I'd be happy to help you find the right gear! What are you looking for today?"
        
        # Strip any hallucinated prices that don't match our catalog
        # This is a simplified check — production systems use regex + catalog cross-reference
        banned_phrases = ["guaranteed lowest price", "we price match", "best price anywhere"]
        for phrase in banned_phrases:
            if phrase.lower() in text.lower():
                # Replace with compliant language
                text = text.replace(phrase, "great value")
        
        return text.strip()
    
    def _detect_stage(self, user_msg: str, assistant_msg: str, state: ConversationState) -> str:
        """
        Classify the conversion stage based on conversation signals.
        """
        user_lower = user_msg.lower()
        
        # Decision signals
        decision_keywords = ["add to cart", "buy", "purchase", "checkout", "order"]
        if any(kw in user_lower for kw in decision_keywords):
            return "decision"
        
        # Consideration signals
        consideration_keywords = ["compare", "versus", "vs", "difference between", 
                                   "worth it", "price", "expensive", "alternative"]
        if any(kw in user_lower for kw in consideration_keywords):
            return "consideration"
        
        # Discovery signals
        discovery_keywords = ["looking for", "do you have", "show me", "recommend",
                               "need", "searching", "help me find"]
        if any(kw in user_lower for kw in discovery_keywords):
            return "discovery"
        
        # If customer mentioned cart or purchase in previous turns
        if state.conversion_stage == "decision":
            return "decision"
        
        return state.conversion_stage


# =============================================
# EXAMPLE USAGE
# =============================================
if __name__ == "__main__":
    agent = ConversionAgent(api_key="sk-your-key-here")
    
    state = ConversationState(
        session_id="sess_xyz789",
        customer_id="cust_abc123",
        customer_name="Alex",
        last_product_viewed="Trailblazer Hiking Boot"
    )
    
    # Simulate a conversation
    messages = [
        "I'm looking for warm jackets for a winter hiking trip in Colorado.",
        "The Summit Down Jacket looks nice, but $349 seems steep. Is it worth it?",
        "Okay, you've convinced me. Can you add the medium Navy to my cart?"
    ]
    
    for msg in messages:
        print(f"\n{'='*60}")
        print(f"USER: {msg}")
        result = agent.process_message(msg, state)
        print(f"AGENT: {result['response']}")
        print(f"STAGE: {result['conversion_stage']}")
        state = result['conversation_state']

Step 4: Intent Classification (Optional Enhancement)

For high-volume stores, you may want a fast pre-classifier before the full agent loop. This lets you route simple queries (order status, store hours) to lightweight handlers while reserving the LLM for complex shopping interactions:


# agent/intent_classifier.py
from enum import Enum
from typing import Tuple
import re

class Intent(Enum):
    PRODUCT_INQUIRY = "product_inquiry"       # "Tell me about the Summit jacket"
    PRODUCT_SEARCH = "product_search"         # "Show me waterproof boots under $200"
    SIZE_FIT = "size_fit"                     # "Does this run large or small?"
    PRICE_QUESTION = "price_question"         # "Is there a discount on this?"
    COMPARISON = "comparison"                 # "How does X compare to Y?"
    ORDER_STATUS = "order_status"             # "Where is my order #12345?"
    RETURN_POLICY = "return_policy"           # "Can I return if it doesn't fit?"
    SHIPPING_INFO = "shipping_info"           # "When will this arrive?"
    ADD_TO_CART = "add_to_cart"               # Explicit cart action
    GENERAL_CHAT = "general_chat"             # Greetings, thanks, off-topic
    OBJECTION = "objection"                   # Price/value hesitation

class IntentClassifier:
    """
    Fast regex + keyword classifier for routing.
    For production, consider a fine-tuned small model or embedding-based classifier.
    """
    
    def classify(self, message: str, conversation_stage: str) -> Tuple[Intent, float]:
        msg = message.lower().strip()
        
        # Order status patterns
        order_patterns = [
            r"order\s*(?:#|number|id)?\s*\d+",
            r"where\s*(?:is|are)\s*my\s*(?:order|package|delivery)",
            r"tracking",
            r"shipping\s*(?:status|update)"
        ]
        for pattern in order_patterns:
            if re.search(pattern, msg):
                return Intent.ORDER_STATUS, 0.95
        
        # Return policy patterns
        return_keywords = ["return policy", "can i return", "refund", "exchange",
                           "money back", "return window", "return period"]
        if any(kw in msg for kw in return_keywords):
            return Intent.RETURN_POLICY, 0.90
        
        # Cart action
        cart_keywords = ["add to cart", "add it", "put it in my cart", "add the"]
        if any(kw in msg for kw in cart_keywords):
            return Intent.ADD_TO_CART, 0.92
        
        # Comparison
        comparison_keywords = ["compare", "versus", " vs ", "difference between",
                               "which is better", "or the"]
        if any(kw in msg for kw in comparison_keywords):
            return Intent.COMPARISON, 0.88
        
        # Price objection
        objection_keywords = ["expensive", "too much", "worth it", "worth the price",
                              "overpriced", "cheaper", "budget"]
        if any(kw in msg for kw in objection_keywords) and conversation_stage == "consideration":
            return Intent.OBJECTION, 0.85
        
        # Size/fit
        size_keywords = ["size", "fit", "large", "small", "tight", "loose", 
                         "measurements", "sizing chart", "true to size"]
        if any(kw in msg for kw in size_keywords):
            return Intent.SIZE_FIT, 0.87
        
        # Product search
        search_keywords = ["looking for", "show me", "find me", "do you have",
                           "recommend", "suggest", "search"]
        if any(kw in msg for kw in search_keywords):
            return Intent.PRODUCT_SEARCH, 0.86
        
        # Product inquiry (catch-all for product-related questions)
        if any(char in msg for char in ["?", "tell me", "what is", "details"]):
            return Intent.PRODUCT_INQUIRY, 0.75
        
        return Intent.GENERAL_CHAT, 0.70

Step 5: Building a Response Validator (Guardrails)

A conversion agent handles money — it must never misrepresent prices, link to dead URLs, or make claims your products can't support. The validator runs as a post-processing step on every response:


# guardrails/validator.py
import re
from typing import Dict, List, Optional, Tuple

class ResponseValidator:
    """
    Post-generation validation for agent responses.
    Catches hallucinations and policy violations before the message reaches the user.
    """
    
    def __init__(self, catalog_price_map: Dict[str, float], brand_voice_rules: Dict = None):
        self.price_map = catalog_price_map  # {product_name: correct_price}
        self.brand_voice_rules = brand_voice_rules or {}
        self.banned_terms = [
            "guaranteed", "promise", "always works", "never fails",
            "cheapest", "lowest price guaranteed"
        ]
    
    def validate(self, response: str, products_referenced: List[str]) -> Dict:
        """
        Run all validation checks. Returns a dict with:
        - passed: bool
        - corrections: list of applied fixes
        - flags: list of warnings for logging
        """
        corrections = []
        flags = []
        
        # Check 1: Price accuracy
        price_check = self._validate_prices(response)

— Ad —

Google AdSense will appear here after approval

← Back to all articles