Building a Serverless QnABot with Custom Response Bots on AWS
Sunil Biradar ยท September 3, 2024
Introduction
In this blog post, we'll walk through the process of creating a serverless QnABot using AWS Lambda, the Serverless Framework, and Amazon Lex. We'll cover everything from initial setup to implementing custom response bots for handling multi-turn conversations. This guide is based on a real-world project and addresses common challenges and roadblocks you might encounter along the way.
Table of Contents
- Setting Up the Serverless Framework
- Creating the Initial Serverless Project
- Understanding and Configuring Deployment Stages
- Implementing the Lambda Function
- Configuring IAM Roles
- Deploying to Different AWS Regions
- Integrating with QnABot
- Implementing Custom Response Bots
- Testing and Troubleshooting
- Best Practices and Tips
Setting Up the Serverless Framework
To get started, you'll need to install the Serverless Framework and configure your AWS credentials.
- Install Node.js and npm from https://nodejs.org/
- Install the Serverless Framework globally:
npm install -g serverless
- Configure your AWS credentials:
- Create an AWS account if you don't have one
- Create an IAM user with programmatic access and AdministratorAccess policy
- Run
aws configure
and enter your AWS access key ID and secret access key
Creating the Initial Serverless Project
Let's create a new Serverless project for our QnABot:
- Create a new directory for your project and navigate to it:
mkdir qnabot-project cd qnabot-project
- Initialize a new Serverless project:
serverless create --template aws-nodejs --path .
- Open the generated
serverless.yml
file and update it with the following content:
org: sunilb0575p
app: e-shop-response-bots
service: qna-chatbot
provider:
name: aws
runtime: nodejs20.x
region: us-west-2
functions:
return-status:
handler: handler.returnStatus
This configuration sets up a basic serverless service with a single Lambda
function named return-status
.
Understanding and Configuring Deployment Stages
By default, the Serverless Framework uses a stage called "dev". You can specify different stages for different environments (e.g., development, staging, production).
To deploy to a specific stage, use the --stage
option:
serverless deploy --stage production
You can also configure the stage in your serverless.yml
:
provider:
stage: ${opt:stage, 'dev'}
This allows CLI override while defaulting to 'dev' if not specified.
Implementing the Lambda Function
Now, let's implement our Lambda function in the handler.js
file:
'use strict'
module.exports.returnStatus = async event => {
console.log('Input:', JSON.stringify(event, null, 2))
return {
statusCode: 200,
body: JSON.stringify({
message: 'Return status check function executed successfully!'
})
}
}
This is a basic implementation that logs the input and returns a success message.
Configuring IAM Roles
To integrate with QnABot, we need to use a specific IAM role. Update your
serverless.yml
:
functions:
return-status:
handler: handler.returnStatus
role: arn:aws:iam::YOUR_ACCOUNT_ID:role/dev-qnabot-6-0-1-FulfillmentLambdaRole-trLi2DR59osV
Replace YOUR_ACCOUNT_ID
with your actual AWS account ID.
Deploying to Different AWS Regions
To deploy to a specific AWS region, add the region
field under the provider
section in your serverless.yml
:
provider:
name: aws
runtime: nodejs20.x
region: us-west-2
You can also override this using the --region
flag during deployment:
serverless deploy --region us-west-2
Integrating with QnABot
To integrate with QnABot, ensure your function name starts with "qna-". In our
case, the service name already starts with "qna-", so the deployed function name
will be qna-chatbot-dev-return-status
, which satisfies this requirement.
Implementing Custom Response Bots
To implement custom response bots for multi-turn conversations, we'll use Amazon Lex. Here's how to set it up:
-
Create a new Amazon Lex bot named "QNAReturnStatus" with intents for capturing Return Status number and DOB.
-
Update your
serverless.yml
to include permissions for Lex:
provider:
name: aws
runtime: nodejs20.x
region: us-west-2
iamRoleStatements:
- Effect: Allow
Action:
- lex:PostText
Resource: 'arn:aws:lex:${self:provider.region}:${aws:accountId}:bot:QNAReturnStatus:*'
functions:
return-status:
handler: handler.returnStatus
role: arn:aws:iam::YOUR_ACCOUNT_ID:role/dev-qnabot-6-0-1-FulfillmentLambdaRole-trLi2DR59osV
- Modify your
handler.js
to handle the multi-turn conversation:
const AWS = require('aws-sdk')
const lex = new AWS.LexRuntime()
exports.returnStatus = async (event, context) => {
const sessionAttributes = event.sessionAttributes || {}
const returnNumber = sessionAttributes.return_info
? sessionAttributes.return_info.ReturnNumber
: null
const dob = sessionAttributes.return_info
? sessionAttributes.return_info.DOB
: null
if (!returnNumber) {
return elicitSlot(
event,
'What is your Return number?',
'QNAReturnStatus',
'ReturnNumber'
)
}
if (!dob) {
return elicitSlot(
event,
'What is your date of birth? (MM/DD/YYYY)',
'QNAReturnStatus',
'DOB'
)
}
// Here you would typically make an API call to check the Return status
const status = await checkReturnStatus(returnNumber, dob)
return {
statusCode: 200,
body: JSON.stringify({ message: `Your Return status is ${status}` })
}
}
function elicitSlot(event, message, botName, slotToElicit) {
return lex
.postText({
botName: botName,
botAlias: '$LATEST',
userId: event.userId || 'user1',
inputText: event.inputText || '',
sessionAttributes: event.sessionAttributes || {},
requestAttributes: {
'x-amz-lex:qnabot-response': JSON.stringify({
elicitResponse: {
responsebot: botName,
namespaceattribute: 'return_info',
slottoelicit: slotToElicit
}
})
}
})
.promise()
.then(lexResponse => {
return {
statusCode: 200,
body: JSON.stringify({ message: lexResponse.message }),
sessionAttributes: lexResponse.sessionAttributes
}
})
}
async function checkReturnStatus(returnNumber, dob) {
// Implement your Return status check logic here
return 'VALID'
}
- In the QnABot Content Designer:
- Create a new item for the Return status question
- Set the Lambda hook to your function
- Set up Elicit Response to use your custom Lex bot
Testing and Troubleshooting
To test your function locally:
serverless invoke local -f return-status
To pass custom event data:
serverless invoke local -f return-status --path event.json
Where event.json
contains your test event data.
Common issues and solutions:
- Deployment fails: Ensure your AWS credentials are correctly configured and you have the necessary permissions.
- Function not recognized by QnABot: Verify that your function name starts with "qna-".
- Lex integration not working: Check the IAM role permissions and ensure the Lex bot name is correct.
Best Practices and Tips
- Use environment variables for configuration values.
- Implement proper error handling and input validation.
- Use AWS CloudWatch for logging and monitoring.
- Regularly update your dependencies and runtime versions.
- Use AWS X-Ray for tracing and performance optimization.
- Implement CI/CD for automated testing and deployment.
Conclusion
Building a serverless QnABot with custom response bots on AWS involves several components working together seamlessly. By following this guide, you should be able to set up a basic implementation and extend it to suit your specific needs. Remember to always follow AWS best practices for security and performance optimization.
Happy coding!