AI 購物代理
購物代理是一個 AI 系統 作為客戶的個人購物助手。 它理解自然語言請求、搜尋商品目錄、根據偏好和限制做出推薦,並引導客戶完成結帳。 在本課程中,您將學習生產級購物代理背後的架構,並建構一個 that integrates with Shopify's Catalog API and Checkout Kit.
購物助手架構
一個設計良好的購物代理不是一個單體式提示詞。它是一個由專門元件組成的管線,共同運作:
核心元件
Intent Classifier: Determines what the customer wants to do -- browse products, compare options, make a purchase, ask about shipping, or something else. This is typically handled by the LLM itself with structured output.
Product Discovery: Translates natural language into Catalog API queries with appropriate filters and search terms.
Recommendation Engine: Ranks and filters results based on customer preferences, purchase history, and contextual signals.
Cart Manager: Maintains shopping cart state across the conversation, handling additions, removals, and quantity changes.
Checkout Flow: Orchestrates the purchase process through Checkout Kit, collecting necessary buyer information and processing payment.
使用 Shopify Catalog 的商品推薦引擎
推薦引擎是您的代理超越簡單搜尋的地方。 It combines Catalog API results with contextual understanding to surface the right products.
// src/agents/recommendation-engine.ts
import Anthropic from '@anthropic-ai/sdk';
import { CatalogClient } from './catalog-client';
interface CustomerContext {
preferences: string[];
budget: { min: number; max: number } | null;
previousPurchases: string[];
conversationHistory: Message[];
}
interface ProductRecommendation {
productId: string;
title: string;
price: number;
reason: string; // Why this product was recommended
confidence: number;
}
export class RecommendationEngine {
private anthropic: Anthropic;
private catalog: CatalogClient;
constructor() {
this.anthropic = new Anthropic();
this.catalog = new CatalogClient();
}
async recommend(
query: string,
context: CustomerContext
): Promise<ProductRecommendation[]> {
// Step 1: Extract search parameters from natural language
const searchParams = await this.extractSearchParams(query, context);
// Step 2: Query the Catalog API
const rawProducts = await this.catalog.search({
query: searchParams.searchTerms,
filters: {
priceRange: context.budget || undefined,
categories: searchParams.categories,
availability: 'IN_STOCK',
},
limit: 25, // Fetch more than we need for ranking
});
// Step 3: Re-rank results using the LLM
const ranked = await this.rankProducts(rawProducts, query, context);
return ranked.slice(0, 5); // Return top 5 recommendations
}
private async extractSearchParams(
query: string,
context: CustomerContext
) {
const response = await this.anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 500,
messages: [
{
role: 'user',
content: `Extract search parameters from this shopping request.
Customer said: "${query}"
Known preferences: ${context.preferences.join(', ') || 'none'}
Budget: ${context.budget ? `$${context.budget.min}-$${context.budget.max}` : 'not specified'}
Previous purchases: ${context.previousPurchases.join(', ') || 'none'}
Return JSON with: searchTerms (string), categories (string[]), attributes (object)`,
},
],
});
return JSON.parse(response.content[0].type === 'text'
? response.content[0].text
: '{}');
}
private async rankProducts(
products: any[],
originalQuery: string,
context: CustomerContext
): Promise<ProductRecommendation[]> {
const response = await this.anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 2000,
messages: [
{
role: 'user',
content: `You are a personal shopping assistant. Rank these products for the customer.
Customer request: "${originalQuery}"
Preferences: ${context.preferences.join(', ')}
Budget: ${context.budget ? `$${context.budget.min}-$${context.budget.max}` : 'flexible'}
Products:
${products.map((p, i) => `${i + 1}. ${p.title} - $${p.price} - ${p.description}`).join('\n')}
Return a JSON array of objects with: productId, title, price, reason (one sentence explaining why this is a good match), confidence (0-1).
Order by confidence descending.`,
},
],
});
return JSON.parse(response.content[0].type === 'text'
? response.content[0].text
: '[]');
}
}
When building recommendation flows, fire the Catalog API search and any user-context lookups (purchase history, saved preferences) in parallel using Promise.all(). The LLM re-ranking step depends on both, but the data fetches are independent of each other.
對話式商務流程
購物對話遵循可預測的模式。 Designing for these patterns makes your agent feel natural rather than robotic.
對話狀態機
實作
// src/agents/shopping-agent.ts
import Anthropic from '@anthropic-ai/sdk';
import { RecommendationEngine } from './recommendation-engine';
import { CartManager } from './cart-manager';
import { CheckoutFlow } from './checkout-flow';
type ConversationState =
| 'greeting'
| 'discovery'
| 'browsing'
| 'comparison'
| 'cart'
| 'checkout'
| 'confirmation';
interface AgentState {
conversationState: ConversationState;
cart: CartItem[];
searchContext: any;
recommendations: any[];
}
const SYSTEM_PROMPT = `You are a friendly, knowledgeable shopping assistant. Your job is to help customers find and purchase products they will love.
Guidelines:
- Ask clarifying questions when the request is vague
- Always explain WHY you recommend a product, not just WHAT it is
- Respect budget constraints -- never recommend products above the stated budget
- When showing products, highlight the key differentiators
- Be honest about trade-offs between options
- Guide customers toward checkout when they seem ready, but never be pushy
- If asked about something outside shopping, politely redirect
You have access to the following tools:
- search_products: Search the product catalog
- add_to_cart: Add a product to the shopping cart
- view_cart: Show current cart contents
- begin_checkout: Start the checkout process
- get_product_details: Get detailed information about a specific product`;
export class ShoppingAgent {
private anthropic: Anthropic;
private recommendations: RecommendationEngine;
private cartManager: CartManager;
private checkoutFlow: CheckoutFlow;
private state: AgentState;
private messages: Anthropic.MessageParam[] = [];
constructor(sessionId: string) {
this.anthropic = new Anthropic();
this.recommendations = new RecommendationEngine();
this.cartManager = new CartManager(sessionId);
this.checkoutFlow = new CheckoutFlow();
this.state = {
conversationState: 'greeting',
cart: [],
searchContext: {},
recommendations: [],
};
}
async handleMessage(userMessage: string): Promise<string> {
this.messages.push({ role: 'user', content: userMessage });
const response = await this.anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1500,
system: SYSTEM_PROMPT,
tools: this.getToolDefinitions(),
messages: this.messages,
});
// Process tool calls in a loop until the agent produces a text response
let currentResponse = response;
while (currentResponse.stop_reason === 'tool_use') {
const toolResults = await this.executeTools(currentResponse);
this.messages.push(
{ role: 'assistant', content: currentResponse.content },
{ role: 'user', content: toolResults }
);
currentResponse = await this.anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1500,
system: SYSTEM_PROMPT,
tools: this.getToolDefinitions(),
messages: this.messages,
});
}
const textContent = currentResponse.content.find(
(block) => block.type === 'text'
);
const assistantMessage = textContent?.text || '';
this.messages.push({ role: 'assistant', content: assistantMessage });
return assistantMessage;
}
private async executeTools(
response: Anthropic.Message
): Promise<Anthropic.ToolResultBlockParam[]> {
const toolUseBlocks = response.content.filter(
(block) => block.type === 'tool_use'
);
const results: Anthropic.ToolResultBlockParam[] = [];
for (const tool of toolUseBlocks) {
if (tool.type !== 'tool_use') continue;
let result: string;
switch (tool.name) {
case 'search_products':
const products = await this.recommendations.recommend(
tool.input.query as string,
{ preferences: [], budget: null, previousPurchases: [], conversationHistory: [] }
);
this.state.recommendations = products;
this.state.conversationState = 'browsing';
result = JSON.stringify(products);
break;
case 'add_to_cart':
await this.cartManager.addItem(
tool.input.productId as string,
tool.input.quantity as number
);
this.state.conversationState = 'cart';
result = JSON.stringify(await this.cartManager.getCart());
break;
case 'begin_checkout':
const checkoutUrl = await this.checkoutFlow.initiate(
await this.cartManager.getCart()
);
this.state.conversationState = 'checkout';
result = JSON.stringify({ checkoutUrl });
break;
default:
result = JSON.stringify({ error: 'Unknown tool' });
}
results.push({
type: 'tool_result',
tool_use_id: tool.id,
content: result,
});
}
return results;
}
private getToolDefinitions(): Anthropic.Tool[] {
return [
{
name: 'search_products',
description: 'Search for products in the catalog based on a natural language query',
input_schema: {
type: 'object' as const,
properties: {
query: { type: 'string', description: 'Natural language product search query' },
},
required: ['query'],
},
},
{
name: 'add_to_cart',
description: 'Add a product to the customer shopping cart',
input_schema: {
type: 'object' as const,
properties: {
productId: { type: 'string', description: 'The product variant ID' },
quantity: { type: 'number', description: 'Quantity to add' },
},
required: ['productId', 'quantity'],
},
},
{
name: 'begin_checkout',
description: 'Start the checkout process with the current cart',
input_schema: {
type: 'object' as const,
properties: {},
required: [],
},
},
];
}
}
Checkout Kit 整合
Checkout Kit 彌合了您代理的商品推薦和實際購買之間的差距。 Here is how the integration works across platforms.
JavaScript (Web Agents)
// src/checkout/web-checkout.ts
import { CheckoutKit } from '@shopify/checkout-kit-js';
export class WebCheckoutFlow {
private kit: CheckoutKit;
constructor(storeDomain: string, storefrontToken: string) {
this.kit = new CheckoutKit({
domain: storeDomain,
storefrontAccessToken: storefrontToken,
});
}
async createCheckout(cartItems: CartItem[], buyerEmail: string) {
// Create a cart via the Storefront API
const cart = await this.kit.createCart({
lines: cartItems.map((item) => ({
merchandiseId: item.variantId,
quantity: item.quantity,
})),
buyerIdentity: {
email: buyerEmail,
countryCode: 'US',
},
});
return {
cartId: cart.id,
checkoutUrl: cart.checkoutUrl,
totalAmount: cart.cost.totalAmount.amount,
currency: cart.cost.totalAmount.currencyCode,
};
}
}
Swift (iOS Agents)
// Sources/Checkout/ShopifyCheckout.swift
import ShopifyCheckoutKit
class AgentCheckoutManager {
let configuration: Configuration
init(storeDomain: String, storefrontToken: String) {
self.configuration = Configuration(
storeDomain: storeDomain,
storefrontAccessToken: storefrontToken
)
}
func presentCheckout(checkoutURL: URL, from viewController: UIViewController) {
ShopifyCheckoutKit.present(
checkout: checkoutURL,
from: viewController,
delegate: self
)
}
}
extension AgentCheckoutManager: CheckoutDelegate {
func checkoutDidComplete(event: CheckoutCompletedEvent) {
// Track successful purchase for agent analytics
Analytics.track("agent_purchase_completed", properties: [
"orderId": event.orderDetails.id,
"total": event.orderDetails.cart.totalAmount
])
}
func checkoutDidFail(error: CheckoutError) {
// Handle checkout failure gracefully
print("Checkout failed: \(error.localizedDescription)")
}
func checkoutDidCancel() {
// Customer backed out -- agent should follow up
}
}
Shopify carts expire after 24 hours of inactivity. If your agent maintains long-running conversations, always validate the cart before initiating checkout. If the cart has expired, recreate it from the saved cart items. Never assume a previously created cart is still valid.
代理到結帳管線
The complete pipeline from customer intent to completed purchase involves several steps, each with potential failure points that your agent must handle:
In agentic commerce, errors are not just technical problems -- they are broken customer experiences. Your agent must handle: network timeouts to the Catalog API, out-of-stock products discovered at checkout time, payment declines, and shipping restriction mismatches. For every error, the agent should communicate clearly and offer an alternative path forward.
效能最佳化
購物代理必須快速回應。 Customers expect sub-second responses for simple queries and under three seconds for complex product searches. Here are key optimization strategies:
- Pre-fetch popular categories -- Cache the top 100 products in common categories locally
- Stream LLM responses -- Use streaming to show the agent "typing" while it processes
- Parallel tool execution -- When the agent calls multiple tools, execute them concurrently
- Connection pooling -- Reuse HTTP connections to the Catalog API and Checkout Kit
- Edge caching -- Deploy product search caches at the edge for global performance
繼續前往工作流程自動化 to learn how to combine AI agents with Shopify Flow for automated commerce operations.