Best Practices for AI Agent Design with BuyWhere

Guidelines for designing effective AI agents that integrate with the BuyWhere API.

1. Error Handling and Resilience

Always Implement Retry Logic

Network issues and rate limits are inevitable. Implement robust retry mechanisms with exponential backoff.

import time
import random
from typing import Callable, Any

def resilient_api_call(func: Callable, *args, max_retries: int = 3, **kwargs) -> Any:
    """Execute API call with exponential backoff retry logic."""
    for attempt in range(max_retries):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            if attempt == max_retries - 1:
                raise
            
            # Exponential backoff with jitter
            wait_time = (2 ** attempt) + random.uniform(0, 1)
            time.sleep(wait_time)

Handle Different Error Types Appropriately

Different HTTP status codes require different responses:

  • 4xx Errors (Client errors): Usually indicate a problem with the request that needs fixing before retrying
  • 5xx Errors (Server errors): Often temporary, safe to retry with backoff
  • 429 Rate Limited: Respect the Retry-After header
  • 401/403 Auth issues: Check credentials and permissions

2. Performance Optimization

Cache Aggressively

BuyWhere data is relatively static (updates every 5-10 minutes). Implement smart caching:

from cachetools import TTLCache
import time

# Different TTLs for different data types
product_cache = TTLCache(maxsize=1000, ttl=600)   # 10 minutes for product details
search_cache = TTLCache(maxsize=500, ttl=60)      # 1 minute for search results
deal_cache = TTLCache(maxsize=100, ttl=300)       # 5 minutes for deals

Batch Operations

Minimize API calls by using batch endpoints:

# Instead of 100 individual calls:
# for product_id in product_ids:
#     product = api.get_product(product_id)

# Use batch endpoint:
products = api.get_products_batch(product_ids)

Optimize Search Queries

Be specific with your search parameters to reduce unnecessary data transfer:

# Good: Specific query with filters
results = api.search_products(
    query="iPhone 15 Pro 256GB",
    category="electronics",
    max_price=1500,
    limit=10
)

# Less efficient: Broad query requiring client-side filtering
results = api.search_products(query="phone", limit=100)
# Then filter client-side for iPhone 15 Pro under $1500

3. User Experience Best Practices

Provide Clear Feedback

Keep users informed about what the agent is doing:

def search_with_feedback(query: str):
    print(f"🔍 Searching for '{query}'...")
    results = api.search_products(query)
    print(f"✅ Found {len(results)} products")
    return results

Handle Edge Cases Gracefully

Anticipate and handle common edge cases:

  • No results found
  • Partial results (some items unavailable)
  • Timeout scenarios
  • Invalid user input

Maintain Conversation Context

For conversational agents, remember important context:

class ShoppingAgent:
    def __init__(self):
        self.last_search_results = []
        self.user_preferences = {}
        self.conversation_history = []
    
    def handle_follow_up(self, user_input: str):
        # Use last search results for "show me more details on the second one"
        # Use user preferences for filtering
        pass

4. Monitoring and Observability

Log Key Metrics

Track important metrics for debugging and optimization:

import logging
from datetime import datetime

logger = logging.getLogger(__name__)

class MetricsTracker:
    def __init__(self):
        self.request_count = 0
        self.error_count = 0
        self.rate_limit_hits = 0
        self.start_time = datetime.now()
    
    def log_request(self, endpoint: str, status_code: int, response_time: float):
        self.request_count += 1
        if status_code >= 400:
            self.error_count += 1
        if status_code == 429:
            self.rate_limit_hits += 1
            
        logger.info(
            f"API Request: {endpoint} | Status: {status_code} | "
            f"Time: {response_time:.2f}s | "
            f"Total Requests: {self.request_count}"
        )

Set Up Alerts

Configure alerts for abnormal patterns:

  • Sudden increase in error rates
  • Rate limit hits exceeding thresholds
  • Unusually slow response times
  • Authentication failures

5. Security Considerations

Protect API Keys

Never expose API keys in client-side code or public repositories:

# ❌ Bad: Hardcoded in source code
API_KEY = "bw_live_abc123"

# ✅ Good: Environment variables
import os
API_KEY = os.getenv("BUYWHERE_API_KEY")

# ✅ Better: Secret management services
# AWS Secrets Manager, HashiCorp Vault, etc.

Validate and Sanitize Inputs

Prevent injection attacks and unexpected behavior:

def sanitize_search_query(query: str) -> str:
    # Remove potentially harmful characters
    # Limit length
    # Normalize whitespace
    return query.strip()[:100]

Use Principle of Least Privilege

Only request the permissions your agent actually needs:

  • Read-only access for shopping agents
  • Specific endpoint access rather than wildcards
  • Separate keys for different environments (dev/test/prod)

6. Testing Strategies

Unit Test with Mocks

Test your agent logic without hitting the real API:

import unittest
from unittest.mock import Mock, patch

class TestShoppingAgent(unittest.TestCase):
    @patch('buywhere_api.Client')
    def test_search_handles_no_results(self, mock_client):
        # Setup mock to return empty results
        mock_instance = Mock()
        mock_instance.search_products.return_value = []
        mock_client.return_value = mock_instance
        
        # Test agent behavior
        agent = ShoppingAgent(api_key="test_key")
        results = agent.search("nonexistent product xyz123")
        self.assertEqual(len(results), 0)

Integration Test Against Staging

Validate real API interactions in a controlled environment:

def test_real_api_integration():
    # Use staging environment or test API key
    api = BuyWhereAPI(
        base_url="https://staging-api.buywhere.ai",
        api_key="bw_free_test_key"
    )
    
    # Test basic functionality
    results = api.search_products("laptop", limit=1)
    assert len(results) >= 0  # Should not crash
    
    # Test rate limit handling
    # ... etc

Load Test Your Agent

Ensure your agent performs well under expected load:

# Simulate multiple concurrent users
import concurrent.futures
import time

def simulate_user_session():
    # Simulate a typical user interaction
    pass

with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
    futures = [executor.submit(simulate_user_session) for _ in range(50)]
    results = [f.result() for f in futures]

7. Documentation and Maintenance

Document Your Agent's Capabilities

Clearly document what your agent can and cannot do:

# My Shopping Agent Capabilities

✅ Can do:
- Search for products by name, category, or brand
- Compare prices across different retailers
- Notify users of price drops on watched items
- Handle follow-up questions about previous search results

❌ Cannot do:
- Make purchases on behalf of users
- Access user's personal shopping history (without permission)
- Guarantee real-time price accuracy (data updates every 5-10 minutes)

Keep Dependencies Updated

Regularly update your dependencies to get security fixes and new features:

# Check for outdated packages
pip list --outdated

# Update BuyWhere SDK
pip install --upgrade buywhere-sdk

Monitor Deprecation Notices

Stay informed about API changes:

  • Subscribe to the BuyWhere developer newsletter
  • Check the changelog regularly
  • Test against beta/staging environments before upgrades