Building Your First AI Chatbot with Guardrails
A step-by-step tutorial for developers who want AI assistance WITHOUT the autonomous chaos. Build a customer support bot in 4 hours with full understanding of every line.
What We're Building
A customer support chatbot that can:
- Handle FAQ responses
- Create support tickets
- Check order status
- Escalate to humans when needed
Tech Stack: Node.js + Express + AYW Platform
Prerequisites
- Basic JavaScript knowledge
- Node.js installed
- AYW beta account (sign up at ayw.platform/signup)
Step 1: Project Setup (15 mins)
Instead of letting AI "just build it," let's start with decisions:
// AYW Generated + Human Approved
// File: package.json
// Why this stack: Express for REST API, AYW SDK for AI assistance
// Security: helmet for headers, cors with whitelist
// Approved by: [your-name] at 2026-04-29
{
"name": "ayw-support-bot",
"version": "1.0.0",
"dependencies": {
"express": "^4.18.2",
"helmet": "^7.0.0",
"cors": "^2.8.5",
"express-validator": "^7.0.1",
"@ayw/sdk": "^1.0.0"
}
}
Why these choices? AYW explains:
- Express: Your team knows it (low learning curve)
- Helmet: Security headers (OWASP recommended)
- CORS: Controlled cross-origin (whitelist only)
- express-validator: Input sanitization (prevents injection)
Step 2: Basic Bot Logic (1 hour)
// AYW Generated + Human Approved
// File: src/bot.js
// Purpose: Handle incoming chat messages with intent recognition
// Security: Input validated, rate-limited, audit-logged
// Approved by: [your-name] at 2026-04-29
const { body, validationResult } = require('express-validator');
// AYW Note: Intent mapping - what users want vs. what bot understands
const intents = {
'order_status': ['order', 'status', 'where', 'shipping'],
'return_item': ['return', 'refund', 'exchange'],
'faq': ['hours', 'location', 'contact', 'help'],
'escalate': ['human', 'agent', 'real person', 'speak to someone']
};
async function handleMessage(req, res) {
// AYW Security: Validate input first
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ error: 'Invalid input' });
}
const { message, userId } = req.body;
// AYW Generated: Intent recognition (explained)
const intent = detectIntent(message, intents);
// Audit log (required for compliance)
await auditLog('message_received', { userId, intent, timestamp: new Date() });
switch(intent) {
case 'order_status':
return handleOrderStatus(userId, res);
case 'return_item':
return handleReturn(userId, res);
case 'faq':
return handleFAQ(message, res);
case 'escalate':
return escalateToHuman(userId, res);
default:
return res.json({
message: "I'm not sure I understand. Can you rephrase?",
escalate: true
});
}
}
// AYW Note: Simple keyword matching (v1), can upgrade to ML later
function detectIntent(message, intents) {
const lowerMsg = message.toLowerCase();
for (const [intent, keywords] of Object.entries(intents)) {
if (keywords.some(kw => lowerMsg.includes(kw))) {
return intent;
}
}
return 'unknown';
}
What's different here:
- Every function has a purpose comment
- Security validation happens FIRST
- Audit logging is baked in
- Intent logic is simple and understandable
- You can explain this to a junior dev
Step 3: Add API Endpoints (1 hour)
// AYW Generated + Human Approved
// File: src/routes.js
// Purpose: Expose chat endpoint with security middleware
// Rate limiting: 10 messages per IP per hour
// Authentication: JWT required (explained below)
const rateLimit = require('express-rate-limit');
const chatLimiter = rateLimit({
windowMs: 3600000, // 1 hour
max: 10,
message: 'Too many messages, please try again later.'
});
app.post('/api/chat',
chatLimiter,
[
body('message').isLength({ min: 5, max: 1000 }).trim().escape(),
body('userId').isUUID()
],
handleMessage
);
// AYW Note: Why JWT auth? So we can track user conversations
// Alternative considered: Session-based (rejected - API-first design)
app.post('/api/chat', authenticateJWT, handleMessage);
Step 4: Test Your Bot (1 hour)
// AYW Generated Test
// File: test/bot.test.js
// Purpose: Verify bot handles edge cases
describe('Chatbot Tests', () => {
test('Handles angry user gracefully', async () => {
const response = await request(app)
.post('/api/chat')
.send({ message: "This is ridiculous! I've been waiting 3 hours!" });
expect(response.body.message).toContain('understand');
expect(response.status).toBe(200);
});
test('Escalates when requested', async () => {
const response = await request(app)
.post('/api/chat')
.send({ message: "I want to speak to a human" });
expect(response.body.escalate).toBe(true);
});
test('Validates input (security)', async () => {
const response = await request(app)
.post('/api/chat')
.send({ message: "<script>alert('xss')</script>" });
expect(response.status).toBe(400);
});
});
Step 5: Deploy with Confidence (30 mins)
# AYW Generated + Human Approved
# Dockerfile
# Base: Node 18 Alpine (security + small image)
# Why Alpine: 80% fewer CVEs than standard Node image
FROM node:18-alpine
# AYW Security: Non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
USER appuser
EXPOSE 3000
CMD ["node", "src/index.js"]
The Result: A Bot You Understand
| Aspect | Autonomous AI | AYW Human-in-the-Loop |
|---|---|---|
| Time to build | 30 mins | 4 hours |
| Code understanding | 10% | 100% |
| Can modify later | No | Yes |
| Security vulnerabilities | High | Low |
Try It Yourself
- Sign up for AYW beta: ayw.platform/signup
- Follow this tutorial - you'll understand every line
- Deploy with confidence - no black boxes
Your Turn
What's been your experience building chatbots? Have you used AI coding tools? Did you understand the generated code? Drop a comment - let's discuss!
This is Article 2 in AYW's Developer Relations series. Next: "The Security Risks of Autonomous AI Coding"
Tags: #ai #chatbot #nodejs #tutorial #humantheloop #ayw
Series: AYW Developer Tutorials (Part 2 of 6)
Top comments (0)