본문으로 건너뛰기

WhatsApp 채팅봇

이 가이드는 Mastra Agent 및 Workflow를 사용하여 WhatsApp 채팅 봇을 만드는 방법을 보여줍니다. 봇은 웹후크를 통해 들어오는 WhatsApp 메시지를 수신하고, AI Agent를 통해 처리하고, 응답을 자연스러운 텍스트 메시지로 나누고, WhatsApp Business API를 통해 다시 보냅니다.

전제조건
전제조건에 대한 직접 링크

이 예제에는 WhatsApp Business API 설정이 필요하며 anthropic Model을 사용합니다. 다음 환경 변수를 .env 파일에 추가하세요.

.env
ANTHROPIC_API_KEY=<your-anthropic-api-key>
WHATSAPP_VERIFY_TOKEN=<your-verify-token>
WHATSAPP_ACCESS_TOKEN=<your-whatsapp-access-token>
WHATSAPP_BUSINESS_PHONE_NUMBER_ID=<your-phone-number-id>
WHATSAPP_API_VERSION=v22.0

WhatsApp 클라이언트 만들기
WhatsApp 클라이언트 만들기에 대한 직접 링크

이 클라이언트는 WhatsApp Business API를 통해 사용자에게 메시지 보내기를 처리합니다.

src/whatsapp-client.ts
// Simple WhatsApp Business API client for sending messages

interface SendMessageParams {
to: string
message: string
}

export async function sendWhatsAppMessage({ to, message }: SendMessageParams) {
// Get environment variables for WhatsApp API
const apiVersion = process.env.WHATSAPP_API_VERSION || 'v22.0'
const phoneNumberId = process.env.WHATSAPP_BUSINESS_PHONE_NUMBER_ID
const accessToken = process.env.WHATSAPP_ACCESS_TOKEN

// Check if required environment variables are set
if (!phoneNumberId || !accessToken) {
return false
}

// WhatsApp Business API endpoint
const url = `https://graph.facebook.com/${apiVersion}/${phoneNumberId}/messages`

// Message payload following WhatsApp API format
const payload = {
messaging_product: 'whatsapp',
recipient_type: 'individual',
to: to,
type: 'text',
text: {
body: message,
},
}

try {
// Send message via WhatsApp Business API
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify(payload),
})

const result = await response.json()

if (response.ok) {
console.log(`✅ WhatsApp message sent to ${to}: "${message}"`)
return true
} else {
console.error('❌ Failed to send WhatsApp message:', result)
return false
}
} catch (error) {
console.error('❌ Error sending WhatsApp message:', error)
return false
}
}

채팅 Agent 만들기
채팅 Agent 만들기에 대한 직접 링크

친근하고 대화를 잘하는 성격으로 주요 대화 로직을 처리하는 Agent입니다.

src/mastra/agents/chat-agent.ts
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
import { LibSQLStore } from '@mastra/libsql'

export const chatAgent = new Agent({
id: 'chat-agent',
name: 'Chat Agent',
instructions: `
You are a helpful, friendly, and knowledgeable AI assistant that loves to chat with users via WhatsApp.

Your personality:
- Warm, approachable, and conversational
- Enthusiastic about helping with any topic
- Use a casual, friendly tone like you're chatting with a friend
- Be concise but informative
- Show genuine interest in the user's questions

Your capabilities:
- Answer questions on a wide variety of topics
- Provide helpful advice and suggestions
- Engage in casual conversation
- Help with problem-solving and creative tasks
- Explain complex topics in simple terms

Guidelines:
- Keep responses informative but not overwhelming
- Ask follow-up questions when appropriate
- Be encouraging and positive
- If you don't know something, admit it honestly
- Adapt your communication style to match the user's tone
- Remember this is WhatsApp, so keep it conversational and natural

Always aim to be helpful while maintaining a friendly, approachable conversation style.
`,
model: 'openai/gpt-5.6-sol',
memory: new Memory({
storage: new LibSQLStore({
id: 'agent-storage',
url: 'file:../mastra.db',
}),
}),
})

문자 메시지 Agent 만들기
문자 메시지 Agent 만들기에 대한 직접 링크

이 Agent는 긴 응답을 WhatsApp에 적합한 자연스럽고 작은 크기의 문자 메시지로 변환합니다.

src/mastra/agents/text-message-agent.ts
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
import { LibSQLStore } from '@mastra/libsql'

export const textMessageAgent = new Agent({
id: 'text-message-agent',
name: 'Text Message Agent',
instructions: `
You are a text message converter that takes formal or lengthy text and breaks it down into natural, casual text messages.

Your job is to:
- Convert any input text into 5-8 short, casual text messages
- Each message should be 1-2 sentences maximum
- Use natural, friendly texting language (contractions, casual tone)
- Maintain all the important information from the original text
- Make it feel like you're texting a friend
- Use appropriate emojis sparingly to add personality
- Keep the conversational flow logical and easy to follow

Think of it like you're explaining something exciting to a friend via text - break it into bite-sized, engaging messages that don't overwhelm them with a long paragraph.

Always return exactly 5-8 messages in the messages array.
`,
model: 'openai/gpt-5.6-sol',
memory: new Memory({
storage: new LibSQLStore({
id: 'agent-storage',
url: 'file:../mastra.db',
}),
}),
})

채팅 Workflow 만들기
채팅 Workflow 만들기에 대한 직접 링크

이 Workflow는 응답 생성, 메시지 분할, WhatsApp을 통한 전송 등 전체 채팅 프로세스를 조율합니다.

src/mastra/workflows/chat-workflow.ts
import { createStep, createWorkflow } from '@mastra/core/workflows'
import { z } from 'zod'
import { sendWhatsAppMessage } from '../../whatsapp-client'

const respondToMessage = createStep({
id: 'respond-to-message',
description: 'Generate response to user message',
inputSchema: z.object({ userMessage: z.string() }),
outputSchema: z.object({ response: z.string() }),
execute: async ({ inputData, mastra }) => {
const agent = mastra?.getAgent('chatAgent')
if (!agent) {
throw new Error('Chat agent not found')
}

const response = await agent.generate([{ role: 'user', content: inputData.userMessage }])

return { response: response.text }
},
})

const breakIntoMessages = createStep({
id: 'break-into-messages',
description: 'Breaks response into text messages',
inputSchema: z.object({ prompt: z.string() }),
outputSchema: z.object({ messages: z.array(z.string()) }),
execute: async ({ inputData, mastra }) => {
const agent = mastra?.getAgent('textMessageAgent')
if (!agent) {
throw new Error('Text Message agent not found')
}

const response = await agent.generate([{ role: 'user', content: inputData.prompt }], {
structuredOutput: {
schema: z.object({
messages: z.array(z.string()),
}),
},
})

if (!response.object) throw new Error('Error generating messages')

return response.object
},
})

const sendMessages = createStep({
id: 'send-messages',
description: 'Sends text messages via WhatsApp',
inputSchema: z.object({
messages: z.array(z.string()),
userPhone: z.string(),
}),
outputSchema: z.object({ sentCount: z.number() }),
execute: async ({ inputData }) => {
const { messages, userPhone } = inputData

console.log(`\n🔥 Sending ${messages.length} WhatsApp messages to ${userPhone}...`)

let sentCount = 0

// Send each message with a small delay for natural flow
for (let i = 0; i < messages.length; i++) {
const success = await sendWhatsAppMessage({
to: userPhone,
message: messages[i],
})

if (success) {
sentCount++
}

// Add delay between messages for natural texting rhythm
if (i < messages.length - 1) {
await new Promise(resolve => setTimeout(resolve, 1000))
}
}

console.log(`\n✅ Successfully sent ${sentCount}/${messages.length} WhatsApp messages\n`)

return { sentCount }
},
})

export const chatWorkflow = createWorkflow({
id: 'chat-workflow',
inputSchema: z.object({ userMessage: z.string() }),
outputSchema: z.object({ sentCount: z.number() }),
})
.then(respondToMessage)
.map(async ({ inputData }) => ({
prompt: `Break this AI response into 3-8 casual, friendly text messages that feel natural for WhatsApp conversation:\n\n${inputData.response}`,
}))
.then(breakIntoMessages)
.map(async ({ inputData, getInitData }) => {
// Parse the original stringified input to get user phone
const initData = getInitData<typeof chatWorkflow>()
const webhookData = JSON.parse(initData.userMessage)
const userPhone = webhookData.entry?.[0]?.changes?.[0]?.value?.messages?.[0]?.from || 'unknown'

return {
messages: inputData.messages,
userPhone,
}
})
.then(sendMessages)

chatWorkflow.commit()

마스트라 구성 설정
마스트라 구성 설정에 대한 직접 링크

Agent, Workflow 및 WhatsApp Webhook 엔드포인트를 사용하여 Mastra 인스턴스를 구성합니다.

src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { registerApiRoute } from '@mastra/core/server'
import { PinoLogger } from '@mastra/loggers'
import { LibSQLStore } from '@mastra/libsql'

import { chatWorkflow } from './workflows/chat-workflow'
import { textMessageAgent } from './agents/text-message-agent'
import { chatAgent } from './agents/chat-agent'

export const mastra = new Mastra({
workflows: { chatWorkflow },
agents: { textMessageAgent, chatAgent },
storage: new LibSQLStore({
id: 'agent-storage',
url: ':memory:',
}),
logger: new PinoLogger({
name: 'Mastra',
level: 'info',
}),
server: {
apiRoutes: [
registerApiRoute('/whatsapp', {
method: 'GET',
handler: async c => {
const verifyToken = process.env.WHATSAPP_VERIFY_TOKEN
const {
'hub.mode': mode,
'hub.challenge': challenge,
'hub.verify_token': token,
} = c.req.query()

if (mode === 'subscribe' && token === verifyToken) {
return c.text(challenge, 200)
} else {
return c.status(403)
}
},
}),
registerApiRoute('/whatsapp', {
method: 'POST',
handler: async c => {
const mastra = c.get('mastra')
const chatWorkflow = mastra.getWorkflow('chatWorkflow')

const body = await c.req.json()

const workflowRun = await chatWorkflow.createRun()
const runResult = await workflowRun.start({
inputData: { userMessage: JSON.stringify(body) },
})

return c.json(runResult)
},
}),
],
},
})

채팅 봇 테스트
채팅 봇 테스트에 대한 직접 링크

WhatsApp 웹훅 페이로드를 시뮬레이션하여 채팅 봇을 로컬에서 테스트할 수 있습니다.

src/test-whatsapp-bot.ts
import 'dotenv/config'

import { mastra } from './mastra'

// Simulate a WhatsApp webhook payload
const mockWebhookData = {
entry: [
{
changes: [
{
value: {
messages: [
{
from: '1234567890', // Test phone number
text: {
body: 'Hello! How are you today?',
},
},
],
},
},
],
},
],
}

const workflow = mastra.getWorkflow('chatWorkflow')
const workflowRun = await workflow.createRun()

const result = await workflowRun.start({
inputData: { userMessage: JSON.stringify(mockWebhookData) },
})

console.log('Workflow completed:', result)

예제 출력
예제 출력에 대한 직접 링크

사용자가 "안녕하세요! 오늘 잘 지내세요?"라고 보내는 경우 WhatsApp 봇에 다음과 같은 여러 메시지로 응답할 수 있습니다.

Hey there! 👋 I'm doing great, thanks for asking!

How's your day going so far?

I'm here and ready to chat about whatever's on your mind

Whether you need help with something or just want to talk, I'm all ears! 😊

What's new with you?

봇은 Memory를 통해 대화 컨텍스트를 유지하고 WhatsApp 메시징에 자연스러운 응답을 제공합니다.