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"

May 9, 2025 - 08:53
 0
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.

Image description

Here is the workflow:

  1. 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.
  2. 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.

Image description

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.

Image description

Step 1. Setup table ShoeInventory and table OrderDetails in database named demo_csbot_db_2

Image description

The last column of the ShoeInventory table (S3Location) is for showing the images of the products.

Image description

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.