logo
Menu
Shopify Customer Care powered by GenAI

Shopify Customer Care powered by GenAI

Building a Shopify Customer Care Agent powered by GenAI with Amazon Bedrock

Published Mar 8, 2024
Last Modified Mar 11, 2024
Do you run an online store that receives a lot of customer service inquiries? If so, you know how common it is for customers to ask the same questions over and over again. They want to know where their order is, how to make a return, or why their discount didn't apply. During busy periods, these questions can quickly overwhelm your customer service team, preventing them from focusing on more important tasks. But what if there was a way to automate these common customer service tasks?
There are a ton of IVR (phone) integrations where customers can call and spend almost 3-4 minutes pressing different buttons or trying to summarize in 2 words what they want just to be forwarded to a representative that can understand what they want and to answer the exact same questions all day.
To overcome this situation I've built a solution that utilizes GenAI to understand what the customer wants and build an agent that is capable to answer these questions using a GenAI API call with Amazon Bedrock.
So whether you're just getting started with AI or you're a seasoned pro, this tutorial will show you how to use Amazon Bedrock Agents and AWS Lambda to take your Shopify management to the next level.
Note: This post has a version in spanish here: https://dev.to/aws-espanol/llevando-la-gestion-de-shopify-al-siguiente-nivel-con-genai-2bje (Versiรณn en Espaรฑol)

What will you learn?

  • Create an Amazon Bedrock Agent using one of the foundational models available: Claude Instant V1.
  • Create an openAPI 3.0 spec that works with an Amazon Bedrock Agent.
  • Create a Lambda Function that meets the requirements to reply an Amazon Bedrock Agent request.

How does the application work?

Amazon Bedrock Agent - Shopify Integration Diagram
Fig 1. Application Infrastructure Diagram
This app is the backend that can be integrated with any Chat client using API Gateway.
This app will use the Bedrock Agents API and will understand what the customer is asking for, then it will try to collect all the input required to be able to get the order information status from Shopify and provide it to the customer in Human Language.
In order to accomplish this when the Agent has all the information it will invoke a Lambda Function that will be in charge of interacting with the Shopify API and provide the Agent with the information that is needed to answer the customer's question.

The final product:

๐Ÿค“ What are Amazon Bedrock Agents?

Amazon Bedrock Agents are IA tools that can automate business tasks like order management with natural language instructions and AWS Lambda, improving the efficiency and reducing manual work.

โ˜‘๏ธ Build an Amazon Bedrock Agent in 4 steps

  1. Create Shopify credentials. Given that we're going to use Shopify for this tutiral we need an Access Token to query its API.
  2. Write an OpenAPI 3.0 spec that contains all the documentation about our API to instruct the Agento n how to use it.
  3. Create a Lambda function that will be in charge of querying the order status in Shopify.
  4. Create and setup the Agent.

๐Ÿ”‘ Step 1: Generate Shopify Credentials

Shopify is t he leading ecom platform built by builders and makes the administration of an online store super easy, since it was built by builders each functionallity has an API.
The Lambda Function makes a call to a Shopify API (Orders API), in order to do so it needs an Access Token.
Getting the Access Token: (If you already know how to do this, you can skip this step)
  1. Create a Custom App in Shopify:
  2. Define permissions:ย 

Install the app and get credentials:ย 
Install Custom App in Shopify
Install App Step 2

ย ๐Ÿ“ƒ Step 2: Create OpenAPI 3.0 spec

This is the key step and the magic source, the better the spec is the better the Agent will perform.
An openAPI 3.0 spec is a plain text in JSON with a specific format where you indicate:
  • API Endpoints
  • HTTP Request Methods accepted
  • Parameters for each endpoint and its formatting
  • Expected responses.
For each bullet there's a "description" field where you can specify in natural language what it does, this is what is going to help the Agent to make a decision.
Document Header:
1
2
3
4
5
6
7
8
9
{
"openapi": "3.0.0",
"info": {
"title": "Order Info API",
"version": "1.0.0",
"description": "API that provides and identifies order details"
},
"paths":{}
}
Path:
  • /orders/{orderId}: It will receive GET requests and returns the order information. orderId is a required parameter passed in the URL.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
"paths": {
"/orders/{orderNumber}": {
"get": {
"summary": "Gets information about an order",
"description": "Gets the entire information about an order based on its number",
"operationId": "getOrderInfo",
"parameters": [
{
"name": "orderNumber",
"in": "path",
"description": "ID of the order that needs to be fetched",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
}
],
"responses": {}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
"paths": {
"/orders/{orderNumber}": {
"get": {
"summary": "Gets information about an order",
"description": "Gets the entire information about an order based on its number",
"operationId": "getOrderInfo",
"parameters": [
{
"name": "orderNumber",
"in": "path",
"description": "ID of the order that needs to be fetched",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
}
],
"responses": {}
}
Response:
  • Build a response that meets Bedrock Agent requirements.
    • Status Code: 200
    • An object with a property named content: application/json
    • Enum of object properties.
  • Object properties:
    • Id: Order Number
    • Status: Order Status
    • MoreInfo: If the order is fulfilled, info about the tracking number, url, etc.
1
2
3
4
5
6
7
8
9
{
'application/json': {
'body': JSON.stringify({
"id": orderNumber,
"status": orderStatus,
"moreInfo": moreInfo
})
}
}
Response:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
"responses": {
"200": {
"description": "Object with the order information",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"status": {
"type": "string",
"description": "Status of the order"
},
"moreInfo": {
"type" :"string",
"description": "More information about the order usually the tracking URL"
}
}
}
}
}
}
}
Full OpenAPI 3.0 Spec:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
{
"openapi": "3.0.0",
"info": {
"title": "Order Info API",
"version": "1.0.0",
"description": "API that provides and identifies order details"
},
"paths": {
"/orders/{orderNumber}": {
"get": {
"summary": "Gets information about an order",
"description": "Gets the entire information about an order based on its number",
"operationId": "getOrderInfo",
"parameters": [
{
"name": "orderNumber",
"in": "path",
"description": "ID of the order that needs to be fetched",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
}
],
"responses": {
"200": {
"description": "Object with the order information",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"status": {
"type": "string",
"description": "Status of the order"
},
"moreInfo": {
"type" :"string",
"description": "More information about the order usually the tracking URL"
}
}
}
}
}
}
}
}
}
}
}
Save this spec as a text file and upload it to an S3 Bucket, this file will be required in next steps.

๐Ÿง‘โ€๐Ÿ’ป Step 3: Create a Lambda Function

This Lambda Function will be in charge to query the order information from Shopify.
Steps to create a Lambda Function:
  1. Create Function
  2. Author from Scratch
  3. Set a name
  4. Runtime: NodeJS (you can use Python or any programming language you feel comfortable with)
  5. Architecture: X86_64
To make a call to the Shopify API I'm going to use the Axios library, and in the handler body I'll call this object.
If you need any help on adding 3rd party libraries to a NodeJS Lambda Function, leave a commentt and I'll write a post. about it.
The Axios object needs 2 properties:
  1. URL
  2. Headers
    1. Shopify requires a special header to authenticate the requests, named X-Shopify-Access-Token
    2. Content-Type
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const axios = require('axios');

/**
Let's create the axios request to Shopify
In order to get the Shopify-Access Token we'll need to create a custom app in Shopify to use the token
*/

const shopifyRequest = axios.create({
baseURL: `https://your-shopify-store.myshopify.com/admin/api/2024-01/graphql.json`,
headers: {
'X-Shopify-Access-Token': '[HERE GOES YOUR ACCESS TOKEN]',
'Content-Type': 'application/json'
}
});

exports.handler = async (event) => {
// Lambda Function Code GOES here

}
In the following request to the Shopify's GraphQL API the orderNumber is passed as argument and it. will return the order staatus and its fulfillments, if there is any fulfillment it will also return the tracking information.
For training purposes I already know that the orderNumber is going to be received in the position 0 of the specified parameters. A great improvement to this can be looking for the property named orderNumber in the event parameter.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const orderNumber = event.parameters[0].value;
const query = `{
orders(first:1,query: "name:${orderNumber}") {
edges {
node {
name
displayFulfillmentStatus
fulfillments {
trackingInfo {
number
url
}
}
}
}
}
}`
;

// Let's get the response from Shopify

const shopifyResponse = await shopifyRequest.post('', { query: query });
The shopifyResponse object stores the required information.
Let's create the responseBody object:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Let's get the order fulfillment status from the response

const orderStatus = shopifyResponse.data.data.orders?.edges[0]?.node.displayFulfillmentStatus;
const moreInfo = shopifyResponse.data.data.orders?.edges[0]?.node.fulfillments[0]?.trackingInfo[0]?.url;
// Let's return the response

let responseBody = {
'application/json': {
'body': JSON.stringify({
"id": orderNumber,
"status": orderStatus,
"moreInfo": moreInfo
})
}
}
The Bedrock Agent needs to receive some attributes in order to continue its flow:
API responses will belong to an ActionGroup, so the response must specify to wich ActionGroup belongs.
This can be accomplished passing the following properties in the response:
  • ActionGroup
  • Path
  • HTTP Method
  • Status Code
  • Body (responseBody)
1
2
3
4
5
6
7
8
let actionResponse = {
actionGroup: event.actionGroup,
apiPath: event.apiPath,
httpMethod: event.httpMethod,
httpStatusCode: 200,
responseBody: responseBody,

}
Let's prepare and return the Lambda Function response:
1
2
3
4
5
6
let response = {
messageVersion: '1.0',
statusCode: 200,
response: actionResponse,
};
return response;

๐Ÿ‘” Step 4: Creating a Bedrock Agent

Go to the Bedrock Console and then select "Agents"
Create a Bedrock Agent from console.
Then:
  • Give your agent a name: OrderInfoAgent
  • Require User Input: YES
  • Check if you would like to use an existing role or create a new one, encription and timeout (how long the session will last), and tags.
Create a Bedrock Agent - Wizard Step 1
Create a Bedrock Agent - Wizard Step 1 - Add Role info
Next Step:
  1. Select the FM (Foundational Model):
    1. Here's a guide about how to choose a LLM : https://community.aws/posts/how-to-choose-your-llm
    2. If you don't see any LLM in the dropdown, this is because you need to enable them: (https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html).
  2. Write the instructions for your agent: It is super important to write an excellent prompt, even though the Foundational Model might be capable of understanding multiple languages, writing the prompot in English will make thigs easier, ie: You're a kind customer care agent that is here to provide order status information to our customers, on each response you'll provide as much information as you can grab about the order and you'll always thank our customer for being a loyal customer, if you don't know the answer tell the customer to contact customercare@mycompany.com
Create a Bedrock Agent - Select a FM
3) Set up the Action Groups, an Agent might have multiple Action Groups, these groups are going to be executed base on the Customer's question. In this case the Agent has only one Action Group.
  • Name: GetOrderInformation
  • Select the Lambda Function created in the previous step
  • Select the OpenAPI spec
Bedrock Agent setup Action Group

4) Don't create a knowledgebase, click Next, review all the information and click Create Agent.
Voilรก! in a few minutes the agent will be ready for testing.
Spoiler Alert: Copy the Agent's ARN, you'll need it shortly.
Bedrock Agent Created - Copy ARN

๐Ÿ’ฃ Testing the Agent

Bedrock Agent - Not Working
Ok, this is not the expected result, it crashed ๐Ÿคฏ
What happened?
The following error was thrown: Access denied while invoking Lambda function arn:aws:lambda:us-east-1:XXXXXXX:function:XXXXXXX. Check the permissions on Lambda function and retry the request.
When clicking Show Trace > there's no clear explanation of what happened, the root cause of this error is that no permissions were given in the Lambda Function to be invoked by the Bedrock Agent.

๐Ÿ˜ฑ The Bedrock Agent is not working: Lambda Function missing permissions

In order to allow the Bedrock Agent to execute a Lambda Function, a Resource Based policy has to be added in the Function.
  1. In the Lambda Function go to Configurations -> Permissions
Lambda Function - Configuration -> Permissions
  1. In the section resource based policy statements click "Add Permissions"
Lambda Function - Add Permissions

ย 3. Select AWS Service and open the services list. Unfortunately, Amazon Bedrock (at the moment of writing this article) is not part of this list. Select: Other
Select AWS Services - Other
  1. Fill in the information
StatementId: An identifier for this policy
Principal: bedrock.amazonaws.com
Source ARN: Bedrock Agent's ARN
Action: lambda:invokeFunction

๐ŸŽ‰ And now, it works ๐Ÿ™‚

Now after giving it a second try and asking about the order status, the agent will be capable to answer with the order information and not with an error. (As expected)
This agent is capable of answering in multiple languages given that the Foundational Model used (Claude v1) is able to do so, not all FM are capable to do it.
In Spanish:
Bedrock Agent- Spanish Chat
In English:
Bedrock Agent - English Conversation

๐ŸŽฏ Conclusion:

In this episode you've learned to create a Bedrock Agent in 4 steps and with a few lines of codes if you compare the number of lines you'll have to write if ever wondering to provide intelligence to the Agent.
The Agent is capable of understanding what the customer wants because it is powered by Generative AI using the Foundational Model Claude V1.
The goal of this Agent is to reduce the number of phone calls and repetitive tasks that the Customer Care Service operator handles.
The main goal of Bedrock Agents is to let the developer focus on building the code that delivers the information and then leverage on the Agents capabilities to:
  • Understand what customer wants
  • Look for the information needed, invoke an API to execute an action.
  • Provide the answer to the customer.
Also you've learned how to solve the Invoke permission error in the Lambda Function.

โญ๏ธ Next Steps (Next episode):

The Bedrock Agent is working, now its time to improve the prompt that empowers the Foundational Model, improve the Lambda Function to provide more information, and make the agent available to be invoked using a public API.
This will be covered in the next episode.
ย 

3 Comments