AI retailer assistant with Amazon Bedrock agent
Scenario A shoe website wants a virtual retailer that can chat with customers, find suitable products in the inventory and add them to the cart. Architecture The virtual retailer assistant is built by using Amazon Bedrock Agent Nova Pro. Here is the workflow: A customer asks the retailer agent for a specific type of product, with some requirements including colors, prices, purposes. 2-3-4. Referred to the OpenAPI schema and based on the scenario, the agent invokes a Lambda function to query to the inventory table to list all products. The agent infers from the response of the Lambda function, combines it with the customer's preferences, and recommends suitable products. In case the customer choose product(s) from the response of the agent, the agent will add the product to the cart by invoking a different Lambda function to interact with the Cart table. Prerequisites The customer must enable access to Nova Pro in the specific AWS Region. Steps In this scope of demo, I create a SQLite file with 2 tables given above. If you want to create a SQLite database, you can download the SQLite Editor extension in VS Code. Step 1. Setup table ShoeInventory and table OrderDetails in database named demo_csbot_db_2 The last column of the ShoeInventory table (S3Location) is for showing the images of the products. Step 2. Create the OpenAPI schema { "openapi": "3.0.0", "info": { "title": "Customer Service Bot API", "version": "1.0.0", "description": "Customer service APIs for a retail store selling shoes" }, "paths": { "/place_order": { "get": { "summary": "Sub task to place an order on behalf of the customer", "description": "Place an order for the number of shoes by creating an Order record and updating inventory in the database", "operationId": "get_place_order", "parameters": [{ "name": "ShoeID", "in": "query", "description": "Shoe ID to place an order", "required": true, "schema": { "type": "integer" } }, { "name": "CustomerID", "in": "query", "description": "Customer ID to place an order", "required": true, "schema": { "type": "integer" } }, { "name": "NumberOfProducts", "in": "query", "description": "Number of shoes to order", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "Order has been placed", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Your order has been placed" } } } } } } } } }, "/check_inventory": { "get": { "summary": "Returns all details related to shoes, including inventory details", "description": "Checks inventory for shoes and returns all available information about available shoes, including shoe ID, shoe colors, inventory, best fit activity, style description, s3 location and price ", "operationId": "get_check_inventory", "responses": { "200": { "description": "Returns Shoe information", "content": { "application/json": { "schema": { "type": "object", "properties": { "ShoeID": { "type": "integer", "description": "This is the shoe ID for this shoe" }, "BestFitActivity": { "type": "string", "description": "Best fit activity for this shoe"

Scenario
A shoe website wants a virtual retailer that can chat with customers, find suitable products in the inventory and add them to the cart.
Architecture
The virtual retailer assistant is built by using Amazon Bedrock Agent Nova Pro.
Here is the workflow:
- A customer asks the retailer agent for a specific type of product, with some requirements including colors, prices, purposes. 2-3-4. Referred to the OpenAPI schema and based on the scenario, the agent invokes a Lambda function to query to the inventory table to list all products.
- The agent infers from the response of the Lambda function, combines it with the customer's preferences, and recommends suitable products.
In case the customer choose product(s) from the response of the agent, the agent will add the product to the cart by invoking a different Lambda function to interact with the Cart table.
Prerequisites
The customer must enable access to Nova Pro in the specific AWS Region.
Steps
In this scope of demo, I create a SQLite file with 2 tables given above. If you want to create a SQLite database, you can download the SQLite Editor
extension in VS Code.
Step 1. Setup table ShoeInventory and table OrderDetails in database named demo_csbot_db_2
The last column of the ShoeInventory table (S3Location) is for showing the images of the products.
Step 2. Create the OpenAPI schema
{
"openapi": "3.0.0",
"info": {
"title": "Customer Service Bot API",
"version": "1.0.0",
"description": "Customer service APIs for a retail store selling shoes"
},
"paths": {
"/place_order": {
"get": {
"summary": "Sub task to place an order on behalf of the customer",
"description": "Place an order for the number of shoes by creating an Order record and updating inventory in the database",
"operationId": "get_place_order",
"parameters": [{
"name": "ShoeID",
"in": "query",
"description": "Shoe ID to place an order",
"required": true,
"schema": {
"type": "integer"
}
},
{
"name": "CustomerID",
"in": "query",
"description": "Customer ID to place an order",
"required": true,
"schema": {
"type": "integer"
}
},
{
"name": "NumberOfProducts",
"in": "query",
"description": "Number of shoes to order",
"required": true,
"schema": {
"type": "integer"
}
}],
"responses": {
"200": {
"description": "Order has been placed",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "Your order has been placed"
}
}
}
}
}
}
}
}
},
"/check_inventory": {
"get": {
"summary": "Returns all details related to shoes, including inventory details",
"description": "Checks inventory for shoes and returns all available information about available shoes, including shoe ID, shoe colors, inventory, best fit activity, style description, s3 location and price ",
"operationId": "get_check_inventory",
"responses": {
"200": {
"description": "Returns Shoe information",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"ShoeID": {
"type": "integer",
"description": "This is the shoe ID for this shoe"
},
"BestFitActivity": {
"type": "string",
"description": "Best fit activity for this shoe"
},
"StyleDesc": {
"type": "string",
"description": "Detailed description of the shoe"
},
"ShoeColors": {
"type": "string",
"description": "The colors of this shoe"
},
"Price": {
"type": "string",
"description": "Price of this shoe"
},
"InvCount": {
"type": "integer",
"description": "Inventory count"
},
"Size": {
"type": "integer",
"description": "Inventory size"
},
"S3Location": {
"type": "string",
"description": "Image of the shoe"
}
}
}
}
}
}
}
}
}
}
}
Step 3. Create Lambda code, one function to query the ShoeInventory table and one function to add to the OrderDetail table. Also, give it the necessary permissions.
import json
import boto3
import sqlite3
from datetime import datetime
import random
import logging
import os
logger = logging.getLogger()
logger.setLevel(logging.INFO)
s3 = boto3.client('s3')
bucket = os.environ.get('BUCKET_NAME') #Name of bucket with data file and OpenAPI file
db_name = 'demo_csbot_db_2.sqlite' #Location of data file in S3
local_db = '/tmp/csbot.db' #Location in Lambda /tmp folder where data file will be copied
#Download data file from S3
s3.download_file(bucket, db_name, local_db)
cursor = None
conn = None
#Initial data load and SQLite3 cursor creation
def load_data():
#load SQL Lite database from S3
# create the db
global conn
conn = sqlite3.connect(local_db)
cursor = conn.cursor()
logger.info('Completed initial data load ')
return cursor
#Function returns all customer info for a particular customerId
def return_customer_info(custName):
query = 'SELECT customerId, customerName, Addr1, Addr2, City, State, Zipcode, PreferredActivity, ShoeSize, OtherInfo from CustomerInfo where customerName like "%' + custName +'%"'
cursor.execute(query)
resp = cursor.fetchall()
#adding column names to response values
names = [description[0] for description in cursor.description]
valDict = {}
index = 0
for name in names:
valDict[name]=resp[0][index]
index = index + 1
logger.info('Customer Info retrieved', valDict)
return valDict
#Function returns shoe inventory for a particular shoeid
def return_shoe_inventory():
query = 'SELECT ShoeID, BestFitActivity, StyleDesc, ShoeColors, Price, InvCount, Size, S3Location from ShoeInventory'
cursor.execute(query)
resp = cursor.fetchall()
print ("query: ", resp)
#adding column names to response values
names = [description[0] for description in cursor.description]
valDict = []
interimDict = {}
index = 0
for item in resp:
for name in names:
interimDict[name]=item[index]
index = index + 1
index = 0
valDict.append(interimDict)
interimDict={}
logger.info('Shoe info retrieved')
return valDict
def return_shoe_image_inventory():
query = 'SELECT ShoeID, S3Location from ShoeInventory'
cursor.execute(query)
resp = cursor.fetchall()
print ("query: ", resp)
#adding column names to response values
names = [description[0] for description in cursor.description]
valDict = []
interimDict = {}
index = 0
for item in resp:
for name in names:
interimDict[name]=item[index]
index = index + 1
index = 0
valDict.append(interimDict)
interimDict={}
logger.info('Shoe and image info retrieved')
return valDict
#function places order -- reduces shoe inventory, updates order_details table --> all actions resulting from a shoe purchase
def place_shoe_order(ssId, custId, InvCnt):
global cursor
global conn
query = 'Update ShoeInventory set InvCount = InvCount - 1 where ShoeID = ' + str(ssId)
ret = cursor.execute(query)
today = datetime.today().strftime('%Y-%m-%d')
query = 'INSERT INTO OrderDetails (orderdate, shoeId, CustomerId, InvCount) VALUES ("'+today+'",'+str(ssId)+','+ str(custId)+','+str(InvCnt)+')'
ret = cursor.execute(query)
conn.commit()
#Writing updated db file to S3 and setting cursor to None to force reload of data
s3.upload_file(local_db, bucket, db_name)
cursor = None
logger.info('Shoe order placed')
return 1
def lambda_handler(event, context):
responses = []
global cursor
if cursor == None:
cursor = load_data()
id = ''
api_path = event['apiPath']
logger.info('API Path')
logger.info(api_path)
if api_path == '/customer/{CustomerName}':
parameters = event['parameters']
for parameter in parameters:
if parameter["name"] == "CustomerName":
cName = parameter["value"]
body = return_customer_info(cName)
elif api_path == '/place_order':
parameters = event['parameters']
print ("place order parameters:", parameters)
for parameter in parameters:
if parameter["name"] == "ShoeID":
id = parameter["value"]
if parameter["name"] == "CustomerID":
cid = parameter["value"]
if parameter["name"] == "NumberOfProducts":
numOfProd = parameter["value"]
body = place_shoe_order(id, cid, numOfProd)
elif api_path == '/check_inventory':
body = return_shoe_inventory()
elif api_path == '/check_image_inventory':
body = return_shoe_image_inventory()
else:
body = {"{} is not a valid api, try another one.".format(api_path)}
response_body = {
'application/json': {
'body': json.dumps(body)
}
}
action_response = {
'actionGroup': event['actionGroup'],
'apiPath': event['apiPath'],
'httpMethod': event['httpMethod'],
'httpStatusCode': 200,
'responseBody': response_body
}
responses.append(action_response)
api_response = {
'messageVersion': '1.0',
'response': action_response}
return api_response
Step 4. Setup the instruction for the Bedrock Nova Pro agent
You are an agent assisting customers with purchasing shoes. You must greet by saying "Hi. I am a virtual retail agent. Tell me what you're looking for, and I'll help you find the perfect fit." Then, to find the best fit, you may ask customers about their favorite color, foot length, and intended use of the shoes, but should not ask all these at once. Once you have information about foot length, favorite color and intended use, check the inventory for shoes that match these criteria. Generate a response that includes the shoe ID, style description, available colors, and sizes based on the inventory details. If multiple matches are found, display all options to the customer.
If there are no products that have the preferred size, offer the nearest size and inform the customer that the shoe can be tight if the alternative size is smaller, or loose if the alternative size is bigger than the preferred size.
Order Placement:
- After the customer selects a shoe, ask for the customer ID and the number of products that they want to buy. Use the chosen shoe ID, customer ID and the number of products that customer wants to buy to place the order, ensuring these shoes are still in stock by checking the inventory count.
Additional Considerations:
- If no matching shoes are available, inform the customer and offer alternatives.
- If the selected shoe is out of stock, notify the customer and suggest other options.
Demo
In this demo, the flow is that first, the customer is looking for a shoe, given specific requirements like foot length and favorite color. Then the agent will query all the shoes in the inventory, and base on the customer's requirements to list the suitable products for the customer. If the customer choose product(s), the agent will ask for the customer name and add the order to the Order table for further processing in the future.
Here is the demo for the retailer agent in the Bedrock playground: https://haianh.s3.us-east-1.amazonaws.com/EnglishRetailer.mp4
Conclusion
This blog has provided a use case for applying Amazon Bedrock Nova Pro model for a virtual retailer.